From patchwork Mon Sep 19 10:55:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 76528 Delivered-To: patch@linaro.org Received: by 10.140.106.72 with SMTP id d66csp895272qgf; Mon, 19 Sep 2016 03:56:01 -0700 (PDT) X-Received: by 10.98.107.198 with SMTP id g189mr45828122pfc.14.1474282561200; Mon, 19 Sep 2016 03:56:01 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id ys7si26048246pac.59.2016.09.19.03.56.00; Mon, 19 Sep 2016 03:56:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-pm-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-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-pm-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755215AbcISKz7 (ORCPT + 14 others); Mon, 19 Sep 2016 06:55:59 -0400 Received: from mailout3.w1.samsung.com ([210.118.77.13]:56958 "EHLO mailout3.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754792AbcISKzz (ORCPT ); Mon, 19 Sep 2016 06:55:55 -0400 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout3.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0ODQ00CYWZP4YX90@mailout3.w1.samsung.com>; Mon, 19 Sep 2016 11:55:52 +0100 (BST) Received: from eusmges4.samsung.com (unknown [203.254.199.244]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20160919105551eucas1p1b2805e3dd23a5f3cfe38919625df0be9~1tCtmXPna0950809508eucas1p15; Mon, 19 Sep 2016 10:55:51 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges4.samsung.com (EUCPMTA) with SMTP id 0C.96.28332.734CFD75; Mon, 19 Sep 2016 11:55:51 +0100 (BST) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20160919105550eucas1p2d9bcb35f5464e14bd3c5925baf62e111~1tCtA449H2401324013eucas1p2v; Mon, 19 Sep 2016 10:55:50 +0000 (GMT) X-AuditID: cbfec7f4-f791c6d000006eac-37-57dfc437eabc Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id 52.E8.07726.D04CFD75; Mon, 19 Sep 2016 11:55:09 +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 <0ODQ00LJ5ZOPIK20@eusync1.samsung.com>; Mon, 19 Sep 2016 11:55:50 +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 v2 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks Date: Mon, 19 Sep 2016 12:55:23 +0200 Message-id: <1474282525-30441-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1474282525-30441-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrBIsWRmVeSWpSXmKPExsWy7djPc7rmR+6HGxxcLmCxccZ6VovrX56z Wky6P4HF4vULQ4tNj6+xWnzsucdq8bn3CKPFjPP7mCzWHrnLbnHxlKvF4TftrBY/znSzWBxf G+7A6/H+Riu7x+W+XiaPO9f2sHlsXlLv0bdlFaPH501yAWxRXDYpqTmZZalF+nYJXBn/599m KbhUUjHh9Hy2BsZpyV2MnBwSAiYSyw9/ZIKwxSQu3FvP1sXIxSEksJRR4u/k7VDOZ0aJnutX WGA6du9dxwiRWMYosfrofmYIp4FJYuHSVrBZbAKGEl1vu8DaRQSaGCUmbljPCuIwC3QxSzw8 9YERpEpYIFhi7lIIm0VAVeJnQz8ziM0r4CFxc8sjVoh9chInj00GszkFPCVmT/wLdcc8donu Fr0uRg4gW1Zi0wFmiLCLxMU3f9ggbGGJV8e3sEPYMhKdHQehHu1nlGhq1YawZzBKnHvLC2Fb Sxw+fhFsFbMAn8SkbdOZIcbzSnS0CUGYHhKPZtRAVDtKPF23kB3i9zmMEvde3GSfwCizgJFh FaNIamlxbnpqsYlecWJucWleul5yfu4mRmD8n/53/MsOxsXHrA4xCnAwKvHwMgTcDxdiTSwr rsw9xCjBwawkwvt0D1CINyWxsiq1KD++qDQntfgQozQHi5I4754FV8KFBNITS1KzU1MLUotg skwcnFINjOmPz7k3z5w790RJorcz46m0pS/+HL26RXCqmLwOi/MlYb+r4TMyhPq7z1cmzH/z eNdqIZmGnOfL7/k9eXjn7PNzJz6Lpa9TeaQ/Tcy/h+HKtzmmh71S37O8C1YV6zRIvGSu+MnM s9PqO8udH4UBS2QXry7yy7myr4uPY0HOtL+rf77tTfk83UWJpTgj0VCLuag4EQAcwiFJ+wIA AA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupikeLIzCtJLcpLzFFi42I5/e/4ZV3eI/fDDW6917HYOGM9q8X1L89Z LSbdn8Bi8fqFocWmx9dYLT723GO1+Nx7hNFixvl9TBZrj9xlt7h4ytXi8Jt2VosfZ7pZLI6v DXfg9Xh/o5Xd43JfL5PHnWt72Dw2L6n36NuyitHj8ya5ALYoN5uM1MSU1CKF1Lzk/JTMvHRb pdAQN10LJYW8xNxUW6UIXd+QICWFssScUiDPyAANODgHuAcr6dsluGX8n3+bpeBSScWE0/PZ GhinJXcxcnJICJhI7N67jhHCFpO4cG89WxcjF4eQwBJGiTdL37JAOE1MEmce32IHqWITMJTo etsFViUi0MQo8aRvGjuIwyzQxyzROm06WJWwQLDE3KUfwOayCKhK/GzoZwaxeQU8JG5uecQK sU9O4uSxyWA2p4CnxOyJf1lAbCGgmjdbN7NOYORdwMiwilEktbQ4Nz232FCvODG3uDQvXS85 P3cTIzAeth37uXkH46WNwYcYBTgYlXh4GQLuhwuxJpYVV+YeYpTgYFYS4X26ByjEm5JYWZVa lB9fVJqTWnyI0RToqInMUqLJ+cBYzSuJNzQxNLc0NDK2sDA3MlIS5y35cCVcSCA9sSQ1OzW1 ILUIpo+Jg1OqgVF8b+rNRmvBd3aqTx65uqduYGCaW9Mdsa37/LGXCX/ijAPFym2Wf9qjVFm5 R40tdtIxt+8FZnm3r92J932ZLswtWvwk9ZB+5Xr2gtjHMtV1Sw9nMPf5sq48kmETclna+9rB pFlaK/qiFq6Z4nNsweMmqVfWM3dKuveLOKT+z7i+/45aeVOomhJLcUaioRZzUXEiAIzQUm6d AgAA X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20160919105550eucas1p2d9bcb35f5464e14bd3c5925baf62e111 X-Msg-Generator: CA X-Sender-IP: 182.198.249.179 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: 20160919105550eucas1p2d9bcb35f5464e14bd3c5925baf62e111 X-RootMTR: 20160919105550eucas1p2d9bcb35f5464e14bd3c5925baf62e111 References: <1474282525-30441-1-git-send-email-m.szyprowski@samsung.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@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 | 227 +++++++++++++++------ 2 files changed, 188 insertions(+), 61 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-pm" 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..3d65e3f92f5a 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 @@ static enum exynos4_soc exynos4_soc; 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 @@ static const unsigned long exynos4x12_clk_save[] __initconst = { 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 const struct samsung_div_clock exynos4x12_div_clks[] __initconst = { 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 const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = { 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,116 @@ static const struct exynos_cpuclk_cfg_data e4412_armclk_d[] __initconst = { { 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; + + dev_set_name(&pdev->dev, pdev->dev.of_node->name); + + 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)); + ctx->dev = NULL; + + exynos4x12_save_isp = samsung_clk_alloc_reg_dump(exynos4x12_clk_isp_save, + ARRAY_SIZE(exynos4x12_clk_isp_save)); + if (!exynos4x12_save_isp) + dev_warn(&pdev->dev, "failed to allocate sleep save data, no sleep support!\n"); + else { + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + } + + 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) +{ + struct platform_device *parent_pdev; + struct device *parent; + int ret; + + if (!exynos4412_clk_node) + return 0; + + parent_pdev = of_find_device_by_node(exynos4412_clk_node); + if (!parent_pdev) + return -ENODEV; + + parent = &parent_pdev->dev; + ret = of_platform_populate(parent->of_node, NULL, NULL, parent); + if (ret) + return ret; + + return platform_driver_register(&exynos4x12_isp_clk_driver); +} +arch_initcall_sync(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 +1632,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,