From patchwork Thu Sep 1 13:45:49 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 75217 Delivered-To: patch@linaro.org Received: by 10.140.29.8 with SMTP id a8csp308934qga; Thu, 1 Sep 2016 06:48:20 -0700 (PDT) X-Received: by 10.66.126.131 with SMTP id my3mr19034860pab.115.1472737700922; Thu, 01 Sep 2016 06:48:20 -0700 (PDT) Return-Path: Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id 126si5799600pff.262.2016.09.01.06.48.20 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 01 Sep 2016 06:48:20 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) client-ip=2001:1868:205::9; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) smtp.mailfrom=linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bfSKh-0007tY-Fv; Thu, 01 Sep 2016 13:47:07 +0000 Received: from mailout1.w1.samsung.com ([210.118.77.11]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bfSKA-0007c0-Jn for linux-arm-kernel@lists.infradead.org; Thu, 01 Sep 2016 13:46:38 +0000 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout1.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0OCT004HCVKYY5C0@mailout1.w1.samsung.com> for linux-arm-kernel@lists.infradead.org; Thu, 01 Sep 2016 14:46:10 +0100 (BST) X-AuditID: cbfec7f4-f79cb6d000001359-71-57c831229be4 Received: from eusync2.samsung.com ( [203.254.199.212]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id 66.A8.04953.22138C75; Thu, 1 Sep 2016 14:46:10 +0100 (BST) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OCT00993VKRF730@eusync2.samsung.com>; Thu, 01 Sep 2016 14:46:10 +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 Subject: [PATCH 3/5] clocks: exynos4x12: add runtime pm support for ISP clocks Date: Thu, 01 Sep 2016 15:45:49 +0200 Message-id: <1472737551-15272-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1472737551-15272-1-git-send-email-m.szyprowski@samsung.com> References: <1472737551-15272-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrCLMWRmVeSWpSXmKPExsVy+t/xK7pKhifCDWa28VlsnLGe1eL6l+es FpPuT2CxeP3C0GLT42usFh977rFafO49wmgx4/w+Jou1R+6yW1w85Wpx+E07q8WPM90sFsfX hjvwery/0crucbmvl8njzrU9bB6bl9R79G1ZxejxeZNcAFsUl01Kak5mWWqRvl0CV8b6iy8Z C16XVKza08rawLgiuYuRk0NCwETixPlmJghbTOLCvfVsXYxcHEICSxklmo79YQFJCAk0MUl0 PEkBsdkEDCW63naBFYkINDFKPOmbxg7iMAv0MUu0TpvODlIlLOAn8WDWCjYQm0VAVWJP+09G EJtXwEOi5+1KRoh1chInj01mBbE5BTwlOtetZYfY5iGxYsdcxgmMvAsYGVYxiqaWJhcUJ6Xn GuoVJ+YWl+al6yXn525ihITllx2Mi49ZHWIU4GBU4uF1eHMsXIg1say4MvcQowQHs5IIb5L2 iXAh3pTEyqrUovz4otKc1OJDjNIcLErivHN3vQ8REkhPLEnNTk0tSC2CyTJxcEo1MK5eoNVs ff9m8I6pepMT9mwP+5NVZqmmExIdqV284fTb6C1TNz/1mhOrOcN11o4TccZmKattG2fJLLJa 8nj7pawjljHRBreed1Vryf1+fpnBM2Fyk663ZqU/H8tX52KnyWV3HwZukhGyfHbuv7fTHZkH Mgbm2Yz+f0LW1/6Wk5Va8fP5n5nn25RYijMSDbWYi4oTAS0DJIlHAgAA X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160901_064635_074178_D44B743A X-CRM114-Status: GOOD ( 18.84 ) X-Spam-Score: -8.3 (--------) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-8.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [210.118.77.11 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -1.4 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [210.118.77.11 listed in wl.mailspike.net] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ulf Hansson , Bartlomiej Zolnierkiewicz , Michael Turquette , Stephen Boyd , Krzysztof Kozlowski , Inki Dae , Chanwoo Choi , Sylwester Nawrocki , Marek Szyprowski MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.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 | 228 +++++++++++++++------ 2 files changed, 189 insertions(+), 61 deletions(-) -- 1.9.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel 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..50a98fb3e895 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,117 @@ 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 { + /* save initial values */ + exynos4x12_isp_clk_suspend(&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 = { + .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 +1633,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,