From patchwork Mon Oct 24 12:12:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 78939 Delivered-To: patch@linaro.org Received: by 10.140.97.247 with SMTP id m110csp2544467qge; Mon, 24 Oct 2016 05:14:51 -0700 (PDT) X-Received: by 10.36.44.18 with SMTP id i18mr1784348iti.67.1477311291818; Mon, 24 Oct 2016 05:14:51 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i10si3664397pai.144.2016.10.24.05.14.51; Mon, 24 Oct 2016 05:14:51 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-samsung-soc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-samsung-soc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-samsung-soc-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S936362AbcJXMMq (ORCPT + 4 others); Mon, 24 Oct 2016 08:12:46 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:43089 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S936464AbcJXMMh (ORCPT ); Mon, 24 Oct 2016 08:12:37 -0400 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout2.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0OFJ002OLWKSNB50@mailout2.w1.samsung.com>; Mon, 24 Oct 2016 13:12:29 +0100 (BST) Received: from eusmges5.samsung.com (unknown [203.254.199.245]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20161024121228eucas1p26adde780571b16ec170cbe61d2df4a69~AdqmT7aMI2843028430eucas1p2X; Mon, 24 Oct 2016 12:12:28 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges5.samsung.com (EUCPMTA) with SMTP id 36.2D.19540.CAAFD085; Mon, 24 Oct 2016 13:12:28 +0100 (BST) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20161024121227eucas1p1637d1a18e86e38daefce1d9867c12b63~AdqloBV_f0671506715eucas1p1w; Mon, 24 Oct 2016 12:12:27 +0000 (GMT) X-AuditID: cbfec7f5-f79ce6d000004c54-64-580dfaaca5a2 Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 8A.4B.10494.98AFD085; Mon, 24 Oct 2016 13:11:53 +0100 (BST) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OFJ00C6YWKJ1FB0@eusync1.samsung.com>; Mon, 24 Oct 2016 13:12:27 +0100 (BST) From: Marek Szyprowski To: linux-clk@vger.kernel.org, linux-pm@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: Marek Szyprowski , Stephen Boyd , Michael Turquette , Ulf Hansson , Sylwester Nawrocki , Chanwoo Choi , Inki Dae , Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz Subject: [PATCH v3 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks Date: Mon, 24 Oct 2016 14:12:08 +0200 Message-id: <1477311130-6534-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1477311130-6534-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAAzWSb0hTURjGPffPdl3euE3Rg6kfBgYVmkLBpTIMrG6UaQipGcw1r1PanOw6 ywgSwz/NtE0jZ4ZZqLFNmU7RUtHS5SzTuQzzgznTIJC0ckkuMHLe+vZ7eZ73eTiHl0DFq1go kZtXwGryZEqJQIT1jHqdUW2/ybSYyt4AutNoxekPP7/gdI1bj9FOZ4eQti3N4PSPO/M47amy A9roHETodvtHIe16c4Ie+VqO0xtvKzHa0Z4aTzLfZkuFzHR1FcLYzLcFzNzMgIDpar7JVHeb AeOxRSQLL4qOZrHK3EJWc+BYpijHPfgdz7fkX6tuvIUWg3GpDvgTkDoIP41PYjwHw6l5q0AH RISYagFwo2IC4wcPgEbTAvi/8bRxAuWFVgDtpincJ4ipYgQudmX4WEDFQt2KbjsqiCoB0NBh xX0DSpWg8P6gAfG5AqkUuNn/CPUxRkVC04OHW0wQJHUKtnTG8W0R8PVo7XaBP8VAk6kZ8eVA yiyEjw19iM8PqXBoe4Hy/gRY5lkX8BwIlx3dQp7D4HRt5b933gWwpHQ/z0YAJ1dIno/AEYdr uwuldsKanjqUjydhRZmYtzBwrtOL8HwcttY/x/mPaABwqGIO04OwJuBnBkGsllMpWO5QNCdT cdo8RbRcrbKBrSsY/+NYfwZaRg8PA4oAkgBy7F1AmhiXFXJFqmEACVQSRPZ6yTQxmSUrus5q 1FKNVslyw2A3gUlCyIGm96liSiErYK+wbD6r+a8ihH9oMRj7FbgU1rCjT0h61+Su1QT2atJQ VRvIVGd8Lnep0+cTd21aI0XBy+6xV5lrcbPixRi/FHmfxS69JJBesCQlxcuz1U/6W9Uhlui9 6S+xtpN6t7S7h9ADQ7jWr8GoMOsWG3vPRjWfPpOtOn+Ou3wvWYlI98TfyBmarl+oS1yWYFyO LHYfquFkfwFgoc8RAQMAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupnkeLIzCtJLcpLzFFi42I5/e/4Zd3OX7wRBksuCVtsnLGe1eL6l+es FpPuT2CxOH9+A7vFpsfXWC0+9txjtfjce4TRYsb5fUwWa4/cZbe4eMrV4vCbdlaLH2e6WSyO rw134PV4f6OV3eNyXy+Tx6ZVnWwed67tYfPYvKTeo2/LKkaPz5vkAtij3GwyUhNTUosUUvOS 81My89JtlUJD3HQtlBTyEnNTbZUidH1DgpQUyhJzSoE8IwM04OAc4B6spG+X4JZxf98H1oLV BRV985qZGxhPx3cxcnJICJhILJ93lhnCFpO4cG89WxcjF4eQwBJGif+XO5kgnCYmiRlbDrCC VLEJGEp0ve0CqxIRaGKUeNI3jR3EYRZoY5b43/GVEaRKWCBY4u/u+WBzWQRUJVbOmgNkc3Dw CrhLLN1oC7FOTuLksclgQzkFPCRWrlzCBGILAZXc6XjNMoGRdwEjwypGkdTS4tz03GIjveLE 3OLSvHS95PzcTYzAyNh27OeWHYxd74IPMQpwMCrx8Cpc5YkQYk0sK67MPcQowcGsJMK7/Sdv hBBvSmJlVWpRfnxRaU5q8SFGU6CbJjJLiSbnA6M2ryTe0MTQ3NLQyNjCwtzISEmcd+qHK+FC AumJJanZqakFqUUwfUwcnFINjNPsOTo36teImjX+nfj7qu8zv93qIcJhc1Vy1GefSHl3mvv6 nrDrOdGTzgp+coiYpKc0OdxUlvfA46Nqn5p28WqXft818wyzUO1b6XmX5qgvinvUklf5Wiu1 1vj1z0951X27dyswr7IK+3x3ua9t7r8TfyTjXLn9N9s9DK3p+fVaJW395XmB75VYijMSDbWY i4oTAbvcp+WiAgAA X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20161024121227eucas1p1637d1a18e86e38daefce1d9867c12b63 X-Msg-Generator: CA X-Sender-IP: 182.198.249.180 X-Local-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRs=?= =?UTF-8?B?7IK87ISx7KCE7J6QG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Global-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRtT?= =?UTF-8?B?YW1zdW5nIEVsZWN0cm9uaWNzG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDAyQ0QwMjczOTI=?= CMS-TYPE: 201P X-HopCount: 7 X-CMS-RootMailID: 20161024121227eucas1p1637d1a18e86e38daefce1d9867c12b63 X-RootMTR: 20161024121227eucas1p1637d1a18e86e38daefce1d9867c12b63 References: <1477311130-6534-1-git-send-email-m.szyprowski@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org Exynos4412 clock controller contains some additional clocks for FIMC-ISP (Camera ISP) subsystem. Registers for those clocks are partially located in the SOC area, which belongs to ISP power domain. This patch implements integration of ISP clocks with ISP power domain by using runtime pm feature of clocks core. This finally solves all the mysterious freezes in accessing ISP clocks when ISP power domain is disabled. Signed-off-by: Marek Szyprowski --- .../devicetree/bindings/clock/exynos4-clock.txt | 22 +++ drivers/clk/samsung/clk-exynos4.c | 211 +++++++++++++++------ 2 files changed, 172 insertions(+), 61 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt index f5a5b19ed3b2..429dd7e420e4 100644 --- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt @@ -41,3 +41,25 @@ Example 2: UART controller node that consumes the clock generated by the clock clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>; clock-names = "uart", "clk_uart_baud0"; }; + +Exynos4412 clock controller contains some additional clocks for FIMC-ISP +(Camera ISP) subsystem. Registers for those clocks are partially located +in the SOC area, which belongs to ISP power domain. To properly handle +additional ISP clocks and their integration with power domains, an +additional subnode "isp-clock-controller" with "samsung,exynos4412-isp-clock" +compatible has to be defined under the main Exynos4 clock node. This subnode +can be then used for linking with respective ISP power domain (for more +information, see Samsung Exynos power domains bindings). + +Example 3: An example of a clock controller for Exynos4412 with ISP clocks. + + clock: clock-controller@10030000 { + compatible = "samsung,exynos4412-clock"; + reg = <0x10030000 0x20000>; + #clock-cells = <1>; + + isp-clock-controller { + compatible = "samsung,exynos4412-isp-clock"; + power-domains = <&pd_isp>; + }; + }; diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index faab9b31baf5..e5165be348ef 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -16,7 +16,10 @@ #include #include #include +#include #include +#include +#include #include "clk.h" #include "clk-cpu.h" @@ -123,6 +126,8 @@ #define CLKOUT_CMU_CPU 0x14a00 #define PWR_CTRL1 0x15020 #define E4X12_PWR_CTRL2 0x15024 + +/* Exynos4x12 specific registers, which belong to ISP power domain */ #define E4X12_DIV_ISP0 0x18300 #define E4X12_DIV_ISP1 0x18304 #define E4X12_GATE_ISP0 0x18800 @@ -156,6 +161,8 @@ enum exynos4_plls { static void __iomem *reg_base; static enum exynos4_soc exynos4_soc; +static struct samsung_clk_provider *exynos4412_ctx; +static struct device_node *exynos4412_clk_node; /* * Support for CMU save/restore across system suspends @@ -164,6 +171,7 @@ enum exynos4_plls { static struct samsung_clk_reg_dump *exynos4_save_common; static struct samsung_clk_reg_dump *exynos4_save_soc; static struct samsung_clk_reg_dump *exynos4_save_pll; +static struct samsung_clk_reg_dump *exynos4x12_save_isp; /* * list of controller registers to be saved and restored during a @@ -192,6 +200,13 @@ enum exynos4_plls { E4X12_PWR_CTRL2, }; +static const unsigned long exynos4x12_clk_isp_save[] __initconst = { + E4X12_DIV_ISP0, + E4X12_DIV_ISP1, + E4X12_GATE_ISP0, + E4X12_GATE_ISP1, +}; + static const unsigned long exynos4_clk_pll_regs[] __initconst = { EPLL_LOCK, VPLL_LOCK, @@ -822,20 +837,21 @@ static void __init exynos4_clk_sleep_init(void) {} DIV(0, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4), DIV(0, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8), DIV(0, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4), - DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3, - CLK_GET_RATE_NOCACHE, 0), - DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3, - CLK_GET_RATE_NOCACHE, 0), - DIV(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3), - DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, - 4, 3, CLK_GET_RATE_NOCACHE, 0), - DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, - 8, 3, CLK_GET_RATE_NOCACHE, 0), DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4), DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3), DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3), }; +static struct samsung_div_clock exynos4x12_isp_div_clks[] = { + DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3, 0, 0), + DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3, 0, 0), + DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, + 4, 3, 0, 0), + DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, + 8, 3, 0, 0), + DIV_F(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3, 0, 0), +}; + /* list of gate clocks supported in all exynos4 soc's */ static const struct samsung_gate_clock exynos4_gate_clks[] __initconst = { /* @@ -1132,64 +1148,41 @@ static void __init exynos4_clk_sleep_init(void) {} 0, 0), GATE(CLK_I2S0, "i2s0", "aclk100", E4X12_GATE_IP_MAUDIO, 3, 0, 0), - GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, - CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0), GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, 0), }; +static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = { + GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, 0, 0), + GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, 0, 0), + GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2, 0, 0), + GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, 0, 0), + GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, 0, 0), + GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, 0, 0), + GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, 0, 0), + GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, 0, 0), + GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, 0, 0), + GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, 0, 0), + GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, 0, 0), + GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, 0, 0), + GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, 0, 0), + GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, 0, 0), + GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, 0, 0), + GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, 0, 0), + GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, 0, 0), + GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, 0, 0), + GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, 0, 0), + GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, 0, 0), + GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, 0, 0), + GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, 0, 0), + GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, 0, 0), + GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, 0, 0), + GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, 0, 0), + GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, 0, 0), +}; + static const struct samsung_clock_alias exynos4_aliases[] __initconst = { ALIAS(CLK_MOUT_CORE, NULL, "moutcore"), ALIAS(CLK_ARM_CLK, NULL, "armclk"), @@ -1438,6 +1431,100 @@ static void __init exynos4x12_core_down_clock(void) { 0 }, }; +static int exynos4x12_isp_clk_suspend(struct device *dev) +{ + samsung_clk_save(reg_base, exynos4x12_save_isp, + ARRAY_SIZE(exynos4x12_clk_isp_save)); + return 0; +} + +static int exynos4x12_isp_clk_resume(struct device *dev) +{ + samsung_clk_restore(reg_base, exynos4x12_save_isp, + ARRAY_SIZE(exynos4x12_clk_isp_save)); + return 0; +} + +static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev) +{ + struct samsung_clk_provider *ctx = exynos4412_ctx; + + if (!ctx) + return -ENODEV; + + exynos4x12_save_isp = samsung_clk_alloc_reg_dump(exynos4x12_clk_isp_save, + ARRAY_SIZE(exynos4x12_clk_isp_save)); + if (!exynos4x12_save_isp) + return -ENOMEM; + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ctx->dev = &pdev->dev; + + samsung_clk_register_div(ctx, exynos4x12_isp_div_clks, + ARRAY_SIZE(exynos4x12_isp_div_clks)); + samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks, + ARRAY_SIZE(exynos4x12_isp_gate_clks)); + + return 0; +} + +static const struct of_device_id exynos4x12_isp_clk_of_match[] = { + { .compatible = "samsung,exynos4412-isp-clock", }, + { }, +}; + +static const struct dev_pm_ops exynos4x12_isp_pm_ops = { + SET_RUNTIME_PM_OPS(exynos4x12_isp_clk_suspend, + exynos4x12_isp_clk_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver exynos4x12_isp_clk_driver __refdata = { + .driver = { + .name = "exynos-isp-clk", + .of_match_table = exynos4x12_isp_clk_of_match, + .suppress_bind_attrs = true, + .pm = &exynos4x12_isp_pm_ops, + }, + .probe = exynos4x12_isp_clk_probe, +}; + +static int __init exynos4x12_isp_clk_init(void) +{ + if (!exynos4412_clk_node) + return 0; + + of_platform_populate(exynos4412_clk_node, NULL, NULL, NULL); + return platform_driver_register(&exynos4x12_isp_clk_driver); +} +arch_initcall(exynos4x12_isp_clk_init); + +static void __init exynos4x12_isp_defer_clocks(struct samsung_clk_provider *ctx, + struct device_node *parent) +{ + struct device_node *np = of_get_next_available_child(parent, NULL); + if (!np) + return; + + if (of_device_is_compatible(np, + exynos4x12_isp_clk_of_match[0].compatible)) { + int i; + + for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_div_clks); i++) + samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER), + exynos4x12_isp_div_clks[i].id); + for (i = 0; i < ARRAY_SIZE(exynos4x12_isp_gate_clks); i++) + samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER), + exynos4x12_isp_gate_clks[i].id); + exynos4412_ctx = ctx; + exynos4412_clk_node = parent; + } + of_node_put(np); +} + /* register exynos4 clocks */ static void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc soc) @@ -1529,6 +1616,8 @@ static void __init exynos4_clk_init(struct device_node *np, samsung_clk_register_fixed_factor(ctx, exynos4x12_fixed_factor_clks, ARRAY_SIZE(exynos4x12_fixed_factor_clks)); + exynos4x12_isp_defer_clocks(ctx, np); + if (of_machine_is_compatible("samsung,exynos4412")) { exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", mout_core_p4x12[0], mout_core_p4x12[1], 0x14200,