Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756087Ab2JCIZZ (ORCPT ); Wed, 3 Oct 2012 04:25:25 -0400 Received: from mailout1.samsung.com ([203.254.224.24]:34881 "EHLO mailout1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751466Ab2JCIZS (ORCPT ); Wed, 3 Oct 2012 04:25:18 -0400 X-AuditID: cbfee61b-b7f2b6d000000f14-32-506bf66ce4d1 From: Tomasz Figa To: chander.kashyap@linaro.org Cc: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, kgene.kim@samsung.com, mturquette@linaro.org, mturquette@ti.com, linux-kernel@vger.kernel.org, Thomas Abraham Subject: Re: [PATCH 2/2] ARM: Exynos4: Register clocks via common clock framework Date: Wed, 03 Oct 2012 10:25:04 +0200 Message-id: <3324947.79dxGcG09s@amdc1227> Organization: Samsung Poland R&D Center User-Agent: KMail/4.9.1 (Linux/3.5.3-gentoo; KDE/4.9.1; x86_64; ; ) In-reply-to: <1349093361-18820-3-git-send-email-thomas.abraham@linaro.org> References: <1349093361-18820-1-git-send-email-thomas.abraham@linaro.org> <1349093361-18820-3-git-send-email-thomas.abraham@linaro.org> MIME-version: 1.0 Content-transfer-encoding: 7Bit Content-type: text/plain; charset=us-ascii X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrDLMWRmVeSWpSXmKPExsVy+t9jQd2cb9kBBjfei1hc3jWHzWLG+X1M DkwenzfJBTBGcdmkpOZklqUW6dslcGXseH+aseDTHqaKr1flGxh3tTJ1MXJySAiYSPxZtYsd whaTuHBvPRuILSQwnVFi64eSLkYuILuFSeLziQfMIAk2ATWJzw2PwIpEBOQklu/dxQxSxCxw i1Fi7bn7rCAJYYFgiakvjjN2MXJwsAioSny55wgS5hXQlNj5oxNsDr+AusS7bU/BjhAVcJa4 0riIEcTmFPCSuHvoMyPE4k5GiQWn3rNBNAtK/Jh8jwXEZhaQl9i3fyorhK0lsX7ncaYJjIKz kJTNQlI2C0nZAkbmVYyiqQXJBcVJ6blGesWJucWleel6yfm5mxjBYfpMegfjqgaLQ4wCHIxK PLwavNkBQqyJZcWVuYcYJTiYlUR4XR4BhXhTEiurUovy44tKc1KLDzFKc7AoifM2e6QECAmk J5akZqemFqQWwWSZODilGhiFUm5Jz53pu/ep2vNZFxpOlGQv972xcteXdw1PZ9qabLtj7tB5 pcIoNG03V5j/14NxGQt5C//uYUvhc/Xk53dJC/2+6oXahoNM/ww3Nh4+/N5W9MYp3ti1TtKz bbezb73msajBPnbWMXmZ+5a1QdPkNFdKX7jtacuatbO/1GZ+8nvj2N8l3/uVWIozEg21mIuK EwFoAKSGTwIAAA== Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 39743 Lines: 1069 Hi Chander, Thomas, I think this patch could be split into several smaller, while retaining logical integrity of particular patches, e.g.: - the change introduced to __clk_init (with proper description and rationale why the generic code is being touched) - generic exynos4 code - exynos4210-specific code - exynos4x12-specific code - patch enabling common clock framework on exynos4. Also, see some nitpicks inline. On Monday 01 of October 2012 17:39:21 chander.kashyap@linaro.org wrote: > From: Thomas Abraham > > Register clocks for Exynos4 platfotms using common clock framework. > Also included are set of helper functions for clock registration > that can be reused on other Samsung platforms as well. > > Cc: Mike Turquette > Cc: Kukjin Kim > Signed-off-by: Thomas Abraham > --- > arch/arm/mach-exynos/Kconfig | 1 + > arch/arm/mach-exynos/common.h | 3 + > arch/arm/mach-exynos/mct.c | 11 +- > arch/arm/plat-samsung/Kconfig | 4 +- > drivers/clk/Makefile | 1 + > drivers/clk/clk.c | 12 +- > drivers/clk/samsung/Makefile | 6 + > drivers/clk/samsung/clk-exynos4.c | 585 > +++++++++++++++++++++++++++++++++++++ drivers/clk/samsung/clk.c > | 231 +++++++++++++++ > drivers/clk/samsung/clk.h | 190 ++++++++++++ > 10 files changed, 1037 insertions(+), 7 deletions(-) > create mode 100644 drivers/clk/samsung/Makefile > create mode 100644 drivers/clk/samsung/clk-exynos4.c > create mode 100644 drivers/clk/samsung/clk.c > create mode 100644 drivers/clk/samsung/clk.h > > diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig > index b5b4c8c..4866ec7 100644 > --- a/arch/arm/mach-exynos/Kconfig > +++ b/arch/arm/mach-exynos/Kconfig > @@ -15,6 +15,7 @@ config ARCH_EXYNOS4 > bool "SAMSUNG EXYNOS4" > default y > select HAVE_SMP > + select COMMON_CLK > select MIGHT_HAVE_CACHE_L2X0 > help > Samsung EXYNOS4 SoCs based systems > diff --git a/arch/arm/mach-exynos/common.h > b/arch/arm/mach-exynos/common.h index aed2eeb..2274431 100644 > --- a/arch/arm/mach-exynos/common.h > +++ b/arch/arm/mach-exynos/common.h > @@ -21,6 +21,9 @@ void exynos4_restart(char mode, const char *cmd); > void exynos5_restart(char mode, const char *cmd); > void exynos_init_late(void); > > +void exynos4210_clk_init(void); > +void exynos4212_clk_init(void); exynos4x12_clk_init? > + > #ifdef CONFIG_PM_GENERIC_DOMAINS > int exynos_pm_late_initcall(void); > #else > diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c > index b601fb8..a7cace0 100644 > --- a/arch/arm/mach-exynos/mct.c > +++ b/arch/arm/mach-exynos/mct.c > @@ -30,6 +30,8 @@ > #include > #include > > +#include "common.h" > + > #define TICK_BASE_CNT 1 > > enum { > @@ -457,7 +459,7 @@ static struct local_timer_ops exynos4_mct_tick_ops > __cpuinitdata = { static void __init exynos4_timer_resources(void) > { > struct clk *mct_clk; > - mct_clk = clk_get(NULL, "xtal"); > + mct_clk = clk_get(NULL, "fin_pll"); > > clk_rate = clk_get_rate(mct_clk); > > @@ -478,6 +480,13 @@ static void __init exynos4_timer_resources(void) > > static void __init exynos4_timer_init(void) > { > +#ifdef CONFIG_COMMON_CLK > + if (soc_is_exynos4210()) > + exynos4210_clk_init(); > + else if (soc_is_exynos4212() || soc_is_exynos4412()) > + exynos4212_clk_init(); exynos4x12_clk_init? > +#endif > + > if ((soc_is_exynos4210()) || (soc_is_exynos5250())) > mct_int_type = MCT_INT_SPI; > else > diff --git a/arch/arm/plat-samsung/Kconfig > b/arch/arm/plat-samsung/Kconfig index 9c3b90c..35b4cb8 100644 > --- a/arch/arm/plat-samsung/Kconfig > +++ b/arch/arm/plat-samsung/Kconfig > @@ -26,7 +26,7 @@ config PLAT_S5P > select S5P_GPIO_DRVSTR > select SAMSUNG_GPIOLIB_4BIT > select PLAT_SAMSUNG > - select SAMSUNG_CLKSRC > + select SAMSUNG_CLKSRC if !COMMON_CLK > select SAMSUNG_IRQ_VIC_TIMER > help > Base platform code for Samsung's S5P series SoC. > @@ -89,7 +89,7 @@ config SAMSUNG_CLKSRC > used by newer systems such as the S3C64XX. > > config S5P_CLOCK > - def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) > + def_bool ((ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) > && !COMMON_CLK) help > Support common clock part for ARCH_S5P and ARCH_EXYNOS SoCs > > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile > index 6327536..5f5b060 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile > @@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ > endif > obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o > obj-$(CONFIG_ARCH_U8500) += ux500/ > +obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ > > # Chip specific > obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c > index 56e4495..456c50b 100644 > --- a/drivers/clk/clk.c > +++ b/drivers/clk/clk.c > @@ -1196,6 +1196,7 @@ EXPORT_SYMBOL_GPL(clk_set_parent); > int __clk_init(struct device *dev, struct clk *clk) > { > int i, ret = 0; > + u8 index; > struct clk *orphan; > struct hlist_node *tmp, *tmp2; > > @@ -1259,6 +1260,7 @@ int __clk_init(struct device *dev, struct clk *clk) > __clk_lookup(clk->parent_names[i]); > } > > + Unnecessary extra blank line? > clk->parent = __clk_init_parent(clk); > > /* > @@ -1298,11 +1300,13 @@ int __clk_init(struct device *dev, struct clk > *clk) * this clock > */ > hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, > child_node) - for (i = 0; i < orphan->num_parents; i++) > - if (!strcmp(clk->name, orphan->parent_names[i])) { > + if (orphan->num_parents > 1) { > + index = orphan->ops->get_parent(orphan->hw); > + if (!strcmp(clk->name, orphan->parent_names[index])) > __clk_reparent(orphan, clk); > - break; > - } > + } else if (!strcmp(clk->name, orphan->parent_names[0])) { > + __clk_reparent(orphan, clk); > + } > > /* > * optional platform-specific magic > diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile > new file mode 100644 > index 0000000..69487f7 > --- /dev/null > +++ b/drivers/clk/samsung/Makefile > @@ -0,0 +1,6 @@ > +# > +# Samsung Clock specific Makefile > +# > + > +obj-$(CONFIG_PLAT_SAMSUNG) += clk.o > +obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o > diff --git a/drivers/clk/samsung/clk-exynos4.c > b/drivers/clk/samsung/clk-exynos4.c new file mode 100644 > index 0000000..74a6f03 > --- /dev/null > +++ b/drivers/clk/samsung/clk-exynos4.c > @@ -0,0 +1,585 @@ > +/* > + * Copyright (c) 2012 Samsung Electronics Co., Ltd. > + * Copyright (c) 2012 Linaro Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * Common Clock Framework support for all Exynos4 platforms > +*/ > + > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "clk.h" > + > +#define EXYNOS4_OP_MODE (S5P_VA_CHIPID + 8) > + > +static const char *pll_parent_names[] __initdata = { "fin_pll" }; > +static const char *fin_pll_parents[] __initdata = { "xxti", "xusbxti" }; > +static const char *mout_apll_parents[] __initdata = { "fin_pll", > "fout_apll", }; +static const char *mout_mpll_parents[] __initdata = { > "fin_pll", "fout_mpll", }; +static const char *mout_epll_parents[] > __initdata = { "fin_pll", "fout_epll", }; + > +static const char *sclk_ampll_parents[] __initdata = { > + "mout_mpll", "sclk_apll", }; > + > +static const char *sclk_evpll_parents[] __initdata = { > + "mout_epll", "mout_vpll", }; > + > +static const char *mout_core_parents[] __initdata = { > + "mout_apll", "mout_mpll", }; > + > +static const char *mout_mfc_parents[] __initdata = { > + "mout_mfc0", "mout_mfc1", }; > + > +static const char *mout_dac_parents[] __initdata = { > + "mout_vpll", "sclk_hdmiphy", }; > + > +static const char *mout_hdmi_parents[] __initdata = { > + "sclk_pixel", "sclk_hdmiphy", }; > + > +static const char *mout_mixer_parents[] __initdata = { > + "sclk_dac", "sclk_hdmi", }; > + > +static const char *group1_parents[] __initdata = { > + "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0", > + "none", "sclk_hdmiphy", "mout_mpll", "mout_epll", > + "mout_vpll" }; > + > +static struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] = { > + FRATE_CLK(NULL, "xxti", NULL, CLK_IS_ROOT, 24000000), > + FRATE_CLK(NULL, "xusbxti", NULL, CLK_IS_ROOT, 24000000), > + FRATE_CLK(NULL, "sclk_hdmi24m", NULL, CLK_IS_ROOT, 24000000), > + FRATE_CLK(NULL, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000), > + FRATE_CLK(NULL, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000), > +}; > + > +static struct samsung_mux_clock exynos4_mux_clks[] = { > + MUXCLK(NULL, "fin_pll", fin_pll_parents, 0, > + EXYNOS4_OP_MODE, 0, 1, 0), > + MUXCLK(NULL, "mout_apll", mout_apll_parents, 0, > + EXYNOS4_CLKSRC_CPU, 0, 1, 0), > + MUXCLK(NULL, "mout_epll", mout_epll_parents, 0, > + EXYNOS4_CLKSRC_TOP0, 4, 1, 0), > + MUXCLK(NULL, "mout_core", mout_core_parents, 0, > + EXYNOS4_CLKSRC_CPU, 16, 1, 0), > + MUXCLK(NULL, "mout_aclk_200", sclk_ampll_parents, 0, > + EXYNOS4_CLKSRC_TOP0, 12, 1, 0), > + MUXCLK(NULL, "mout_aclk_100", sclk_ampll_parents, 0, > + EXYNOS4_CLKSRC_TOP0, 16, 1, 0), > + MUXCLK(NULL, "mout_aclk_160", sclk_ampll_parents, 0, > + EXYNOS4_CLKSRC_TOP0, 20, 1, 0), > + MUXCLK(NULL, "mout_aclk_133", sclk_ampll_parents, 0, > + EXYNOS4_CLKSRC_TOP0, 24, 1, 0), > + MUXCLK("exynos4210-uart.0", "mout_uart0", group1_parents, 0, > + EXYNOS4_CLKSRC_PERIL0, 0, 4, 0), > + MUXCLK("exynos4210-uart.1", "mout_uart1", group1_parents, 0, > + EXYNOS4_CLKSRC_PERIL0, 4, 4, 0), > + MUXCLK("exynos4210-uart.2", "mout_uart2", group1_parents, 0, > + EXYNOS4_CLKSRC_PERIL0, 8, 4, 0), > + MUXCLK("exynos4210-uart.3", "mout_uart3", group1_parents, 0, > + EXYNOS4_CLKSRC_PERIL0, 12, 4, 0), > + MUXCLK("exynos4-sdhci.0", "mout_mmc0", group1_parents, 0, > + EXYNOS4_CLKSRC_FSYS, 0, 4, 0), > + MUXCLK("exynos4-sdhci.1", "mout_mmc1", group1_parents, 0, > + EXYNOS4_CLKSRC_FSYS, 4, 4, 0), > + MUXCLK("exynos4-sdhci.1", "mout_mmc2", group1_parents, 0, > + EXYNOS4_CLKSRC_FSYS, 8, 4, 0), > + MUXCLK("exynos4-sdhci.1", "mout_mmc3", group1_parents, 0, > + EXYNOS4_CLKSRC_FSYS, 12, 4, 0), > + MUXCLK("exynos4210-spi.0", "mout_spi0", group1_parents, 0, > + EXYNOS4_CLKSRC_PERIL1, 16, 4, 0), > + MUXCLK("exynos4210-spi.1", "mout_spi1", group1_parents, 0, > + EXYNOS4_CLKSRC_PERIL1, 20, 4, 0), > + MUXCLK("exynos4210-spi.2", "mout_spi2", group1_parents, 0, > + EXYNOS4_CLKSRC_PERIL1, 24, 4, 0), > + MUXCLK(NULL, "mout_sata", sclk_ampll_parents, 0, > + EXYNOS4_CLKSRC_FSYS, 24, 1, 0), > + MUXCLK(NULL, "mout_mfc0", sclk_ampll_parents, 0, > + EXYNOS4_CLKSRC_MFC, 0, 1, 0), > + MUXCLK(NULL, "mout_mfc1", sclk_evpll_parents, 0, > + EXYNOS4_CLKSRC_MFC, 4, 1, 0), > + MUXCLK("s5p-mfc", "mout_mfc", mout_mfc_parents, 0, > + EXYNOS4_CLKSRC_MFC, 8, 1, 0), > + MUXCLK("s5p-mipi-csis.0", "mout_csis0", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 24, 4, 0), > + MUXCLK("s5p-mipi-csis.1", "mout_csis1", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 28, 4, 0), > + MUXCLK(NULL, "mout_cam0", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 16, 4, 0), > + MUXCLK(NULL, "mout_cam1", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 20, 4, 0), > + MUXCLK("exynos4-fimc.0", "mout_fimc0", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 0, 4, 0), > + MUXCLK("exynos4-fimc.1", "mout_fimc1", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 4, 4, 0), > + MUXCLK("exynos4-fimc.2", "mout_fimc2", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 8, 4, 0), > + MUXCLK("exynos4-fimc.3", "mout_fimc3", group1_parents, 0, > + EXYNOS4_CLKSRC_CAM, 12, 4, 0), > + MUXCLK("exynos4-fb.0", "mout_fimd0", group1_parents, 0, > + EXYNOS4_CLKSRC_LCD0, 0, 4, 0), > + MUXCLK(NULL, "sclk_dac", mout_dac_parents, 0, > + EXYNOS4_CLKSRC_TV, 8, 1, 0), > + MUXCLK(NULL, "sclk_hdmi", mout_hdmi_parents, 0, > + EXYNOS4_CLKSRC_TV, 0, 1, 0), > + MUXCLK(NULL, "sclk_mixer", mout_mixer_parents, 0, > + EXYNOS4_CLKSRC_TV, 4, 1, 0), > +}; > + > +static struct samsung_div_clock exynos4_div_clks[] = { > + DIVCLK(NULL, "sclk_apll", "mout_apll", 0, > + EXYNOS4_CLKDIV_CPU, 24, 3, 0), > + DIVCLK(NULL, "div_core", "mout_core", 0, > + EXYNOS4_CLKDIV_CPU, 0, 3, 0), > + DIVCLK(NULL, "armclk", "div_core", 0, > + EXYNOS4_CLKDIV_CPU, 28, 3, 0), > + DIVCLK(NULL, "aclk_200", "mout_aclk_200", 0, > + EXYNOS4_CLKDIV_TOP, 0, 3, 0), > + DIVCLK(NULL, "aclk_100", "mout_aclk_100", 0, > + EXYNOS4_CLKDIV_TOP, 4, 4, 0), > + DIVCLK(NULL, "aclk_160", "mout_aclk_160", 0, > + EXYNOS4_CLKDIV_TOP, 8, 3, 0), > + DIVCLK(NULL, "aclk_133", "mout_aclk_133", 0, > + EXYNOS4_CLKDIV_TOP, 12, 3, 0), > + DIVCLK("exynos4210-uart.0", "div_uart0", "mout_uart0", 0, > + EXYNOS4_CLKDIV_PERIL0, 0, 4, 0), > + DIVCLK("exynos4210-uart.1", "div_uart1", "mout_uart1", 0, > + EXYNOS4_CLKDIV_PERIL0, 4, 4, 0), > + DIVCLK("exynos4210-uart.2", "div_uart2", "mout_uart2", 0, > + EXYNOS4_CLKDIV_PERIL0, 8, 4, 0), > + DIVCLK("exynos4210-uart.3", "div_uart3", "mout_uart3", 0, > + EXYNOS4_CLKDIV_PERIL0, 12, 4, 0), > + DIVCLK("exynos4-sdhci.0", "div_mmc0", "mout_mmc0", 0, > + EXYNOS4_CLKDIV_FSYS1, 0, 4, 0), > + DIVCLK("exynos4-sdhci.0", "div_mmc0_pre", "div_mmc0", 0, > + EXYNOS4_CLKDIV_FSYS1, 8, 8, 0), > + DIVCLK("exynos4-sdhci.1", "div_mmc1", "mout_mmc1", 0, > + EXYNOS4_CLKDIV_FSYS1, 16, 4, 0), > + DIVCLK("exynos4-sdhci.1", "div_mmc1_pre", "div_mmc1", 0, > + EXYNOS4_CLKDIV_FSYS1, 24, 8, 0), > + DIVCLK("exynos4-sdhci.2", "div_mmc2", "mout_mmc2", 0, > + EXYNOS4_CLKDIV_FSYS2, 0, 4, 0), > + DIVCLK("exynos4-sdhci.2", "div_mmc2_pre", "div_mmc2", 0, > + EXYNOS4_CLKDIV_FSYS2, 8, 8, 0), > + DIVCLK("exynos4-sdhci.3", "div_mmc3", "mout_mmc3", 0, > + EXYNOS4_CLKDIV_FSYS2, 16, 4, 0), > + DIVCLK("exynos4-sdhci.3", "div_mmc3_pre", "div_mmc3", 0, > + EXYNOS4_CLKDIV_FSYS2, 24, 8, 0), > + DIVCLK("exynos4210-spi.0", "div_spi0", "mout_spi0", 0, > + EXYNOS4_CLKDIV_PERIL1, 0, 4, 0), > + DIVCLK("exynos4210-spi.1", "div_spi1", "mout_spi1", 0, > + EXYNOS4_CLKDIV_PERIL1, 16, 4, 0), > + DIVCLK("exynos4210-spi.2", "div_spi2", "mout_spi2", 0, > + EXYNOS4_CLKDIV_PERIL2, 0, 4, 0), > + DIVCLK("exynos4210-spi.0", "div_spi0_pre", "div_spi0", 0, > + EXYNOS4_CLKDIV_PERIL1, 8, 8, 0), > + DIVCLK("exynos4210-spi.1", "div_spi1_pre", "div_spi1", 0, > + EXYNOS4_CLKDIV_PERIL1, 24, 8, 0), > + DIVCLK("exynos4210-spi.2", "div_spi2_pre", "div_spi2", 0, > + EXYNOS4_CLKDIV_PERIL2, 8, 8, 0), > + DIVCLK(NULL, "div_sata", "mout_sata", 0, > + EXYNOS4_CLKDIV_FSYS0, 20, 4, 0), > + DIVCLK("s5p-mfc", "div_mfc", "mout_mfc", 0, > + EXYNOS4_CLKDIV_MFC, 0, 4, 0), > + DIVCLK("s5p-mipi-csis.0", "div_csis0", "mout_csis0", 0, > + EXYNOS4_CLKDIV_CAM, 24, 4, 0), > + DIVCLK("s5p-mipi-csis.1", "div_csis1", "mout_csis1", 0, > + EXYNOS4_CLKDIV_CAM, 28, 4, 0), > + DIVCLK(NULL, "div_cam0", "mout_cam0", 0, > + EXYNOS4_CLKDIV_CAM, 16, 4, 0), > + DIVCLK(NULL, "div_cam1", "mout_cam1", 0, > + EXYNOS4_CLKDIV_CAM, 20, 4, 0), > + DIVCLK("exynos4-fimc.0", "div_fimc0", "mout_fimc0", 0, > + EXYNOS4_CLKDIV_CAM, 0, 4, 0), > + DIVCLK("exynos4-fimc.1", "div_fimc1", "mout_fimc1", 0, > + EXYNOS4_CLKDIV_CAM, 4, 4, 0), > + DIVCLK("exynos4-fimc.2", "div_fimc2", "mout_fimc2", 0, > + EXYNOS4_CLKDIV_CAM, 4, 4, 0), > + DIVCLK("exynos4-fimc.3", "div_fimc3", "mout_fimc3", 0, > + EXYNOS4_CLKDIV_CAM, 4, 4, 0), > + DIVCLK("exynos4-fb.0", "div_fimd0", "mout_fimd0", 0, > + EXYNOS4_CLKDIV_LCD0, 0, 4, 0), > + DIVCLK(NULL, "sclk_pixel", "mout_vpll", 0, > + EXYNOS4_CLKDIV_TV, 0, 4, 0), > +}; > + > +struct samsung_gate_clock exynos4_gate_clks[] = { > + GATECLK("exynos4210-uart.0", "uart0", "aclk_100", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKGATE_IP_PERIL, 0, "uart"), > + GATECLK("exynos4210-uart.1", "uart1", "aclk_100", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKGATE_IP_PERIL, 1, "uart"), > + GATECLK("exynos4210-uart.2", "uart2", "aclk_100", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKGATE_IP_PERIL, 2, "uart"), > + GATECLK("exynos4210-uart.3", "uart3", "aclk_100", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKGATE_IP_PERIL, 3, "uart"), > + GATECLK("exynos4210-uart.4", "uart4", "aclk_100", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKGATE_IP_PERIL, 4, "uart"), > + GATECLK("exynos4210-uart.5", "uart5", "aclk_100", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKGATE_IP_PERIL, 5, "uart"), > + GATECLK("exynos4210-uart.0", "uclk0", "div_uart0", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKSRC_MASK_PERIL0, 0, "clk_uart_baud0"), > + GATECLK("exynos4210-uart.1", "uclk1", "div_uart1", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKSRC_MASK_PERIL0, 4, "clk_uart_baud0"), > + GATECLK("exynos4210-uart.2", "uclk2", "div_uart2", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKSRC_MASK_PERIL0, 8, "clk_uart_baud0"), > + GATECLK("exynos4210-uart.3", "uclk3", "div_uart3", CLK_SET_RATE_PARENT, > + EXYNOS4_CLKSRC_MASK_PERIL0, 12, "clk_uart_baud0"), > + GATECLK(NULL, "timers", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 24, NULL), > + GATECLK("s5p-mipi-csis.0", "csis", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 5, NULL), > + GATECLK(NULL, "jpeg", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 6, NULL), > + GATECLK("exynos4-fimc.0", "fimc0", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 0, "fimc"), > + GATECLK("exynos4-fimc.1", "fimc1", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 1, "fimc"), > + GATECLK("exynos4-fimc.2", "fimc2", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 2, "fimc"), > + GATECLK("exynos4-fimc.3", "fimc3", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 3, "fimc"), > + GATECLK("exynos4-sdhci.0", "hsmmc0", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 5, "hsmmc"), > + GATECLK("exynos4-sdhci.1", "hsmmc1", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 6, "hsmmc"), > + GATECLK("exynos4-sdhci.2", "hsmmc2", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 7, "hsmmc"), > + GATECLK("exynos4-sdhci.3", "hsmmc3", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 8, "hsmmc"), > + GATECLK(NULL, "dwmmc", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 9, NULL), > + GATECLK("s5p-sdo", "dac", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_TV, 2, NULL), > + GATECLK("s5p-mixer", "mixer", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_TV, 1, NULL), > + GATECLK("s5p-mixer", "vp", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_TV, 0, NULL), > + GATECLK("exynos4-hdmi", "hdmi", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_TV, 3, NULL), > + GATECLK("exynos4-hdmi", "hdmiphy", "aclk_160", 0, > + S5P_HDMI_PHY_CONTROL, 0, NULL), > + GATECLK("s5p-sdo", "dacphy", "aclk_160", 0, > + S5P_DAC_PHY_CONTROL, 0, NULL), > + GATECLK(NULL, "adc", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 15, NULL), > + GATECLK(NULL, "keypad", "aclk_100", 0, > + EXYNOS4210_CLKGATE_IP_PERIR, 16, NULL), > + GATECLK(NULL, "rtc", "aclk_100", 0, > + EXYNOS4210_CLKGATE_IP_PERIR, 15, NULL), > + GATECLK(NULL, "watchdog", "aclk_100", 0, > + EXYNOS4210_CLKGATE_IP_PERIR, 14, NULL), > + GATECLK(NULL, "usbhost", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 12, NULL), > + GATECLK(NULL, "otg", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 13, NULL), > + GATECLK("exynos4210-spi.0", "spi0", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 16, "spi"), > + GATECLK("exynos4210-spi.1", "spi1", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 17, "spi"), > + GATECLK("exynos4210-spi.2", "spi2", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 18, "spi"), > + GATECLK("samsung-i2s.0", "iis0", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 19, "iis"), > + GATECLK("samsung-i2s.1", "iis1", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 20, "iis"), > + GATECLK("samsung-i2s.2", "iis2", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 21, "iis"), > + GATECLK("samsung-ac97", "ac97", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 27, NULL), > + GATECLK("s5p-mfc", "mfc", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_MFC, 0, NULL), > + GATECLK("s3c2440-i2c.0", "i2c0", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 6, "i2c"), > + GATECLK("s3c2440-i2c.1", "i2c1", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 7, "i2c"), > + GATECLK("s3c2440-i2c.2", "i2c2", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 8, "i2c"), > + GATECLK("s3c2440-i2c.3", "i2c3", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 9, "i2c"), > + GATECLK("s3c2440-i2c.4", "i2c4", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 10, "i2c"), > + GATECLK("s3c2440-i2c.5", "i2c5", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 11, "i2c"), > + GATECLK("s3c2440-i2c.6", "i2c6", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 12, "i2c"), > + GATECLK("s3c2440-i2c.7", "i2c7", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 13, "i2c"), > + GATECLK("s3c2440-hdmiphy-i2c", "i2c", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_PERIL, 14, NULL), > + GATECLK(SYSMMU_CLOCK_DEVNAME(mfc_l, 0), "sysmmu0", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_MFC, 1, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(mfc_r, 1), "sysmmu1", "aclk_100", 0, > + EXYNOS4_CLKGATE_IP_MFC, 2, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(tv, 2), "sysmmu2", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_TV, 4, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(jpeg, 3), "sysmmu3", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 11, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(rot, 4), "sysmmu4", "aclk_200", 0, > + EXYNOS4210_CLKGATE_IP_IMAGE, 4, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc0, 5), "sysmmu5", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 7, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc1, 6), "sysmmu6", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 8, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc2, 7), "sysmmu7", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 9, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(fimc3, 8), "sysmmu8", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_CAM, 10, "sysmmu"), > + GATECLK(SYSMMU_CLOCK_DEVNAME(fimd, 10), "sysmmu10", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_LCD0, 4, "sysmmu"), > + GATECLK("dma-pl330.0", "dma0", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 0, "dma"), > + GATECLK("dma-pl330.1", "dma1", "aclk_133", 0, > + EXYNOS4_CLKGATE_IP_FSYS, 1, "dma"), > + GATECLK("exynos4-fb.0", "fimd", "aclk_160", 0, > + EXYNOS4_CLKGATE_IP_LCD0, 0, "lcd"), > + GATECLK("exynos4210-spi.0", "sclk_spi0", "div_spi0_pre", 0, > + EXYNOS4_CLKSRC_MASK_PERIL1, 16, "spi_busclk0"), > + GATECLK("exynos4210-spi.1", "sclk_spi1", "div_spi1_pre", 0, > + EXYNOS4_CLKSRC_MASK_PERIL1, 20, "spi_busclk0"), > + GATECLK("exynos4210-spi.2", "sclk_spi2", "div_spi2_pre", 0, > + EXYNOS4_CLKSRC_MASK_PERIL1, 24, "spi_busclk0"), > + GATECLK("exynos4-sdhci.0", "sclk_mmc0", "div_mmc0_pre", 0, > + EXYNOS4_CLKSRC_MASK_FSYS, 0, "mmc_busclk.2"), > + GATECLK("exynos4-sdhci.1", "sclk_mmc1", "div_mmc1_pre", 0, > + EXYNOS4_CLKSRC_MASK_FSYS, 4, "mmc_busclk.2"), > + GATECLK("exynos4-sdhci.2", "sclk_mmc2", "div_mmc2_pre", 0, > + EXYNOS4_CLKSRC_MASK_FSYS, 8, "mmc_busclk.2"), > + GATECLK("exynos4-sdhci.3", "sclk_mmc3", "div_mmc3_pre", 0, > + EXYNOS4_CLKSRC_MASK_FSYS, 12, "mmc_busclk.2"), > + GATECLK("s5p-mipi-csis.0", "sclk_csis0", "div_csis0", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 24, "sclk_csis"), > + GATECLK("s5p-mipi-csis.1", "sclk_csis1", "div_csis1", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 28, "sclk_csis"), > + GATECLK(NULL, "sclk_cam0", "div_cam0", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 16, NULL), > + GATECLK(NULL, "sclk_cam1", "div_cam1", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 20, NULL), > + GATECLK("exynos4-fimc.0", "sclk_fimc", "div_fimc0", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 0, "sclk_fimc"), + GATECLK("exynos4-fimc.0", "sclk_fimc0", "div_fimc0", 0, + EXYNOS4_CLKSRC_MASK_CAM, 0, "sclk_fimc"), > + GATECLK("exynos4-fimc.1", "sclk_fimc", "div_fimc1", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 4, "sclk_fimc"), + GATECLK("exynos4-fimc.1", "sclk_fimc1", "div_fimc1", 0, + EXYNOS4_CLKSRC_MASK_CAM, 4, "sclk_fimc"), > + GATECLK("exynos4-fimc.2", "sclk_fimc", "div_fimc2", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 8, "sclk_fimc"), + GATECLK("exynos4-fimc.2", "sclk_fimc2", "div_fimc2", 0, + EXYNOS4_CLKSRC_MASK_CAM, 8, "sclk_fimc"), > + GATECLK("exynos4-fimc.3", "sclk_fimc", "div_fimc3", 0, > + EXYNOS4_CLKSRC_MASK_CAM, 12, "sclk_fimc"), + GATECLK("exynos4-fimc.3", "sclk_fimc3", "div_fimc3", 0, + EXYNOS4_CLKSRC_MASK_CAM, 12, "sclk_fimc"), > + GATECLK("exynos4-fb.0", "sclk_fimd", "div_fimd0", 0, > + EXYNOS4_CLKSRC_MASK_LCD0, 0, "sclk_fimd"), > +}; > + > +/* register clock common to all Exynos4 platforms */ > +void __init exynos4_clk_init(void) > +{ > + samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks, > + ARRAY_SIZE(exynos4_fixed_rate_clks)); > + samsung_clk_register_mux(exynos4_mux_clks, > + ARRAY_SIZE(exynos4_mux_clks)); > + samsung_clk_register_div(exynos4_div_clks, > + ARRAY_SIZE(exynos4_div_clks)); > + samsung_clk_register_gate(exynos4_gate_clks, > + ARRAY_SIZE(exynos4_gate_clks)); > +} > + > +/* > + * Exynos4210 Specific Clocks > + */ > + > +static const char *exynos4210_vpll_parent_names[] __initdata = { > + "mout_vpll_src" }; > +static const char *mout_vpll_src_parents[] __initdata = { > + "fin_pll", "sclk_hdmi24m" }; > +static const char *exynos4210_mout_vpll_parents[] __initdata = { > + "mout_vpll_src", "fout_vpll", }; > + > +/* Exynos4210 specific fixed rate clocks */ > +static struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] = { > + FRATE_CLK(NULL, "sclk_usbphy1", NULL, CLK_IS_ROOT, 48000000), > +}; > + > +/* Exynos4210 specific mux-type clocks */ > +static struct samsung_mux_clock exynos4210_mux_clks[] = { > + MUXCLK(NULL, "mout_vpll_src", mout_vpll_src_parents, 0, > + EXYNOS4_CLKSRC_TOP1, 0, 1, 0), > + MUXCLK(NULL, "mout_vpll", exynos4210_mout_vpll_parents, 0, > + EXYNOS4_CLKSRC_TOP0, 8, 1, 0), > + MUXCLK(NULL, "mout_mpll", mout_mpll_parents, 0, > + EXYNOS4_CLKSRC_CPU, 8, 1, 0), > +}; > + > +static unsigned long exynos4210_get_rate_apll(unsigned long xtal_rate) > +{ > + return s5p_get_pll45xx(xtal_rate, > + __raw_readl(EXYNOS4_APLL_CON0), pll_4508); > +} > + > +static unsigned long exynos4210_get_rate_mpll(unsigned long xtal_rate) > +{ > + return s5p_get_pll45xx(xtal_rate, > + __raw_readl(EXYNOS4_MPLL_CON0), pll_4508); > +} > + > +static unsigned long exynos4210_get_rate_epll(unsigned long xtal_rate) > +{ > + return s5p_get_pll46xx(xtal_rate, __raw_readl(EXYNOS4_EPLL_CON0), > + __raw_readl(EXYNOS4_EPLL_CON1), pll_4600); > +} > + > +static unsigned long exynos4210_get_rate_vpll(unsigned long > vpllsrc_rate) +{ > + return s5p_get_pll46xx(vpllsrc_rate, __raw_readl(EXYNOS4_VPLL_CON0), > + __raw_readl(EXYNOS4_VPLL_CON1), pll_4650c); > +} > + > +static u32 exynos4_vpll_div[][8] = { > + { 54000000, 3, 53, 3, 1024, 0, 17, 0 }, > + { 108000000, 3, 53, 2, 1024, 0, 17, 0 }, > +}; > + > +static int exynos4210_vpll_set_rate(unsigned long rate) > +{ > + unsigned int vpll_con0, vpll_con1 = 0; > + unsigned int i; > + > + vpll_con0 = __raw_readl(EXYNOS4_VPLL_CON0); > + vpll_con0 &= ~(0x1 << 27 | \ > + PLL90XX_MDIV_MASK << PLL46XX_MDIV_SHIFT | \ > + PLL90XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | \ > + PLL90XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); > + > + vpll_con1 = __raw_readl(EXYNOS4_VPLL_CON1); > + vpll_con1 &= ~(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT | \ > + PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT | \ > + PLL4650C_KDIV_MASK << PLL46XX_KDIV_SHIFT); > + > + for (i = 0; i < ARRAY_SIZE(exynos4_vpll_div); i++) { > + if (exynos4_vpll_div[i][0] == rate) { > + vpll_con0 |= exynos4_vpll_div[i][1] << PLL46XX_PDIV_SHIFT; > + vpll_con0 |= exynos4_vpll_div[i][2] << PLL46XX_MDIV_SHIFT; > + vpll_con0 |= exynos4_vpll_div[i][3] << PLL46XX_SDIV_SHIFT; > + vpll_con1 |= exynos4_vpll_div[i][4] << PLL46XX_KDIV_SHIFT; > + vpll_con1 |= exynos4_vpll_div[i][5] << PLL46XX_MFR_SHIFT; > + vpll_con1 |= exynos4_vpll_div[i][6] << PLL46XX_MRR_SHIFT; > + vpll_con0 |= exynos4_vpll_div[i][7] << 27; > + break; > + } > + } > + > + if (i == ARRAY_SIZE(exynos4_vpll_div)) { > + pr_err("%s: Invalid Clock VPLL Frequency\n", __func__); > + return -EINVAL; > + } > + > + __raw_writel(vpll_con0, EXYNOS4_VPLL_CON0); > + __raw_writel(vpll_con1, EXYNOS4_VPLL_CON1); > + > + /* Wait for VPLL lock */ > + while (!(__raw_readl(EXYNOS4_VPLL_CON0) & (1 << PLL46XX_LOCKED_SHIFT))) > + continue; Is it guaranteed to lock in some reasonable time? Maybe some kind of timeout should be added? > + > + return 0; > +} > + > +/* Exynos4210 specific clock registration */ > +void __init exynos4210_clk_init(void) > +{ > + group1_parents[4] = "sclk_usbphy1"; > + > + exynos4_clk_init(); > + > + samsung_clk_register_pll("fout_apll", pll_parent_names, > + NULL, exynos4210_get_rate_apll); > + samsung_clk_register_pll("fout_mpll", pll_parent_names, > + NULL, exynos4210_get_rate_mpll); > + samsung_clk_register_pll("fout_epll", pll_parent_names, > + NULL, exynos4210_get_rate_epll); > + samsung_clk_register_pll("fout_vpll", exynos4210_vpll_parent_names, > + exynos4210_vpll_set_rate, exynos4210_get_rate_vpll); > + > + samsung_clk_register_fixed_rate(exynos4210_fixed_rate_clks, > + ARRAY_SIZE(exynos4210_fixed_rate_clks)); > + samsung_clk_register_mux(exynos4210_mux_clks, > + ARRAY_SIZE(exynos4210_mux_clks)); > + > + pr_info("EXYNOS4210: PLL settings: A=%ld, M=%ld, E=%ld, V=%ld\n", > + _get_rate("fout_apll"), _get_rate("fout_mpll"), > + _get_rate("fout_epll"), _get_rate("fout_vpll")); > + > + pr_info("EXYNOS4210: ARMCLK=%ld, ACLK200=%ld, ACLK100=%ld\n" > + " ACLK160=%ld, ACLK133=%ld\n", _get_rate("armclk"), > + _get_rate("aclk_200"), _get_rate("aclk_100"), > + _get_rate("aclk_160"), _get_rate("aclk_133")); > +} > + > +/* > + * Exynos4212 Specific Clocks > + */ > + > +static const char *exynos4212_mout_vpll_parents[] __initdata = { > + "fin_pll", "fout_vpll", }; > + > +/* Exynos4212 specific mux clocks */ > +static struct samsung_mux_clock exynos4212_mux_clks[] = { > + MUXCLK(NULL, "mout_mpll", mout_mpll_parents, 0, > + EXYNOS4_CLKSRC_DMC, 12, 1, 0), > + MUXCLK(NULL, "mout_vpll", exynos4212_mout_vpll_parents, 0, > + EXYNOS4_CLKSRC_TOP0, 8, 1, 0), > +}; > + > +static unsigned long exynos4212_get_rate_apll(unsigned long xtal_rate) > +{ > + return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0)); > +} > + > +static unsigned long exynos4212_get_rate_mpll(unsigned long xtal_rate) > +{ > + return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS4_MPLL_CON0)); > +} > + > +static unsigned long exynos4212_get_rate_epll(unsigned long xtal_rate) > +{ > + return s5p_get_pll36xx(xtal_rate, __raw_readl(EXYNOS4_EPLL_CON0), > + __raw_readl(EXYNOS4_EPLL_CON1)); > +} > + > +static unsigned long exynos4212_get_rate_vpll(unsigned long > vpllsrc_rate) +{ > + return s5p_get_pll36xx(vpllsrc_rate, __raw_readl(EXYNOS4_VPLL_CON0), > + __raw_readl(EXYNOS4_VPLL_CON1)); > +} > + > +/* Exynos4212 specific clock registeration */ > +void __init exynos4212_clk_init(void) > +{ > + exynos4_clk_init(); > + > + samsung_clk_register_pll("fout_apll", pll_parent_names, > + NULL, exynos4212_get_rate_apll); > + samsung_clk_register_pll("fout_mpll", pll_parent_names, > + NULL, exynos4212_get_rate_mpll); > + samsung_clk_register_pll("fout_epll", pll_parent_names, > + NULL, exynos4212_get_rate_epll); > + samsung_clk_register_pll("fout_vpll", pll_parent_names, > + NULL, exynos4212_get_rate_vpll); > + > + samsung_clk_register_mux(exynos4212_mux_clks, > + ARRAY_SIZE(exynos4212_mux_clks)); > + > + pr_info("EXYNOS4210: PLL settings: A=%ld, M=%ld, E=%ld, V=%ld\n", > + _get_rate("fout_apll"), _get_rate("fout_mpll"), > + _get_rate("fout_epll"), _get_rate("fout_vpll")); > + > + pr_info("EXYNOS4210: ARMCLK=%ld, ACLK200=%ld, ACLK100=%ld\n" > + " ACLK160=%ld, ACLK133=%ld\n", _get_rate("armclk"), > + _get_rate("aclk_200"), _get_rate("aclk_100"), > + _get_rate("aclk_160"), _get_rate("aclk_133")); > +} > diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c > new file mode 100644 > index 0000000..65156b9 > --- /dev/null > +++ b/drivers/clk/samsung/clk.c > @@ -0,0 +1,231 @@ > +/* > + * Copyright (c) 2012 Samsung Electronics Co., Ltd. > + * Copyright (c) 2012 Linaro Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This file includes utility functions to register clocks to common > + * clock framework for Samsung platforms. This includes an > implementation + * of Samsung 'pll type' clock to represent the > implementation of the + * pll found on Samsung platforms. In addition to > that, utility functions + * to register mux, div, gate and fixed rate > types of clocks are included. +*/ > + > +#include "clk.h" > + > +static DEFINE_SPINLOCK(lock); > + > +#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) > + > +/* determine the output clock speed of the pll */ > +static unsigned long samsung_clk_pll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct samsung_clk_pll *clk_pll = to_clk_pll(hw); > + > + if (clk_pll->get_rate) > + return to_clk_pll(hw)->get_rate(parent_rate); > + > + return 0; > +} > + > +/* round operation not supported */ > +static long samsung_clk_pll_round_rate(struct clk_hw *hw, unsigned long > drate, + unsigned long *prate) > +{ > + return samsung_clk_pll_recalc_rate(hw, *prate); > +} > + > +/* set the clock output rate of the pll */ > +static int samsung_clk_pll_set_rate(struct clk_hw *hw, unsigned long > drate, + unsigned long prate) > +{ > + struct samsung_clk_pll *clk_pll = to_clk_pll(hw); > + > + if (clk_pll->set_rate) > + return to_clk_pll(hw)->set_rate(drate); > + > + return 0; > +} > + > +/* clock operations for samsung pll clock type */ > +static const struct clk_ops samsung_clk_pll_ops = { > + .recalc_rate = samsung_clk_pll_recalc_rate, > + .round_rate = samsung_clk_pll_round_rate, > + .set_rate = samsung_clk_pll_set_rate, > +}; > + > +/* register a samsung pll type clock */ > +void __init samsung_clk_register_pll(const char *name, const char > **pnames, + int (*set_rate)(unsigned long rate), > + unsigned long (*get_rate)(unsigned long rate)) > +{ > + struct samsung_clk_pll *clk_pll; > + struct clk *clk; > + struct clk_init_data init; > + int ret; > + > + clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL); > + if (!clk_pll) { > + pr_err("%s: could not allocate pll clk %s\n", __func__, name); > + return; > + } > + > + init.name = name; > + init.ops = &samsung_clk_pll_ops; > + init.flags = CLK_GET_RATE_NOCACHE; > + init.parent_names = pnames; > + init.num_parents = 1; > + > + clk_pll->set_rate = set_rate; > + clk_pll->get_rate = get_rate; > + clk_pll->hw.init = &init; > + > + /* register the clock */ > + clk = clk_register(NULL, &clk_pll->hw); > + if (IS_ERR(clk)) { > + pr_err("%s: failed to register pll clock %s\n", __func__, > + name); > + kfree(clk_pll); > + return; > + } > + > + ret = clk_register_clkdev(clk, name, NULL); > + if (ret) > + pr_err("%s: failed to register clock lookup for %s", __func__, > + name); > +} > + > +/* register a list of fixed clocks */ > +void __init samsung_clk_register_fixed_rate( > + struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk) > +{ > + struct clk *clk; > + unsigned int idx, ret; > + > + for (idx = 0; idx < nr_clk; idx++, clk_list++) { > + clk = clk_register_fixed_rate(NULL, clk_list->name, > + clk_list->parent_name, clk_list->flags, > + clk_list->fixed_rate); > + if (IS_ERR_OR_NULL(clk)) { Is the check for NULL needed here? Looking at samsung_fixed_rate_clock and clk_register, the convention is to always return ERR_PTR on error. > + pr_err("clock: failed to register clock %s\n", > + clk_list->name); > + continue; > + } > + > + ret = clk_register_clkdev(clk, clk_list->name, > + clk_list->dev_name); > + if (ret) > + pr_err("clock: failed to register clock lookup for %s", > + clk_list->name); > + } > +} > + > +/* register a list of mux clocks */ > +void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list, > + unsigned int nr_clk) > +{ > + struct clk *clk; > + unsigned int idx, ret; > + > + for (idx = 0; idx < nr_clk; idx++, clk_list++) { > + clk = clk_register_mux(NULL, clk_list->name, > + clk_list->parent_names, clk_list->num_parents, > + clk_list->flags, clk_list->reg, clk_list->shift, > + clk_list->width, clk_list->mux_flags, &lock); > + if (IS_ERR_OR_NULL(clk)) { See my comment for samsung_clk_register_fixed_rate . > + pr_err("clock: failed to register clock %s\n", > + clk_list->name); > + continue; > + } > + > + ret = clk_register_clkdev(clk, clk_list->name, > + clk_list->dev_name); > + if (ret) > + pr_err("clock: failed to register clock lookup for %s", > + clk_list->name); > + > + if (clk_list->alias) > + clk_register_clkdev(clk, clk_list->alias, > + clk_list->dev_name); > + } > +} > + > +/* reguster a list of div clocks */ > +void __init samsung_clk_register_div(struct samsung_div_clock *clk_list, > + unsigned int nr_clk) > +{ > + struct clk *clk; > + unsigned int idx, ret; > + > + for (idx = 0; idx < nr_clk; idx++, clk_list++) { > + clk = clk_register_divider(NULL, clk_list->name, > + clk_list->parent_name, clk_list->flags, clk_list->reg, > + clk_list->shift, clk_list->width, clk_list->div_flags, > + &lock); > + if (IS_ERR_OR_NULL(clk)) { See my comment for samsung_clk_register_fixed_rate . > + pr_err("clock: failed to register clock %s\n", > + clk_list->name); > + continue; > + } > + > + ret = clk_register_clkdev(clk, clk_list->name, > + clk_list->dev_name); > + if (ret) > + pr_err("clock: failed to register clock lookup for %s", > + clk_list->name); > + > + if (clk_list->alias) > + clk_register_clkdev(clk, clk_list->alias, > + clk_list->dev_name); > + } > +} > + > +/* register a list of gate clocks */ > +void __init samsung_clk_register_gate(struct samsung_gate_clock > *clk_list, + unsigned int nr_clk) > +{ > + struct clk *clk; > + unsigned int idx, ret; > + > + for (idx = 0; idx < nr_clk; idx++, clk_list++) { > + clk = clk_register_gate(NULL, clk_list->name, > + clk_list->parent_name, clk_list->flags, clk_list->reg, > + clk_list->bit_idx, clk_list->gate_flags, &lock); > + if (IS_ERR_OR_NULL(clk)) { See my comment for samsung_clk_register_fixed_rate . > + pr_err("clock: failed to register clock %s\n", > + clk_list->name); > + continue; > + } > + > + ret = clk_register_clkdev(clk, clk_list->name, > + clk_list->dev_name); > + if (ret) { > + pr_err("clock: failed to register clock lookup for %s", > + clk_list->name); > + continue; > + } > + > + ret = clk_register_clkdev(clk, clk_list->alias, > + clk_list->dev_name); > + if (ret) > + pr_err("clock: failed to register alias %s for clock " > + " %s", clk_list->alias, clk_list->name); > + } > +} > + > +/* utility function to get the rate of a specified clock */ > +unsigned long _get_rate(const char *clk_name) > +{ > + struct clk *clk; > + unsigned long rate; > + > + clk = clk_get(NULL, clk_name); > + if (IS_ERR(clk)) > + return 0; > + rate = clk_get_rate(clk); > + clk_put(clk); > + return rate; > +} Shouldn't it be moved to clk-exynos4.c and made static? Best regards, -- Tomasz Figa Samsung Poland R&D Center -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/