diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2016-09-14 18:06:47 (GMT) |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2016-09-14 18:06:47 (GMT) |
commit | 3db385ea144daea9c6e1a15f98eacafaec9ad9f1 (patch) | |
tree | 25316f2cb4f42674bcd127d3b812e17cbfe536eb /drivers/clk | |
parent | 7348b6ce94019548f64d54c6934d5ace3f2b50a9 (diff) | |
parent | be95d2c7d918b2b7b973378a1e92bdc6559c21f9 (diff) | |
download | linux-3db385ea144daea9c6e1a15f98eacafaec9ad9f1.tar.xz |
Merge tag 'clk-v4.9-samsung' of git://linuxtv.org/snawrocki/samsung into clk-next
Pull samsung clk driver updates from Sylwester Nawrocki:
In addition to a few clean up and code consolidation patches this
includes:
- addition of sound subsystem related clocks for Exynos5410 SoC
(EPLL, PDMA) and support for "samsung,exynos5410-audss-clock"
compatible in the clk-exynos-audss driver,
- addition of DRAM controller related clocks for exynos5420,
- MAINTAINERS update adding Chanwoo Choi as the Samsung SoC
clock drivers co-maintainer.
* tag 'clk-v4.9-samsung' of git://linuxtv.org/snawrocki/samsung:
clk: samsung: Add support for EPLL on exynos5410
clk: samsung: clk-exynos-audss: Whitespace and debug trace cleanup
clk: samsung: clk-exynos-audss: Add exynos5410 compatible
clk: samsung: clk-exynos-audss: controller variant handling rework
clk: samsung: Use common registration function for pll2550x
clk: samsung: exynos5410: Expose the peripheral DMA gate clocks
clk: samsung: exynos5420: Add clocks for CMU_CDREX domain
clk: samsung: exynos5410: Use samsung_cmu_register_one() to simplify code
clk: samsung: exynos5260: Move struct samsung_cmu_info to init section
MAINTAINERS: Add myself as Samsung SoC clock drivers co-maintainer
clk: samsung: exynos5410: Add clock IDs for PDMA and EPLL clocks
clk: samsung: Add clock IDs for the CMU_CDREX (DRAM Express Controller)
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/samsung/clk-exynos-audss.c | 84 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5260.c | 350 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5410.c | 61 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5420.c | 37 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5440.c | 9 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-pll.c | 154 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-pll.h | 2 |
7 files changed, 419 insertions, 278 deletions
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index bdf8b97..51d152f 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -14,18 +14,13 @@ #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/syscore_ops.h> #include <linux/module.h> #include <linux/platform_device.h> #include <dt-bindings/clock/exynos-audss-clk.h> -enum exynos_audss_clk_type { - TYPE_EXYNOS4210, - TYPE_EXYNOS5250, - TYPE_EXYNOS5420, -}; - static DEFINE_SPINLOCK(lock); static struct clk **clk_table; static void __iomem *reg_base; @@ -44,9 +39,9 @@ static struct clk *epll; #ifdef CONFIG_PM_SLEEP static unsigned long reg_save[][2] = { - {ASS_CLK_SRC, 0}, - {ASS_CLK_DIV, 0}, - {ASS_CLK_GATE, 0}, + { ASS_CLK_SRC, 0 }, + { ASS_CLK_DIV, 0 }, + { ASS_CLK_GATE, 0 }, }; static int exynos_audss_clk_suspend(void) @@ -73,14 +68,43 @@ static struct syscore_ops exynos_audss_clk_syscore_ops = { }; #endif /* CONFIG_PM_SLEEP */ +struct exynos_audss_clk_drvdata { + unsigned int has_adma_clk:1; + unsigned int has_mst_clk:1; + unsigned int enable_epll:1; + unsigned int num_clks; +}; + +static const struct exynos_audss_clk_drvdata exynos4210_drvdata = { + .num_clks = EXYNOS_AUDSS_MAX_CLKS - 1, +}; + +static const struct exynos_audss_clk_drvdata exynos5410_drvdata = { + .num_clks = EXYNOS_AUDSS_MAX_CLKS - 1, + .has_mst_clk = 1, +}; + +static const struct exynos_audss_clk_drvdata exynos5420_drvdata = { + .num_clks = EXYNOS_AUDSS_MAX_CLKS, + .has_adma_clk = 1, + .enable_epll = 1, +}; + static const struct of_device_id exynos_audss_clk_of_match[] = { - { .compatible = "samsung,exynos4210-audss-clock", - .data = (void *)TYPE_EXYNOS4210, }, - { .compatible = "samsung,exynos5250-audss-clock", - .data = (void *)TYPE_EXYNOS5250, }, - { .compatible = "samsung,exynos5420-audss-clock", - .data = (void *)TYPE_EXYNOS5420, }, - {}, + { + .compatible = "samsung,exynos4210-audss-clock", + .data = &exynos4210_drvdata, + }, { + .compatible = "samsung,exynos5250-audss-clock", + .data = &exynos4210_drvdata, + }, { + .compatible = "samsung,exynos5410-audss-clock", + .data = &exynos5410_drvdata, + }, { + .compatible = "samsung,exynos5420-audss-clock", + .data = &exynos5420_drvdata, + }, + { }, }; static void exynos_audss_clk_teardown(void) @@ -106,19 +130,17 @@ static void exynos_audss_clk_teardown(void) /* register exynos_audss clocks */ static int exynos_audss_clk_probe(struct platform_device *pdev) { - int i, ret = 0; - struct resource *res; const char *mout_audss_p[] = {"fin_pll", "fout_epll"}; const char *mout_i2s_p[] = {"mout_audss", "cdclk0", "sclk_audio0"}; const char *sclk_pcm_p = "sclk_pcm0"; struct clk *pll_ref, *pll_in, *cdclk, *sclk_audio, *sclk_pcm_in; - const struct of_device_id *match; - enum exynos_audss_clk_type variant; + const struct exynos_audss_clk_drvdata *variant; + struct resource *res; + int i, ret = 0; - match = of_match_node(exynos_audss_clk_of_match, pdev->dev.of_node); - if (!match) + variant = of_device_get_match_data(&pdev->dev); + if (!variant) return -EINVAL; - variant = (enum exynos_audss_clk_type)match->data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(&pdev->dev, res); @@ -126,7 +148,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to map audss registers\n"); return PTR_ERR(reg_base); } - /* EPLL don't have to be enabled for boards other than Exynos5420 */ + epll = ERR_PTR(-ENODEV); clk_table = devm_kzalloc(&pdev->dev, @@ -136,10 +158,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) return -ENOMEM; clk_data.clks = clk_table; - if (variant == TYPE_EXYNOS5420) - clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS; - else - clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS - 1; + clk_data.clk_num = variant->num_clks; pll_ref = devm_clk_get(&pdev->dev, "pll_ref"); pll_in = devm_clk_get(&pdev->dev, "pll_in"); @@ -148,13 +167,13 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) if (!IS_ERR(pll_in)) { mout_audss_p[1] = __clk_get_name(pll_in); - if (variant == TYPE_EXYNOS5420) { + if (variant->enable_epll) { epll = pll_in; ret = clk_prepare_enable(epll); if (ret) { dev_err(&pdev->dev, - "failed to prepare the epll clock\n"); + "failed to prepare the epll clock\n"); return ret; } } @@ -210,7 +229,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) sclk_pcm_p, CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 5, 0, &lock); - if (variant == TYPE_EXYNOS5420) { + if (variant->has_adma_clk) { clk_table[EXYNOS_ADMA] = clk_register_gate(NULL, "adma", "dout_srp", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 9, 0, &lock); @@ -234,9 +253,6 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP register_syscore_ops(&exynos_audss_clk_syscore_ops); #endif - - dev_info(&pdev->dev, "setup completed\n"); - return 0; unregister: diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index a43642c..fd1d9bf 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -131,21 +131,21 @@ static const struct samsung_gate_clock aud_gate_clks[] __initconst = { EN_IP_AUD, 4, 0, 0), }; +static const struct samsung_cmu_info aud_cmu __initconst = { + .mux_clks = aud_mux_clks, + .nr_mux_clks = ARRAY_SIZE(aud_mux_clks), + .div_clks = aud_div_clks, + .nr_div_clks = ARRAY_SIZE(aud_div_clks), + .gate_clks = aud_gate_clks, + .nr_gate_clks = ARRAY_SIZE(aud_gate_clks), + .nr_clk_ids = AUD_NR_CLK, + .clk_regs = aud_clk_regs, + .nr_clk_regs = ARRAY_SIZE(aud_clk_regs), +}; + static void __init exynos5260_clk_aud_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = aud_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(aud_mux_clks); - cmu.div_clks = aud_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(aud_div_clks); - cmu.gate_clks = aud_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(aud_gate_clks); - cmu.nr_clk_ids = AUD_NR_CLK; - cmu.clk_regs = aud_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(aud_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &aud_cmu); } CLK_OF_DECLARE(exynos5260_clk_aud, "samsung,exynos5260-clock-aud", @@ -321,21 +321,21 @@ static const struct samsung_gate_clock disp_gate_clks[] __initconst = { EN_IP_DISP, 25, 0, 0), }; +static const struct samsung_cmu_info disp_cmu __initconst = { + .mux_clks = disp_mux_clks, + .nr_mux_clks = ARRAY_SIZE(disp_mux_clks), + .div_clks = disp_div_clks, + .nr_div_clks = ARRAY_SIZE(disp_div_clks), + .gate_clks = disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(disp_gate_clks), + .nr_clk_ids = DISP_NR_CLK, + .clk_regs = disp_clk_regs, + .nr_clk_regs = ARRAY_SIZE(disp_clk_regs), +}; + static void __init exynos5260_clk_disp_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = disp_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(disp_mux_clks); - cmu.div_clks = disp_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(disp_div_clks); - cmu.gate_clks = disp_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(disp_gate_clks); - cmu.nr_clk_ids = DISP_NR_CLK; - cmu.clk_regs = disp_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(disp_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &disp_cmu); } CLK_OF_DECLARE(exynos5260_clk_disp, "samsung,exynos5260-clock-disp", @@ -385,21 +385,21 @@ static const struct samsung_pll_clock egl_pll_clks[] __initconst = { pll2550_24mhz_tbl), }; +static const struct samsung_cmu_info egl_cmu __initconst = { + .pll_clks = egl_pll_clks, + .nr_pll_clks = ARRAY_SIZE(egl_pll_clks), + .mux_clks = egl_mux_clks, + .nr_mux_clks = ARRAY_SIZE(egl_mux_clks), + .div_clks = egl_div_clks, + .nr_div_clks = ARRAY_SIZE(egl_div_clks), + .nr_clk_ids = EGL_NR_CLK, + .clk_regs = egl_clk_regs, + .nr_clk_regs = ARRAY_SIZE(egl_clk_regs), +}; + static void __init exynos5260_clk_egl_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.pll_clks = egl_pll_clks; - cmu.nr_pll_clks = ARRAY_SIZE(egl_pll_clks); - cmu.mux_clks = egl_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(egl_mux_clks); - cmu.div_clks = egl_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(egl_div_clks); - cmu.nr_clk_ids = EGL_NR_CLK; - cmu.clk_regs = egl_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(egl_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &egl_cmu); } CLK_OF_DECLARE(exynos5260_clk_egl, "samsung,exynos5260-clock-egl", @@ -487,19 +487,19 @@ static const struct samsung_gate_clock fsys_gate_clks[] __initconst = { EN_IP_FSYS_SECURE_SMMU_RTIC, 12, 0, 0), }; +static const struct samsung_cmu_info fsys_cmu __initconst = { + .mux_clks = fsys_mux_clks, + .nr_mux_clks = ARRAY_SIZE(fsys_mux_clks), + .gate_clks = fsys_gate_clks, + .nr_gate_clks = ARRAY_SIZE(fsys_gate_clks), + .nr_clk_ids = FSYS_NR_CLK, + .clk_regs = fsys_clk_regs, + .nr_clk_regs = ARRAY_SIZE(fsys_clk_regs), +}; + static void __init exynos5260_clk_fsys_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = fsys_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(fsys_mux_clks); - cmu.gate_clks = fsys_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(fsys_gate_clks); - cmu.nr_clk_ids = FSYS_NR_CLK; - cmu.clk_regs = fsys_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(fsys_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &fsys_cmu); } CLK_OF_DECLARE(exynos5260_clk_fsys, "samsung,exynos5260-clock-fsys", @@ -576,21 +576,21 @@ static const struct samsung_gate_clock g2d_gate_clks[] __initconst = { EN_IP_G2D_SECURE_SMMU_G2D, 15, 0, 0), }; +static const struct samsung_cmu_info g2d_cmu __initconst = { + .mux_clks = g2d_mux_clks, + .nr_mux_clks = ARRAY_SIZE(g2d_mux_clks), + .div_clks = g2d_div_clks, + .nr_div_clks = ARRAY_SIZE(g2d_div_clks), + .gate_clks = g2d_gate_clks, + .nr_gate_clks = ARRAY_SIZE(g2d_gate_clks), + .nr_clk_ids = G2D_NR_CLK, + .clk_regs = g2d_clk_regs, + .nr_clk_regs = ARRAY_SIZE(g2d_clk_regs), +}; + static void __init exynos5260_clk_g2d_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = g2d_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(g2d_mux_clks); - cmu.div_clks = g2d_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(g2d_div_clks); - cmu.gate_clks = g2d_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(g2d_gate_clks); - cmu.nr_clk_ids = G2D_NR_CLK; - cmu.clk_regs = g2d_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(g2d_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &g2d_cmu); } CLK_OF_DECLARE(exynos5260_clk_g2d, "samsung,exynos5260-clock-g2d", @@ -637,23 +637,23 @@ static const struct samsung_pll_clock g3d_pll_clks[] __initconst = { pll2550_24mhz_tbl), }; +static const struct samsung_cmu_info g3d_cmu __initconst = { + .pll_clks = g3d_pll_clks, + .nr_pll_clks = ARRAY_SIZE(g3d_pll_clks), + .mux_clks = g3d_mux_clks, + .nr_mux_clks = ARRAY_SIZE(g3d_mux_clks), + .div_clks = g3d_div_clks, + .nr_div_clks = ARRAY_SIZE(g3d_div_clks), + .gate_clks = g3d_gate_clks, + .nr_gate_clks = ARRAY_SIZE(g3d_gate_clks), + .nr_clk_ids = G3D_NR_CLK, + .clk_regs = g3d_clk_regs, + .nr_clk_regs = ARRAY_SIZE(g3d_clk_regs), +}; + static void __init exynos5260_clk_g3d_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.pll_clks = g3d_pll_clks; - cmu.nr_pll_clks = ARRAY_SIZE(g3d_pll_clks); - cmu.mux_clks = g3d_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(g3d_mux_clks); - cmu.div_clks = g3d_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(g3d_div_clks); - cmu.gate_clks = g3d_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(g3d_gate_clks); - cmu.nr_clk_ids = G3D_NR_CLK; - cmu.clk_regs = g3d_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(g3d_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &g3d_cmu); } CLK_OF_DECLARE(exynos5260_clk_g3d, "samsung,exynos5260-clock-g3d", @@ -772,21 +772,21 @@ static const struct samsung_gate_clock gscl_gate_clks[] __initconst = { EN_IP_GSCL_SECURE_SMMU_MSCL1, 20, 0, 0), }; +static const struct samsung_cmu_info gscl_cmu __initconst = { + .mux_clks = gscl_mux_clks, + .nr_mux_clks = ARRAY_SIZE(gscl_mux_clks), + .div_clks = gscl_div_clks, + .nr_div_clks = ARRAY_SIZE(gscl_div_clks), + .gate_clks = gscl_gate_clks, + .nr_gate_clks = ARRAY_SIZE(gscl_gate_clks), + .nr_clk_ids = GSCL_NR_CLK, + .clk_regs = gscl_clk_regs, + .nr_clk_regs = ARRAY_SIZE(gscl_clk_regs), +}; + static void __init exynos5260_clk_gscl_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = gscl_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(gscl_mux_clks); - cmu.div_clks = gscl_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(gscl_div_clks); - cmu.gate_clks = gscl_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(gscl_gate_clks); - cmu.nr_clk_ids = GSCL_NR_CLK; - cmu.clk_regs = gscl_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(gscl_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &gscl_cmu); } CLK_OF_DECLARE(exynos5260_clk_gscl, "samsung,exynos5260-clock-gscl", @@ -891,21 +891,21 @@ static const struct samsung_gate_clock isp_gate_clks[] __initconst = { EN_SCLK_ISP, 9, CLK_SET_RATE_PARENT, 0), }; +static const struct samsung_cmu_info isp_cmu __initconst = { + .mux_clks = isp_mux_clks, + .nr_mux_clks = ARRAY_SIZE(isp_mux_clks), + .div_clks = isp_div_clks, + .nr_div_clks = ARRAY_SIZE(isp_div_clks), + .gate_clks = isp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(isp_gate_clks), + .nr_clk_ids = ISP_NR_CLK, + .clk_regs = isp_clk_regs, + .nr_clk_regs = ARRAY_SIZE(isp_clk_regs), +}; + static void __init exynos5260_clk_isp_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = isp_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(isp_mux_clks); - cmu.div_clks = isp_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(isp_div_clks); - cmu.gate_clks = isp_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(isp_gate_clks); - cmu.nr_clk_ids = ISP_NR_CLK; - cmu.clk_regs = isp_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(isp_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &isp_cmu); } CLK_OF_DECLARE(exynos5260_clk_isp, "samsung,exynos5260-clock-isp", @@ -955,21 +955,21 @@ static const struct samsung_pll_clock kfc_pll_clks[] __initconst = { pll2550_24mhz_tbl), }; +static const struct samsung_cmu_info kfc_cmu __initconst = { + .pll_clks = kfc_pll_clks, + .nr_pll_clks = ARRAY_SIZE(kfc_pll_clks), + .mux_clks = kfc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(kfc_mux_clks), + .div_clks = kfc_div_clks, + .nr_div_clks = ARRAY_SIZE(kfc_div_clks), + .nr_clk_ids = KFC_NR_CLK, + .clk_regs = kfc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(kfc_clk_regs), +}; + static void __init exynos5260_clk_kfc_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.pll_clks = kfc_pll_clks; - cmu.nr_pll_clks = ARRAY_SIZE(kfc_pll_clks); - cmu.mux_clks = kfc_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(kfc_mux_clks); - cmu.div_clks = kfc_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(kfc_div_clks); - cmu.nr_clk_ids = KFC_NR_CLK; - cmu.clk_regs = kfc_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(kfc_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &kfc_cmu); } CLK_OF_DECLARE(exynos5260_clk_kfc, "samsung,exynos5260-clock-kfc", @@ -1011,21 +1011,21 @@ static const struct samsung_gate_clock mfc_gate_clks[] __initconst = { EN_IP_MFC_SECURE_SMMU2_MFC, 7, 0, 0), }; +static const struct samsung_cmu_info mfc_cmu __initconst = { + .mux_clks = mfc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mfc_mux_clks), + .div_clks = mfc_div_clks, + .nr_div_clks = ARRAY_SIZE(mfc_div_clks), + .gate_clks = mfc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mfc_gate_clks), + .nr_clk_ids = MFC_NR_CLK, + .clk_regs = mfc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mfc_clk_regs), +}; + static void __init exynos5260_clk_mfc_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = mfc_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(mfc_mux_clks); - cmu.div_clks = mfc_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(mfc_div_clks); - cmu.gate_clks = mfc_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(mfc_gate_clks); - cmu.nr_clk_ids = MFC_NR_CLK; - cmu.clk_regs = mfc_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(mfc_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &mfc_cmu); } CLK_OF_DECLARE(exynos5260_clk_mfc, "samsung,exynos5260-clock-mfc", @@ -1158,23 +1158,23 @@ static const struct samsung_pll_clock mif_pll_clks[] __initconst = { pll2550_24mhz_tbl), }; +static const struct samsung_cmu_info mif_cmu __initconst = { + .pll_clks = mif_pll_clks, + .nr_pll_clks = ARRAY_SIZE(mif_pll_clks), + .mux_clks = mif_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mif_mux_clks), + .div_clks = mif_div_clks, + .nr_div_clks = ARRAY_SIZE(mif_div_clks), + .gate_clks = mif_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mif_gate_clks), + .nr_clk_ids = MIF_NR_CLK, + .clk_regs = mif_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mif_clk_regs), +}; + static void __init exynos5260_clk_mif_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.pll_clks = mif_pll_clks; - cmu.nr_pll_clks = ARRAY_SIZE(mif_pll_clks); - cmu.mux_clks = mif_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(mif_mux_clks); - cmu.div_clks = mif_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(mif_div_clks); - cmu.gate_clks = mif_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(mif_gate_clks); - cmu.nr_clk_ids = MIF_NR_CLK; - cmu.clk_regs = mif_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(mif_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &mif_cmu); } CLK_OF_DECLARE(exynos5260_clk_mif, "samsung,exynos5260-clock-mif", @@ -1366,21 +1366,21 @@ static const struct samsung_gate_clock peri_gate_clks[] __initconst = { EN_IP_PERI_SECURE_TZPC, 20, 0, 0), }; +static const struct samsung_cmu_info peri_cmu __initconst = { + .mux_clks = peri_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peri_mux_clks), + .div_clks = peri_div_clks, + .nr_div_clks = ARRAY_SIZE(peri_div_clks), + .gate_clks = peri_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peri_gate_clks), + .nr_clk_ids = PERI_NR_CLK, + .clk_regs = peri_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peri_clk_regs), +}; + static void __init exynos5260_clk_peri_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.mux_clks = peri_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(peri_mux_clks); - cmu.div_clks = peri_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(peri_div_clks); - cmu.gate_clks = peri_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(peri_gate_clks); - cmu.nr_clk_ids = PERI_NR_CLK; - cmu.clk_regs = peri_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(peri_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &peri_cmu); } CLK_OF_DECLARE(exynos5260_clk_peri, "samsung,exynos5260-clock-peri", @@ -1818,25 +1818,25 @@ static const struct samsung_pll_clock top_pll_clks[] __initconst = { pll2650_24mhz_tbl), }; +static const struct samsung_cmu_info top_cmu __initconst = { + .pll_clks = top_pll_clks, + .nr_pll_clks = ARRAY_SIZE(top_pll_clks), + .mux_clks = top_mux_clks, + .nr_mux_clks = ARRAY_SIZE(top_mux_clks), + .div_clks = top_div_clks, + .nr_div_clks = ARRAY_SIZE(top_div_clks), + .gate_clks = top_gate_clks, + .nr_gate_clks = ARRAY_SIZE(top_gate_clks), + .fixed_clks = fixed_rate_clks, + .nr_fixed_clks = ARRAY_SIZE(fixed_rate_clks), + .nr_clk_ids = TOP_NR_CLK, + .clk_regs = top_clk_regs, + .nr_clk_regs = ARRAY_SIZE(top_clk_regs), +}; + static void __init exynos5260_clk_top_init(struct device_node *np) { - struct samsung_cmu_info cmu = { NULL }; - - cmu.pll_clks = top_pll_clks; - cmu.nr_pll_clks = ARRAY_SIZE(top_pll_clks); - cmu.mux_clks = top_mux_clks; - cmu.nr_mux_clks = ARRAY_SIZE(top_mux_clks); - cmu.div_clks = top_div_clks; - cmu.nr_div_clks = ARRAY_SIZE(top_div_clks); - cmu.gate_clks = top_gate_clks; - cmu.nr_gate_clks = ARRAY_SIZE(top_gate_clks); - cmu.fixed_clks = fixed_rate_clks; - cmu.nr_fixed_clks = ARRAY_SIZE(fixed_rate_clks); - cmu.nr_clk_ids = TOP_NR_CLK; - cmu.clk_regs = top_clk_regs; - cmu.nr_clk_regs = ARRAY_SIZE(top_clk_regs); - - samsung_cmu_register_one(np, &cmu); + samsung_cmu_register_one(np, &top_cmu); } CLK_OF_DECLARE(exynos5260_clk_top, "samsung,exynos5260-clock-top", diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index 54ec486..fc471a4 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -14,6 +14,7 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/clk.h> #include "clk.h" @@ -21,6 +22,8 @@ #define APLL_CON0 0x100 #define CPLL_LOCK 0x10020 #define CPLL_CON0 0x10120 +#define EPLL_LOCK 0x10040 +#define EPLL_CON0 0x10130 #define MPLL_LOCK 0x4000 #define MPLL_CON0 0x4100 #define BPLL_LOCK 0x20010 @@ -58,7 +61,7 @@ /* list of PLLs */ enum exynos5410_plls { - apll, cpll, mpll, + apll, cpll, epll, mpll, bpll, kpll, nr_plls /* number of PLLs */ }; @@ -67,6 +70,7 @@ enum exynos5410_plls { PNAME(apll_p) = { "fin_pll", "fout_apll", }; PNAME(bpll_p) = { "fin_pll", "fout_bpll", }; PNAME(cpll_p) = { "fin_pll", "fout_cpll" }; +PNAME(epll_p) = { "fin_pll", "fout_epll" }; PNAME(mpll_p) = { "fin_pll", "fout_mpll", }; PNAME(kpll_p) = { "fin_pll", "fout_kpll", }; @@ -95,6 +99,8 @@ static const struct samsung_mux_clock exynos5410_mux_clks[] __initconst = { MUX(0, "sclk_bpll", bpll_p, SRC_CDREX, 0, 1), MUX(0, "sclk_bpll_muxed", bpll_user_p, SRC_TOP2, 24, 1), + MUX(0, "sclk_epll", epll_p, SRC_TOP2, 12, 1), + MUX(0, "sclk_cpll", cpll_p, SRC_TOP2, 8, 1), MUX(0, "sclk_mpll_bpll", mpll_bpll_p, SRC_TOP1, 20, 1), @@ -176,6 +182,8 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = { GATE(CLK_MMC0, "sdmmc0", "aclk200", GATE_BUS_FSYS0, 12, 0, 0), GATE(CLK_MMC1, "sdmmc1", "aclk200", GATE_BUS_FSYS0, 13, 0, 0), GATE(CLK_MMC2, "sdmmc2", "aclk200", GATE_BUS_FSYS0, 14, 0, 0), + GATE(CLK_PDMA1, "pdma1", "aclk200", GATE_BUS_FSYS0, 2, 0, 0), + GATE(CLK_PDMA0, "pdma0", "aclk200", GATE_BUS_FSYS0, 1, 0, 0), GATE(CLK_SCLK_USBPHY301, "sclk_usbphy301", "dout_usbphy301", GATE_TOP_SCLK_FSYS, 7, CLK_SET_RATE_PARENT, 0), @@ -217,11 +225,26 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = { GATE(CLK_USBD301, "usbd301", "aclk200_fsys", GATE_IP_FSYS, 20, 0, 0), }; -static const struct samsung_pll_clock exynos5410_plls[nr_plls] __initconst = { +static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = { + PLL_36XX_RATE(400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(333000000U, 111, 2, 2, 0), + PLL_36XX_RATE(300000000U, 100, 2, 2, 0), + PLL_36XX_RATE(266000000U, 266, 3, 3, 0), + PLL_36XX_RATE(200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(192000000U, 192, 3, 3, 0), + PLL_36XX_RATE(166000000U, 166, 3, 3, 0), + PLL_36XX_RATE(133000000U, 266, 3, 4, 0), + PLL_36XX_RATE(100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(66000000U, 176, 2, 5, 0), +}; + +static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = { [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK, APLL_CON0, NULL), [cpll] = PLL(pll_35xx, CLK_FOUT_CPLL, "fout_cpll", "fin_pll", CPLL_LOCK, CPLL_CON0, NULL), + [epll] = PLL(pll_2650x, CLK_FOUT_EPLL, "fout_epll", "fin_pll", EPLL_LOCK, + EPLL_CON0, NULL), [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", MPLL_LOCK, MPLL_CON0, NULL), [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", BPLL_LOCK, @@ -230,29 +253,27 @@ static const struct samsung_pll_clock exynos5410_plls[nr_plls] __initconst = { KPLL_CON0, NULL), }; +static const struct samsung_cmu_info cmu __initconst = { + .pll_clks = exynos5410_plls, + .nr_pll_clks = ARRAY_SIZE(exynos5410_plls), + .mux_clks = exynos5410_mux_clks, + .nr_mux_clks = ARRAY_SIZE(exynos5410_mux_clks), + .div_clks = exynos5410_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5410_div_clks), + .gate_clks = exynos5410_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5410_gate_clks), + .nr_clk_ids = CLK_NR_CLKS, +}; + /* register exynos5410 clocks */ static void __init exynos5410_clk_init(struct device_node *np) { - struct samsung_clk_provider *ctx; - void __iomem *reg_base; - - reg_base = of_iomap(np, 0); - if (!reg_base) - panic("%s: failed to map registers\n", __func__); - - ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); - - samsung_clk_register_pll(ctx, exynos5410_plls, - ARRAY_SIZE(exynos5410_plls), reg_base); + struct clk *xxti = of_clk_get(np, 0); - samsung_clk_register_mux(ctx, exynos5410_mux_clks, - ARRAY_SIZE(exynos5410_mux_clks)); - samsung_clk_register_div(ctx, exynos5410_div_clks, - ARRAY_SIZE(exynos5410_div_clks)); - samsung_clk_register_gate(ctx, exynos5410_gate_clks, - ARRAY_SIZE(exynos5410_gate_clks)); + if (!IS_ERR(xxti) && clk_get_rate(xxti) == 24 * MHZ) + exynos5410_plls[epll].rate_table = exynos5410_pll2550x_24mhz_tbl; - samsung_clk_of_add_provider(np, ctx); + samsung_cmu_register_one(np, &cmu); pr_debug("Exynos5410: clock setup completed.\n"); } diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index bb196ca..8c8b495 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -131,6 +131,9 @@ #define TOP_SPARE2 0x10b08 #define BPLL_LOCK 0x20010 #define BPLL_CON0 0x20110 +#define SRC_CDREX 0x20200 +#define DIV_CDREX0 0x20500 +#define DIV_CDREX1 0x20504 #define KPLL_LOCK 0x28000 #define KPLL_CON0 0x28100 #define SRC_KFC 0x28200 @@ -244,6 +247,9 @@ static const unsigned long exynos5x_clk_regs[] __initconst = { GATE_TOP_SCLK_FSYS, GATE_TOP_SCLK_PERIC, TOP_SPARE2, + SRC_CDREX, + DIV_CDREX0, + DIV_CDREX1, SRC_KFC, DIV_KFC0, }; @@ -448,6 +454,8 @@ PNAME(mout_maudio0_p) = {"fin_pll", "maudio_clk", "mout_sclk_dpll", "mout_sclk_epll", "mout_sclk_rpll"}; PNAME(mout_mau_epll_clk_p) = {"mout_sclk_epll", "mout_sclk_dpll", "mout_sclk_mpll", "mout_sclk_spll"}; +PNAME(mout_mclk_cdrex_p) = {"mout_bpll", "mout_mx_mspll_ccore"}; + /* List of parents specific to exynos5800 */ PNAME(mout_epll2_5800_p) = { "mout_sclk_epll", "ff_dout_epll2" }; PNAME(mout_group1_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll", @@ -465,6 +473,9 @@ PNAME(mout_group6_5800_p) = { "mout_sclk_ipll", "mout_sclk_dpll", PNAME(mout_group7_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll", "mout_sclk_mpll", "mout_sclk_spll", "mout_epll2", "mout_sclk_ipll" }; +PNAME(mout_mx_mspll_ccore_p) = {"sclk_bpll", "mout_sclk_dpll", + "mout_sclk_mpll", "ff_dout_spll2", + "mout_sclk_spll", "mout_sclk_epll"}; PNAME(mout_mau_epll_clk_5800_p) = { "mout_sclk_epll", "mout_sclk_dpll", "mout_sclk_mpll", "ff_dout_spll2" }; @@ -523,6 +534,8 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = { MUX(0, "mout_aclk300_disp1", mout_group5_5800_p, SRC_TOP2, 24, 2), MUX(0, "mout_aclk300_gscl", mout_group5_5800_p, SRC_TOP2, 28, 2), + MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", + mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2), MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, SRC_TOP7, 20, 2), MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1), @@ -601,6 +614,8 @@ static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { MUX(0, "mout_aclk300_disp1", mout_group1_p, SRC_TOP2, 24, 2), MUX(0, "mout_aclk300_gscl", mout_group1_p, SRC_TOP2, 28, 2), + MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", + mout_group5_5800_p, SRC_TOP7, 16, 2), MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2), MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1), @@ -744,6 +759,12 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = { MUX(0, "mout_fimd1_final", mout_fimd1_final_p, TOP_SPARE2, 8, 1), + /* CDREX block */ + MUX_F(CLK_MOUT_MCLK_CDREX, "mout_mclk_cdrex", mout_mclk_cdrex_p, + SRC_CDREX, 4, 1, CLK_SET_RATE_PARENT, 0), + MUX_F(CLK_MOUT_BPLL, "mout_bpll", mout_bpll_p, SRC_CDREX, 0, 1, + CLK_SET_RATE_PARENT, 0), + /* MAU Block */ MUX(CLK_MOUT_MAUDIO0, "mout_maudio0", mout_maudio0_p, SRC_MAU, 28, 3), @@ -836,6 +857,21 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(CLK_DOUT_ACLK400_DISP1, "dout_aclk400_disp1", "mout_aclk400_disp1", DIV_TOP2, 4, 3), + /* CDREX Block */ + DIV(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1", + DIV_CDREX0, 28, 3), + DIV_F(CLK_DOUT_SCLK_CDREX, "dout_sclk_cdrex", "mout_mclk_cdrex", + DIV_CDREX0, 24, 3, CLK_SET_RATE_PARENT, 0), + DIV(CLK_DOUT_ACLK_CDREX1, "dout_aclk_cdrex1", "dout_clk2x_phy0", + DIV_CDREX0, 16, 3), + DIV(CLK_DOUT_CCLK_DREX0, "dout_cclk_drex0", "dout_clk2x_phy0", + DIV_CDREX0, 8, 3), + DIV(CLK_DOUT_CLK2X_PHY0, "dout_clk2x_phy0", "dout_sclk_cdrex", + DIV_CDREX0, 3, 5), + + DIV(CLK_DOUT_PCLK_CORE_MEM, "dout_pclk_core_mem", "mout_mclk_cdrex", + DIV_CDREX1, 8, 3), + /* Audio Block */ DIV(0, "dout_maudio0", "mout_maudio0", DIV_MAU, 20, 4), DIV(0, "dout_maupcm0", "dout_maudio0", DIV_MAU, 24, 8), @@ -1364,6 +1400,7 @@ static void __init exynos5x_clk_init(struct device_node *np, if (_get_rate("fin_pll") == 24 * MHZ) { exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl; exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl; + exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl; } samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls), diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c index a57d01b..a80f3ef 100644 --- a/drivers/clk/samsung/clk-exynos5440.c +++ b/drivers/clk/samsung/clk-exynos5440.c @@ -112,6 +112,11 @@ static struct notifier_block exynos5440_clk_restart_handler = { .priority = 128, }; +static const struct samsung_pll_clock exynos5440_plls[] __initconst = { + PLL(pll_2550x, CLK_CPLLA, "cplla", "xtal", 0, 0x4c, NULL), + PLL(pll_2550x, CLK_CPLLB, "cpllb", "xtal", 0, 0x50, NULL), +}; + /* register exynos5440 clocks */ static void __init exynos5440_clk_init(struct device_node *np) { @@ -129,8 +134,8 @@ static void __init exynos5440_clk_init(struct device_node *np) samsung_clk_of_register_fixed_ext(ctx, exynos5440_fixed_rate_ext_clks, ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match); - samsung_clk_register_pll2550x("cplla", "xtal", reg_base + 0x1c, 0x10); - samsung_clk_register_pll2550x("cpllb", "xtal", reg_base + 0x20, 0x10); + samsung_clk_register_pll(ctx, exynos5440_plls, + ARRAY_SIZE(exynos5440_plls), ctx->reg_base); samsung_clk_register_fixed_rate(ctx, exynos5440_fixed_rate_clks, ARRAY_SIZE(exynos5440_fixed_rate_clks)); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 48139bd..9617825 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -890,22 +890,14 @@ static const struct clk_ops samsung_s3c2440_mpll_clk_ops = { #define PLL2550X_M_SHIFT (4) #define PLL2550X_S_SHIFT (0) -struct samsung_clk_pll2550x { - struct clk_hw hw; - const void __iomem *reg_base; - unsigned long offset; -}; - -#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw) - static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 r, p, m, s, pll_stat; u64 fvco = parent_rate; - pll_stat = readl_relaxed(pll->reg_base + pll->offset * 3); + pll_stat = readl_relaxed(pll->con_reg); r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK; if (!r) return 0; @@ -923,43 +915,6 @@ static const struct clk_ops samsung_pll2550x_clk_ops = { .recalc_rate = samsung_pll2550x_recalc_rate, }; -struct clk * __init samsung_clk_register_pll2550x(const char *name, - const char *pname, const void __iomem *reg_base, - const unsigned long offset) -{ - struct samsung_clk_pll2550x *pll; - struct clk *clk; - struct clk_init_data init; - - pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) { - pr_err("%s: could not allocate pll clk %s\n", __func__, name); - return NULL; - } - - init.name = name; - init.ops = &samsung_pll2550x_clk_ops; - init.flags = CLK_GET_RATE_NOCACHE; - init.parent_names = &pname; - init.num_parents = 1; - - pll->hw.init = &init; - pll->reg_base = reg_base; - pll->offset = offset; - - clk = clk_register(NULL, &pll->hw); - if (IS_ERR(clk)) { - pr_err("%s: failed to register pll clock %s\n", __func__, - name); - kfree(pll); - } - - if (clk_register_clkdev(clk, name, NULL)) - pr_err("%s: failed to register lookup for %s", __func__, name); - - return clk; -} - /* * PLL2550xx Clock Type */ @@ -1063,6 +1018,102 @@ static const struct clk_ops samsung_pll2550xx_clk_min_ops = { }; /* + * PLL2650x Clock Type + */ + +/* Maximum lock time can be 3000 * PDIV cycles */ +#define PLL2650X_LOCK_FACTOR 3000 + +#define PLL2650X_M_MASK 0x1ff +#define PLL2650X_P_MASK 0x3f +#define PLL2650X_S_MASK 0x7 +#define PLL2650X_K_MASK 0xffff +#define PLL2650X_LOCK_STAT_MASK 0x1 +#define PLL2650X_M_SHIFT 16 +#define PLL2650X_P_SHIFT 8 +#define PLL2650X_S_SHIFT 0 +#define PLL2650X_K_SHIFT 0 +#define PLL2650X_LOCK_STAT_SHIFT 29 +#define PLL2650X_PLL_ENABLE_SHIFT 31 + +static unsigned long samsung_pll2650x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u64 fout = parent_rate; + u32 mdiv, pdiv, sdiv, pll_con0, pll_con1; + s16 kdiv; + + pll_con0 = readl_relaxed(pll->con_reg); + mdiv = (pll_con0 >> PLL2650X_M_SHIFT) & PLL2650X_M_MASK; + pdiv = (pll_con0 >> PLL2650X_P_SHIFT) & PLL2650X_P_MASK; + sdiv = (pll_con0 >> PLL2650X_S_SHIFT) & PLL2650X_S_MASK; + + pll_con1 = readl_relaxed(pll->con_reg + 4); + kdiv = (s16)((pll_con1 >> PLL2650X_K_SHIFT) & PLL2650X_K_MASK); + + fout *= (mdiv << 16) + kdiv; + do_div(fout, (pdiv << sdiv)); + fout >>= 16; + + return (unsigned long)fout; +} + +static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 con0, con1; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + + con0 = readl_relaxed(pll->con_reg); + con1 = readl_relaxed(pll->con_reg + 4); + + /* Set PLL lock time. */ + writel_relaxed(rate->pdiv * PLL2650X_LOCK_FACTOR, pll->lock_reg); + + /* Change PLL PMS values */ + con0 &= ~((PLL2650X_M_MASK << PLL2650X_M_SHIFT) | + (PLL2650X_P_MASK << PLL2650X_P_SHIFT) | + (PLL2650X_S_MASK << PLL2650X_S_SHIFT)); + con0 |= (rate->mdiv << PLL2650X_M_SHIFT) | + (rate->pdiv << PLL2650X_P_SHIFT) | + (rate->sdiv << PLL2650X_S_SHIFT); + con0 |= (1 << PLL2650X_PLL_ENABLE_SHIFT); + writel_relaxed(con0, pll->con_reg); + + con1 &= ~(PLL2650X_K_MASK << PLL2650X_K_SHIFT); + con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT); + writel_relaxed(con1, pll->con_reg + 4); + + do { + cpu_relax(); + con0 = readl_relaxed(pll->con_reg); + } while (!(con0 & (PLL2650X_LOCK_STAT_MASK + << PLL2650X_LOCK_STAT_SHIFT))); + + return 0; +} + +static const struct clk_ops samsung_pll2650x_clk_ops = { + .recalc_rate = samsung_pll2650x_recalc_rate, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_pll2650x_set_rate, +}; + +static const struct clk_ops samsung_pll2650x_clk_min_ops = { + .recalc_rate = samsung_pll2650x_recalc_rate, +}; + +/* * PLL2650XX Clock Type */ @@ -1263,12 +1314,21 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, else init.ops = &samsung_s3c2440_mpll_clk_ops; break; + case pll_2550x: + init.ops = &samsung_pll2550x_clk_ops; + break; case pll_2550xx: if (!pll->rate_table) init.ops = &samsung_pll2550xx_clk_min_ops; else init.ops = &samsung_pll2550xx_clk_ops; break; + case pll_2650x: + if (!pll->rate_table) + init.ops = &samsung_pll2650x_clk_min_ops; + else + init.ops = &samsung_pll2650x_clk_ops; + break; case pll_2650xx: if (!pll->rate_table) init.ops = &samsung_pll2650xx_clk_min_ops; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 213de9a..a1ca023 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -31,7 +31,9 @@ enum samsung_pll_type { pll_s3c2410_mpll, pll_s3c2410_upll, pll_s3c2440_mpll, + pll_2550x, pll_2550xx, + pll_2650x, pll_2650xx, pll_1450x, pll_1451x, |