From efc4204cf7b0792374676219fefc0651a9ca1e27 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Tue, 2 Aug 2016 15:22:26 +0800 Subject: clk: rockchip: add 65MHz and 106.5MHz rates to rk3399 plls used for HDMI We need to add more clocks for supporting more display resolution for HDMI. Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index c109d80..e4ca8a9 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -100,8 +100,10 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { RK3036_PLL_RATE( 297000000, 1, 99, 4, 2, 1, 0), RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0), RK3036_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0), + RK3036_PLL_RATE( 106500000, 1, 71, 4, 4, 1, 0), RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0), RK3036_PLL_RATE( 74250000, 2, 99, 4, 4, 1, 0), + RK3036_PLL_RATE( 65000000, 1, 65, 6, 4, 1, 0), RK3036_PLL_RATE( 54000000, 1, 54, 6, 4, 1, 0), RK3036_PLL_RATE( 27000000, 1, 27, 6, 4, 1, 0), { /* sentinel */ }, -- cgit v0.10.2 From 4f4e0491670a2bc41887dc2c06782fa39e665d5c Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Tue, 2 Aug 2016 15:22:49 +0800 Subject: clk: rockchip: delete the CLK_IGNORE_UNUSED from aclk_pcie on rk3399 allow aclk_pcie and aclk_perf_pcie disabled when unused. Signed-off-by: Elaine Zhang Signed-off-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index e4ca8a9..b173711a 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -848,9 +848,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(14), 12, 2, DFLAGS, RK3399_CLKGATE_CON(5), 4, GFLAGS), - GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", CLK_IGNORE_UNUSED, + GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", 0, RK3399_CLKGATE_CON(20), 2, GFLAGS), - GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", CLK_IGNORE_UNUSED, + GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", 0, RK3399_CLKGATE_CON(20), 10, GFLAGS), GATE(0, "aclk_perihp_noc", "aclk_perihp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(20), 12, GFLAGS), -- cgit v0.10.2 From e6cebc7273d54259362c7e44a4134d829f38ac59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Fri, 29 Jul 2016 15:56:55 +0800 Subject: clk: rockchip: use general clock flag when registering pll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the general flags the pll list already contains to the clock init, so that needed clock flags can be used for plls. Signed-off-by: Heiko Stübner diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index db81e45..9c1373e 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -837,7 +837,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, u8 num_parents, int con_offset, int grf_lock_offset, int lock_shift, int mode_offset, int mode_shift, struct rockchip_pll_rate_table *rate_table, - u8 clk_pll_flags) + unsigned long flags, u8 clk_pll_flags) { const char *pll_parents[3]; struct clk_init_data init; @@ -892,7 +892,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, init.name = pll_name; /* keep all plls untouched for now */ - init.flags = CLK_IGNORE_UNUSED; + init.flags = flags | CLK_IGNORE_UNUSED; init.parent_names = &parent_names[0]; init.num_parents = 1; diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 7ffd134..1f1c74f 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -385,7 +385,7 @@ void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, list->con_offset, grf_lock_offset, list->lock_shift, list->mode_offset, list->mode_shift, list->rate_table, - list->pll_flags); + list->flags, list->pll_flags); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, list->name); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 2194ffa..3747de5 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -238,7 +238,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, u8 num_parents, int con_offset, int grf_lock_offset, int lock_shift, int mode_offset, int mode_shift, struct rockchip_pll_rate_table *rate_table, - u8 clk_pll_flags); + unsigned long flags, u8 clk_pll_flags); struct rockchip_cpuclk_clksel { int reg; -- cgit v0.10.2 From 178ca5312ad358fb129876bacbee8dac4681673a Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 26 Jul 2016 15:04:25 +0800 Subject: clk: sunxi-ng: mux: Increase fixed pre-divider div size Some clocks have a predivider value that is larger than what u8 can store. One such example is the OUT clk found on A20/A31, which has a /750 pre-divider on one of the osc24M parents. Increase the size of the div field to u16. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 58fc36e..1329b9a 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -18,7 +18,7 @@ void ccu_mux_helper_adjust_parent_for_prediv(struct ccu_common *common, int parent_index, unsigned long *parent_rate) { - u8 prediv = 1; + u16 prediv = 1; u32 reg; if (!((common->features & CCU_FEATURE_FIXED_PREDIV) || diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index 9450826..d35ce5e 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -11,7 +11,7 @@ struct ccu_mux_internal { struct { u8 index; - u8 div; + u16 div; } fixed_prediv; struct { -- cgit v0.10.2 From a36583595c1769cad9aad393ffe5a27d217f734f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 26 Jul 2016 15:04:28 +0800 Subject: clk: sunxi-ng: nkm: Add mux to support multiple parents The MIPI mode of the MIPI-PLL on A31 is an NKM-style PLL with 2 selectable parents. Add mux support to the NKM clock. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index 2071822..1824529 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -93,19 +93,30 @@ static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw, return parent_rate * (n + 1) * (k + 1) / (m + 1); } -static long ccu_nkm_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux, + unsigned long parent_rate, + unsigned long rate, + void *data) { - struct ccu_nkm *nkm = hw_to_ccu_nkm(hw); + struct ccu_nkm *nkm = data; struct _ccu_nkm _nkm; _nkm.max_n = 1 << nkm->n.width; _nkm.max_k = 1 << nkm->k.width; _nkm.max_m = 1 << nkm->m.width; - ccu_nkm_find_best(*parent_rate, rate, &_nkm); + ccu_nkm_find_best(parent_rate, rate, &_nkm); - return *parent_rate * _nkm.n * _nkm.k / _nkm.m; + return parent_rate * _nkm.n * _nkm.k / _nkm.m; +} + +static int ccu_nkm_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct ccu_nkm *nkm = hw_to_ccu_nkm(hw); + + return ccu_mux_helper_determine_rate(&nkm->common, &nkm->mux, + req, ccu_nkm_round_rate, nkm); } static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate, @@ -142,12 +153,29 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static u8 ccu_nkm_get_parent(struct clk_hw *hw) +{ + struct ccu_nkm *nkm = hw_to_ccu_nkm(hw); + + return ccu_mux_helper_get_parent(&nkm->common, &nkm->mux); +} + +static int ccu_nkm_set_parent(struct clk_hw *hw, u8 index) +{ + struct ccu_nkm *nkm = hw_to_ccu_nkm(hw); + + return ccu_mux_helper_set_parent(&nkm->common, &nkm->mux, index); +} + const struct clk_ops ccu_nkm_ops = { .disable = ccu_nkm_disable, .enable = ccu_nkm_enable, .is_enabled = ccu_nkm_is_enabled, + .get_parent = ccu_nkm_get_parent, + .set_parent = ccu_nkm_set_parent, + + .determine_rate = ccu_nkm_determine_rate, .recalc_rate = ccu_nkm_recalc_rate, - .round_rate = ccu_nkm_round_rate, .set_rate = ccu_nkm_set_rate, }; diff --git a/drivers/clk/sunxi-ng/ccu_nkm.h b/drivers/clk/sunxi-ng/ccu_nkm.h index 1936ac1..fcb152f 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.h +++ b/drivers/clk/sunxi-ng/ccu_nkm.h @@ -32,10 +32,33 @@ struct ccu_nkm { struct _ccu_mult n; struct _ccu_mult k; struct _ccu_div m; + struct ccu_mux_internal mux; struct ccu_common common; }; +#define SUNXI_CCU_NKM_WITH_MUX_GATE_LOCK(_struct, _name, _parents, _reg, \ + _nshift, _nwidth, \ + _kshift, _kwidth, \ + _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _lock, _flags) \ + struct ccu_nkm _struct = { \ + .enable = _gate, \ + .lock = _lock, \ + .k = _SUNXI_CCU_MULT(_kshift, _kwidth), \ + .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \ + .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_nkm_ops, \ + _flags), \ + }, \ + } + #define SUNXI_CCU_NKM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \ _nshift, _nwidth, \ _kshift, _kwidth, \ -- cgit v0.10.2 From 2570d4005d475818711c96e83fb84d5048ab8e1b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 27 Jun 2016 16:48:07 +0200 Subject: clk: renesas: r8a7796: Add watchdog core clocks Add all core clocks related to the Watchdog Timer (WDT) controller on the Renesas R-Car M3-W (r8a7796) SoC: OSC, Internal RCLK, and RCLK. Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index c84b549..ea9ed38 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -45,6 +45,7 @@ enum clk_ids { CLK_S3, CLK_SDSRC, CLK_SSPSRC, + CLK_RINT, /* Module Clocks */ MOD_CLK_BASE @@ -94,6 +95,11 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1), DEF_FIXED("cp", R8A7796_CLK_CP, CLK_EXTAL, 2, 1), + + DEF_DIV6_RO("osc", R8A7796_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8), + DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32), + + DEF_BASE("r", R8A7796_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT), }; static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { -- cgit v0.10.2 From b51d5275016c6edbf4656eaee30d836fef127016 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 27 Jun 2016 16:51:14 +0200 Subject: clk: renesas: r8a7796: Add watchdog module clock Add the module clock for the Watchdog Timer (WDT) controller on the Renesas R-Car M3-W (r8a7796) SoC. Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index ea9ed38..c0dee76 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -104,6 +104,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("scif2", 310, R8A7796_CLK_S3D4), + DEF_MOD("rwdt0", 402, R8A7796_CLK_R), DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1), }; -- cgit v0.10.2 From 54479449c801e46ee2b6ba08e2f19cd810f74f94 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Tue, 9 Aug 2016 11:02:33 -0700 Subject: clk: rockchip: mark rk3399 hdcp_noc and vio_noc as critical The aclk_vio_noc should be put into critical list, as the interconnect is not handled right now, but is required by VOP. And the Type-C DP need these clocks: aclk_hdcp_noc, hclk_hdcp_noc, pclk_hdcp_noc. Mark them as critical to avoid someone close them. Signed-off-by: Chris Zhong Reviewed-by: Guenter Roeck Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index b173711a..6f3d0a6 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -1470,6 +1470,9 @@ static const char *const rk3399_cru_critical_clocks[] __initconst = { "aclk_cci_pre", "aclk_gic", "aclk_gic_noc", + "aclk_hdcp_noc", + "hclk_hdcp_noc", + "pclk_hdcp_noc", "pclk_perilp0", "pclk_perilp0", "hclk_perilp0", @@ -1489,6 +1492,7 @@ static const char *const rk3399_cru_critical_clocks[] __initconst = { "gpll_hclk_perilp1_src", "gpll_aclk_perilp0_src", "gpll_aclk_perihp_src", + "aclk_vio_noc", }; static const char *const rk3399_pmucru_critical_clocks[] __initconst = { -- cgit v0.10.2 From 904e6ead02dcb409cb6eb5ec1c31dc2c7c28b5df Mon Sep 17 00:00:00 2001 From: Michael Turquette Date: Fri, 8 Jul 2016 16:32:10 -0700 Subject: clk: migrate ref counts when orphans are reunited It's always nice to see families reunited, and this is equally true when talking about parent clocks and their children. However, if the orphan clk had a positive prepare_count or enable_count, then we would not migrate those counts up the parent chain correctly. This has manifested with the recent critical clocks feature, which often enables clocks very early, before their parents have been registered. Fixed by replacing the call to clk_core_reparent with calls to __clk_set_parent_{before,after}. Cc: James Liao Cc: Erin Lo Signed-off-by: Michael Turquette [sboyd@codeaurora.org: Recalc accuracies and rates too] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 820a939..238b989 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2449,8 +2449,16 @@ static int __clk_core_init(struct clk_core *core) hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { struct clk_core *parent = __clk_init_parent(orphan); - if (parent) - clk_core_reparent(orphan, parent); + /* + * we could call __clk_set_parent, but that would result in a + * redundant call to the .set_rate op, if it exists + */ + if (parent) { + __clk_set_parent_before(orphan, parent); + __clk_set_parent_after(orphan, parent, NULL); + __clk_recalc_accuracies(orphan); + __clk_recalc_rates(orphan, 0); + } } /* -- cgit v0.10.2 From 22d61acffbbe344464b8d56d822c4fe86360e599 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 10 Aug 2016 15:32:53 -0700 Subject: MAINTAINERS: Add linux-clk patchwork URL The common clk framework has a patchwork associated with it. Update the maintainers file to reflect this. Cc: Michael Turquette Signed-off-by: Stephen Boyd diff --git a/MAINTAINERS b/MAINTAINERS index 20bb1d0..5436d3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3150,6 +3150,7 @@ COMMON CLK FRAMEWORK M: Michael Turquette M: Stephen Boyd L: linux-clk@vger.kernel.org +Q: http://patchwork.kernel.org/project/linux-clk/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git S: Maintained F: Documentation/devicetree/bindings/clock/ -- cgit v0.10.2 From 1fd92dbaabe3096ded391eed2e8dd74afe02d0d2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 15 Jul 2016 10:53:02 -0300 Subject: clk: imx7d: do not set the parent of IMX7D_ENET_AXI_ROOT_SRC Booting the kernel on a imx7s-warp leads to several warnings like these: [ 0.000000] ------------[ cut here ]------------ [ 0.000000] WARNING: CPU: 0 PID: 0 at kernel/locking/lockdep.c:3536 lock_release+0x2f8/0x330 [ 0.000000] releasing a pinned lock [ 0.000000] ------------[ cut here ]------------ [ 0.000000] WARNING: CPU: 0 PID: 0 at kernel/locking/lockdep.c:2722 trace_hardirqs_on_caller+0x1ac/0x1f4 [ 0.000000] DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled)) [ 0.000000] ---[ end trace cb88537fdc8fa201 ]--- [ 0.000000] bad: scheduling from the idle thread! [ 0.000000] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 4.7.0-rc7-next-20160715 #404 [ 0.000000] ------------[ cut here ]------------ [ 0.000000] WARNING: CPU: 0 PID: 0 at kernel/time/sched_clock.c:179 sched_clock_register+0x44/0x1f8 [ 0.000000] Modules linked in: [ 0.000591] ------------[ cut here ]------------ [ 0.000610] WARNING: CPU: 0 PID: 0 at kernel/time/sched_clock.c:179 sched_clock_register+0x44/0x1f8 [ 0.002084] ------------[ cut here ]------------ [ 0.002104] WARNING: CPU: 0 PID: 0 at init/main.c:576 start_kernel+0x258/0x3b0 [ 0.002114] Interrupts were enabled early This fix is along the same lines as 5e33ebff7edd ("clk: imx7d: do not set parent of ethernet time/ref clocks") and the explanation from that commit is: "The reason for the warning is that setting the parent enables the ENET PLL since we are using CLK_OPS_PARENT_ENABLE. Enabling the ENET PLL can cause clk_pllv3_wait_lock to sleep. See also: commit fc8726a2c021 ("clk: core: support clocks which requires parents enable (part 2)")." imx7s-warp does not even use the FEC interface, so we should not really configure the parent of IMX7D_ENET_AXI_ROOT_SRC in the common MX7 clock driver code. The dts file should use the assigned-clocks/assigned-clock-parents method, so simply remove the configuration of IMX7D_ENET_AXI_ROOT_SRC parent. Signed-off-by: Fabio Estevam Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 6ed4f8f..9257972 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -860,8 +860,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */ clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); - clk_set_parent(clks[IMX7D_ENET_AXI_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_250M_CLK]); - /* set uart module clock's parent clock source that must be great then 80MHz */ clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); -- cgit v0.10.2 From 2cf9a57811bddb6fa6b0f8d7376da164d5534813 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 12 Aug 2016 14:37:54 +0200 Subject: clk: divider: Fix clk_divider_round_rate() to use clk_readl() clk-divider uses clk_readl()/clk_writel() everywhere, except in clk_divider_round_rate(), where plain readl() is used. Change this to clk_readl(), as it makes a difference on powerpc. Fixes: e6d5e7d90be92cee ("clk-divider: Fix READ_ONLY when divider > 1") Signed-off-by: Geert Uytterhoeven Reviewed-by: James Hogan Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index a0f55bc..96386ff 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -352,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { - bestdiv = readl(divider->reg) >> divider->shift; + bestdiv = clk_readl(divider->reg) >> divider->shift; bestdiv &= div_mask(divider->width); bestdiv = _get_div(divider->table, bestdiv, divider->flags, divider->width); -- cgit v0.10.2 From c7296c51ce5d9aec3ae9fa36b3096983c35bd279 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:25 +0200 Subject: clk: core: New macro CLK_OF_DECLARE_DRIVER This will be used by drivers that requires initialization at of_clk_init() time and also during platform device probing. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Stephen Boyd diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index a39c0c5..f403b8a 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -780,6 +780,18 @@ extern struct of_device_id __clk_of_table; #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn) +/* + * Use this macro when you have a driver that requires two initialization + * routines, one at of_clk_init(), and one at platform device probe + */ +#define CLK_OF_DECLARE_DRIVER(name, compat, fn) \ + static void name##_of_clk_init_driver(struct device_node *np) \ + { \ + of_node_clear_flag(np, OF_POPULATED); \ + fn(np); \ + } \ + OF_DECLARE_1(clk, name, compat, name##_of_clk_init_driver) + #ifdef CONFIG_OF int of_clk_add_provider(struct device_node *np, struct clk *(*clk_src_get)(struct of_phandle_args *args, -- cgit v0.10.2 From aa8d7122609dbd6e18ce270e94b9880a7c97cc9b Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:26 +0200 Subject: clk: axis: Use new macro CLK_OF_DECLARE_DRIVER This driver initializes a clock provider via of_artpec6_clkctrl_setup and then continues the initialization on artpec6_clkctrl_probe. Use the new macro to notify the clk subsystem about this behaviour. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Stephen Boyd diff --git a/drivers/clk/axis/clk-artpec6.c b/drivers/clk/axis/clk-artpec6.c index ffc988b..da1a073 100644 --- a/drivers/clk/axis/clk-artpec6.c +++ b/drivers/clk/axis/clk-artpec6.c @@ -113,8 +113,8 @@ static void of_artpec6_clkctrl_setup(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data); } -CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl", - of_artpec6_clkctrl_setup); +CLK_OF_DECLARE_DRIVER(artpec6_clkctrl, "axis,artpec6-clkctrl", + of_artpec6_clkctrl_setup); static int artpec6_clkctrl_probe(struct platform_device *pdev) { -- cgit v0.10.2 From 9a0c42d216a6abef3b3637f9ceaac26e5f50a6a0 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:27 +0200 Subject: clk: nxp: Use new macro CLK_OF_DECLARE_DRIVER This driver initializes a clock provider via lpc18xx_creg_clk_init and then continues the initialization on lpc18xx_creg_clk_probe. Use the new macro to notify the clk subsystem about this behaviour. Signed-off-by: Ricardo Ribalda Delgado [sboyd@codeaurora.org: s/npx/nxp/ in subject] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/nxp/clk-lpc18xx-creg.c b/drivers/clk/nxp/clk-lpc18xx-creg.c index 9e35749..c6e802e 100644 --- a/drivers/clk/nxp/clk-lpc18xx-creg.c +++ b/drivers/clk/nxp/clk-lpc18xx-creg.c @@ -184,7 +184,8 @@ static void __init lpc18xx_creg_clk_init(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, &clk_creg_early_data); } -CLK_OF_DECLARE(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk", lpc18xx_creg_clk_init); +CLK_OF_DECLARE_DRIVER(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk", + lpc18xx_creg_clk_init); static struct clk *clk_creg[CREG_CLK_MAX]; static struct clk_onecell_data clk_creg_data = { -- cgit v0.10.2 From cb1291c3fdf0c3ffe3eba92a52e6c5362f2aaf6e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:28 +0200 Subject: clk: sunxi: mod0: Use new macro CLK_OF_DECLARE_DRIVER This driver initializes a clock provider via sun4i_a10_mod0_setup and then continues the initialization on sun4i_a10_mod0_clk_probe. Use the new macro to notify the clk subsystem about this behaviour. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index b38d71c..e54266c 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c @@ -91,7 +91,8 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node) sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock, reg); } -CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup); +CLK_OF_DECLARE_DRIVER(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", + sun4i_a10_mod0_setup); static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev) { -- cgit v0.10.2 From 915128b621a05c63fa58ca9e4cbdf394bbe592f3 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:30 +0200 Subject: clk: sunxi: apb0: Use new macro CLK_OF_DECLARE_DRIVER This driver initializes a clock provider via sun8i_a23_apb0_setup and then continues the initialization on sun8i_a23_apb0_clk_probe. Use the new macro to notify the clk subsystem about this behaviour. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index a5666e1..ea1eed2 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c @@ -82,8 +82,8 @@ err_unmap: of_address_to_resource(node, 0, &res); release_mem_region(res.start, resource_size(&res)); } -CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk", - sun8i_a23_apb0_setup); +CLK_OF_DECLARE_DRIVER(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk", + sun8i_a23_apb0_setup); static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) { -- cgit v0.10.2 From 989eafd0b6091c15a0929ea5f520ff926ccaaa25 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:32 +0200 Subject: clk: core: Avoid double initialization of clocks Some clock providers can be initialized via of_clk_init() and also via platform device probe. Avoid double initialization of them by setting the OF_POPULATED flag. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 238b989..0c6009a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3459,6 +3459,10 @@ void __init of_clk_init(const struct of_device_id *matches) &clk_provider_list, node) { if (force || parent_ready(clk_provider->np)) { + /* Don't populate platform devices */ + of_node_set_flag(clk_provider->np, + OF_POPULATED); + clk_provider->clk_init_cb(clk_provider->np); of_clk_set_defaults(clk_provider->np, true); -- cgit v0.10.2 From 971451b3b15dc6104fad79fbe55ea3995ea9911f Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:33 +0200 Subject: clk: fixed-factor: Convert into a module platform driver Adds support for fixed-factor clock providers which have not been enabled via of_clk_init(). This is required by Device trees overlays that introduce clocks providers. Signed-off-by: Ricardo Ribalda Delgado [sboyd@codeaurora.org: Make new private function static, don't check clk for NULL when unregistering in driver remove] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 4db3be2..070d0d7 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * DOC: basic fixed multiplier and divider clock that cannot gate @@ -147,27 +148,25 @@ static const struct of_device_id set_rate_parent_matches[] = { { /* Sentinel */ }, }; -/** - * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock - */ -void __init of_fixed_factor_clk_setup(struct device_node *node) +static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) { struct clk *clk; const char *clk_name = node->name; const char *parent_name; unsigned long flags = 0; u32 div, mult; + int ret; if (of_property_read_u32(node, "clock-div", &div)) { pr_err("%s Fixed factor clock <%s> must have a clock-div property\n", __func__, node->name); - return; + return ERR_PTR(-EIO); } if (of_property_read_u32(node, "clock-mult", &mult)) { pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n", __func__, node->name); - return; + return ERR_PTR(-EIO); } of_property_read_string(node, "clock-output-names", &clk_name); @@ -178,10 +177,68 @@ void __init of_fixed_factor_clk_setup(struct device_node *node) clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, mult, div); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (IS_ERR(clk)) + return clk; + + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (ret) { + clk_unregister(clk); + return ERR_PTR(ret); + } + + return clk; +} + +/** + * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock + */ +void __init of_fixed_factor_clk_setup(struct device_node *node) +{ + _of_fixed_factor_clk_setup(node); } EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup); CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock", of_fixed_factor_clk_setup); + +static int of_fixed_factor_clk_remove(struct platform_device *pdev) +{ + struct clk *clk = platform_get_drvdata(pdev); + + clk_unregister_fixed_factor(clk); + + return 0; +} + +static int of_fixed_factor_clk_probe(struct platform_device *pdev) +{ + struct clk *clk; + + /* + * This function is not executed when of_fixed_factor_clk_setup + * succeeded. + */ + clk = _of_fixed_factor_clk_setup(pdev->dev.of_node); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + platform_set_drvdata(pdev, clk); + + return 0; +} + +static const struct of_device_id of_fixed_factor_clk_ids[] = { + { .compatible = "fixed-factor-clock" }, + { } +}; +MODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids); + +static struct platform_driver of_fixed_factor_clk_driver = { + .driver = { + .name = "of_fixed_factor_clk", + .of_match_table = of_fixed_factor_clk_ids, + }, + .probe = of_fixed_factor_clk_probe, + .remove = of_fixed_factor_clk_remove, +}; +builtin_platform_driver(of_fixed_factor_clk_driver); #endif -- cgit v0.10.2 From 435779fe133626b4e364b320ebc00aac8a0e6047 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 5 Jul 2016 18:23:34 +0200 Subject: clk: fixed-rate: Convert into a module platform driver Adds support for fixed-rate clock providers which have not been enabled via of_clk_init(). This is required by Device trees overlays that introduce clocks providers. Signed-off-by: Ricardo Ribalda Delgado [sboyd@codeaurora.org: Make new private function static, don't check clk for NULL when unregistering in driver remove] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 2edb393..c735272 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -15,6 +15,7 @@ #include #include #include +#include /* * DOC: basic fixed-rate clock that cannot gate @@ -157,18 +158,16 @@ void clk_hw_unregister_fixed_rate(struct clk_hw *hw) EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate); #ifdef CONFIG_OF -/** - * of_fixed_clk_setup() - Setup function for simple fixed rate clock - */ -void of_fixed_clk_setup(struct device_node *node) +static struct clk *_of_fixed_clk_setup(struct device_node *node) { struct clk *clk; const char *clk_name = node->name; u32 rate; u32 accuracy = 0; + int ret; if (of_property_read_u32(node, "clock-frequency", &rate)) - return; + return ERR_PTR(-EIO); of_property_read_u32(node, "clock-accuracy", &accuracy); @@ -176,9 +175,67 @@ void of_fixed_clk_setup(struct device_node *node) clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL, 0, rate, accuracy); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (IS_ERR(clk)) + return clk; + + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (ret) { + clk_unregister(clk); + return ERR_PTR(ret); + } + + return clk; +} + +/** + * of_fixed_clk_setup() - Setup function for simple fixed rate clock + */ +void of_fixed_clk_setup(struct device_node *node) +{ + _of_fixed_clk_setup(node); } EXPORT_SYMBOL_GPL(of_fixed_clk_setup); CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); + +static int of_fixed_clk_remove(struct platform_device *pdev) +{ + struct clk *clk = platform_get_drvdata(pdev); + + clk_unregister_fixed_rate(clk); + + return 0; +} + +static int of_fixed_clk_probe(struct platform_device *pdev) +{ + struct clk *clk; + + /* + * This function is not executed when of_fixed_clk_setup + * succeeded. + */ + clk = _of_fixed_clk_setup(pdev->dev.of_node); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + platform_set_drvdata(pdev, clk); + + return 0; +} + +static const struct of_device_id of_fixed_clk_ids[] = { + { .compatible = "fixed-clock" }, + { } +}; +MODULE_DEVICE_TABLE(of, of_fixed_clk_ids); + +static struct platform_driver of_fixed_clk_driver = { + .driver = { + .name = "of_fixed_clk", + .of_match_table = of_fixed_clk_ids, + }, + .probe = of_fixed_clk_probe, + .remove = of_fixed_clk_remove, +}; +builtin_platform_driver(of_fixed_clk_driver); #endif -- cgit v0.10.2 From 8a23133c7a2afc49d97b5b27caefe6847d32599e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 19 Jul 2016 16:28:47 +0900 Subject: clk: use ERR_CAST() for __clk_create_clk() This code is clear enough, but the intention will be even clearer with this. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0c6009a..6298715 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2499,7 +2499,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, /* This is to allow this function to be chained to others */ if (IS_ERR_OR_NULL(hw)) - return (struct clk *) hw; + return ERR_CAST(hw); clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) -- cgit v0.10.2 From 7752f09cb1e8c4af2910e4fb0220c44ae9ea749e Mon Sep 17 00:00:00 2001 From: Grzegorz Jaszczyk Date: Thu, 21 Jul 2016 12:48:10 +0200 Subject: clk: mvebu: armada-39x: add clk description for supported interfaces Both SATA and second USB3.0 interface are supported in Armada-39x SoC family. Add necessary clk description, so both xhci and sata drivers can be correctly initialized. The binding documentation has also been updated accordingly. Signed-off-by: Grzegorz Jaszczyk Acked-by: Rob Herring Reviewed-by: Thomas Petazzoni Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt index 660e649..cb8542d 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt @@ -86,6 +86,8 @@ ID Clock Peripheral 7 pex3 PCIe 3 8 pex0 PCIe 0 9 usb3h0 USB3 Host 0 +10 usb3h1 USB3 Host 1 +15 sata0 SATA 0 17 sdio SDIO 22 xor0 XOR 0 28 xor1 XOR 1 diff --git a/drivers/clk/mvebu/armada-39x.c b/drivers/clk/mvebu/armada-39x.c index efb974d..4fdfd32 100644 --- a/drivers/clk/mvebu/armada-39x.c +++ b/drivers/clk/mvebu/armada-39x.c @@ -142,6 +142,8 @@ static const struct clk_gating_soc_desc armada_39x_gating_desc[] __initconst = { { "pex3", NULL, 7 }, { "pex0", NULL, 8 }, { "usb3h0", NULL, 9 }, + { "usb3h1", NULL, 10 }, + { "sata0", NULL, 15 }, { "sdio", NULL, 17 }, { "xor0", NULL, 22 }, { "xor1", NULL, 28 }, -- cgit v0.10.2 From 225ff4e87ab2ceca4d4db05a5930a8c7ad16d754 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 May 2016 11:55:09 +0300 Subject: clk: twl6040: Correct clk_ops Since the drover only supports prepare callbacks, the use of is_enabled is not correct, it should be handling is_prepared. Signed-off-by: Peter Ujfalusi Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 697c667..e167e0b 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -34,7 +34,7 @@ struct twl6040_clk { int enabled; }; -static int twl6040_bitclk_is_enabled(struct clk_hw *hw) +static int twl6040_bitclk_is_prepared(struct clk_hw *hw) { struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, mcpdm_fclk); @@ -66,7 +66,7 @@ static void twl6040_bitclk_unprepare(struct clk_hw *hw) } static const struct clk_ops twl6040_mcpdm_ops = { - .is_enabled = twl6040_bitclk_is_enabled, + .is_prepared = twl6040_bitclk_is_prepared, .prepare = twl6040_bitclk_prepare, .unprepare = twl6040_bitclk_unprepare, }; -- cgit v0.10.2 From 994deaae37a05bfe59aded7bb176092fb849c5b4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 May 2016 11:55:10 +0300 Subject: clk: twl6040: Register the clock as of_clk_provider In order ot be able to use the pdmclk clock via DT it need to be registered as of_clk_provide. Since the twl6040 clock driver does not have it's own DT node, use the parent's node for registering. Signed-off-by: Peter Ujfalusi Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index e167e0b..6a2dbe6 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -95,7 +95,8 @@ static int twl6040_clk_probe(struct platform_device *pdev) platform_set_drvdata(pdev, clkdata); - return 0; + return of_clk_add_provider(pdev->dev.parent->of_node, + of_clk_src_simple_get, clkdata->clk); } static struct platform_driver twl6040_clk_driver = { -- cgit v0.10.2 From 7e37deb7fae8437c0487d9fc3f13c7415770efd7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 May 2016 11:55:11 +0300 Subject: clk: twl6040: Rename the driver and use consistent names in the code The driver is to provide the functional clock to OMAP4/5 McPDM. The clock is named as pdmclk in the documentations so change the function names, structure names and variables to align with this. At the same time rename the driver from "twl6040-clk" to "twl6040-pdmclk". This can be done w/o regression since the clock driver is not in use at the moment, the MFD core driver is not even registering the device for it. Signed-off-by: Peter Ujfalusi Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 6a2dbe6..c98b1ec 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -26,60 +26,73 @@ #include #include -struct twl6040_clk { +struct twl6040_pdmclk { struct twl6040 *twl6040; struct device *dev; - struct clk_hw mcpdm_fclk; + struct clk_hw pdmclk_hw; struct clk *clk; int enabled; }; -static int twl6040_bitclk_is_prepared(struct clk_hw *hw) +static int twl6040_pdmclk_is_prepared(struct clk_hw *hw) { - struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, - mcpdm_fclk); - return twl6040_clk->enabled; + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); + + return pdmclk->enabled; } -static int twl6040_bitclk_prepare(struct clk_hw *hw) +static int twl6040_pdmclk_prepare(struct clk_hw *hw) { - struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, - mcpdm_fclk); + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); int ret; - ret = twl6040_power(twl6040_clk->twl6040, 1); + ret = twl6040_power(pdmclk->twl6040, 1); if (!ret) - twl6040_clk->enabled = 1; + pdmclk->enabled = 1; return ret; } -static void twl6040_bitclk_unprepare(struct clk_hw *hw) +static void twl6040_pdmclk_unprepare(struct clk_hw *hw) { - struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, - mcpdm_fclk); + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); int ret; - ret = twl6040_power(twl6040_clk->twl6040, 0); + ret = twl6040_power(pdmclk->twl6040, 0); if (!ret) - twl6040_clk->enabled = 0; + pdmclk->enabled = 0; + +} + +static unsigned long twl6040_pdmclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, + pdmclk_hw); + + return twl6040_get_sysclk(pdmclk->twl6040); } -static const struct clk_ops twl6040_mcpdm_ops = { - .is_prepared = twl6040_bitclk_is_prepared, - .prepare = twl6040_bitclk_prepare, - .unprepare = twl6040_bitclk_unprepare, +static const struct clk_ops twl6040_pdmclk_ops = { + .is_prepared = twl6040_pdmclk_is_prepared, + .prepare = twl6040_pdmclk_prepare, + .unprepare = twl6040_pdmclk_unprepare, + .recalc_rate = twl6040_pdmclk_recalc_rate, }; -static struct clk_init_data wm831x_clkout_init = { - .name = "mcpdm_fclk", - .ops = &twl6040_mcpdm_ops, +static struct clk_init_data twl6040_pdmclk_init = { + .name = "pdmclk", + .ops = &twl6040_pdmclk_ops, + .flags = CLK_GET_RATE_NOCACHE, }; -static int twl6040_clk_probe(struct platform_device *pdev) +static int twl6040_pdmclk_probe(struct platform_device *pdev) { struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent); - struct twl6040_clk *clkdata; + struct twl6040_pdmclk *clkdata; clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL); if (!clkdata) @@ -88,8 +101,8 @@ static int twl6040_clk_probe(struct platform_device *pdev) clkdata->dev = &pdev->dev; clkdata->twl6040 = twl6040; - clkdata->mcpdm_fclk.init = &wm831x_clkout_init; - clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk); + clkdata->pdmclk_hw.init = &twl6040_pdmclk_init; + clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->pdmclk_hw); if (IS_ERR(clkdata->clk)) return PTR_ERR(clkdata->clk); @@ -99,16 +112,16 @@ static int twl6040_clk_probe(struct platform_device *pdev) of_clk_src_simple_get, clkdata->clk); } -static struct platform_driver twl6040_clk_driver = { +static struct platform_driver twl6040_pdmclk_driver = { .driver = { - .name = "twl6040-clk", + .name = "twl6040-pdmclk", }, - .probe = twl6040_clk_probe, + .probe = twl6040_pdmclk_probe, }; -module_platform_driver(twl6040_clk_driver); +module_platform_driver(twl6040_pdmclk_driver); MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock"); MODULE_AUTHOR("Peter Ujfalusi "); -MODULE_ALIAS("platform:twl6040-clk"); +MODULE_ALIAS("platform:twl6040-pdmclk"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From cedfbc309d62f8f029dc0c3b926452cc84796023 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 19 Jul 2016 15:42:17 +0200 Subject: dt-bindings: clock: add DT binding for the Xtal clock on Armada 3700 This commit adds the DT binding documentation for the the Xtal clock on Armada 3700 used in the Marvell Armada 3700 SoCs. Signed-off-by: Gregory CLEMENT Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt new file mode 100644 index 0000000..a88f1f0 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt @@ -0,0 +1,28 @@ +* Xtal Clock bindings for Marvell Armada 37xx SoCs + +Marvell Armada 37xx SoCs allow to determine the xtal clock frequencies by +reading the gpio latch register. + +This node must be a subnode of the node exposing the register address +of the GPIO block where the gpio latch is located. + +Required properties: +- compatible : shall be one of the following: + "marvell,armada-3700-xtal-clock" +- #clock-cells : from common clock binding; shall be set to 0 + +Optional properties: +- clock-output-names : from common clock binding; allows overwrite default clock + output names ("xtal") + +Example: +gpio1: gpio@13800 { + compatible = "marvell,armada-3700-gpio", "syscon", "simple-mfd"; + reg = <0x13800 0x1000>; + + xtalclk: xtal-clk { + compatible = "marvell,armada-3700-xtal-clock"; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; +}; -- cgit v0.10.2 From 7ea8250406a6abe2f057c2096249c63b788b728f Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 19 Jul 2016 15:42:18 +0200 Subject: clk: mvebu: Add the xtal clock for Armada 3700 SoC This clock is the parent of all the Armada 3700 clocks. It is a fixed rate clock which depends on the gpio configuration read when resetting the SoC. Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 3165da7..fddc8ac 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -24,6 +24,9 @@ config ARMADA_39X_CLK bool select MVEBU_CLK_COMMON +config ARMADA_37XX_CLK + bool + config ARMADA_XP_CLK bool select MVEBU_CLK_COMMON diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 7172ef6..4257a36 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o +obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-xtal.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o diff --git a/drivers/clk/mvebu/armada-37xx-xtal.c b/drivers/clk/mvebu/armada-37xx-xtal.c new file mode 100644 index 0000000..612d65e --- /dev/null +++ b/drivers/clk/mvebu/armada-37xx-xtal.c @@ -0,0 +1,91 @@ +/* + * Marvell Armada 37xx SoC xtal clocks + * + * Copyright (C) 2016 Marvell + * + * Gregory CLEMENT + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include + +#define NB_GPIO1_LATCH 0xC +#define XTAL_MODE BIT(31) + +static int armada_3700_xtal_clock_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const char *xtal_name = "xtal"; + struct device_node *parent; + struct regmap *regmap; + struct clk_hw *xtal_hw; + unsigned int rate; + u32 reg; + int ret; + + xtal_hw = devm_kzalloc(&pdev->dev, sizeof(*xtal_hw), GFP_KERNEL); + if (!xtal_hw) + return -ENOMEM; + + platform_set_drvdata(pdev, xtal_hw); + + parent = np->parent; + if (!parent) { + dev_err(&pdev->dev, "no parent\n"); + return -ENODEV; + } + + regmap = syscon_node_to_regmap(parent); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "cannot get regmap\n"); + return PTR_ERR(regmap); + } + + ret = regmap_read(regmap, NB_GPIO1_LATCH, ®); + if (ret) { + dev_err(&pdev->dev, "cannot read from regmap\n"); + return ret; + } + + if (reg & XTAL_MODE) + rate = 40000000; + else + rate = 25000000; + + of_property_read_string_index(np, "clock-output-names", 0, &xtal_name); + xtal_hw = clk_hw_register_fixed_rate(NULL, xtal_name, NULL, 0, rate); + if (IS_ERR(xtal_hw)) + return PTR_ERR(xtal_hw); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, xtal_hw); + + return ret; +} + +static int armada_3700_xtal_clock_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +static const struct of_device_id armada_3700_xtal_clock_of_match[] = { + { .compatible = "marvell,armada-3700-xtal-clock", }, + { } +}; + +static struct platform_driver armada_3700_xtal_clock_driver = { + .probe = armada_3700_xtal_clock_probe, + .remove = armada_3700_xtal_clock_remove, + .driver = { + .name = "marvell-armada-3700-xtal-clock", + .of_match_table = armada_3700_xtal_clock_of_match, + }, +}; + +builtin_platform_driver(armada_3700_xtal_clock_driver); -- cgit v0.10.2 From c302588e17d084408210a45a0fa6243978a0f785 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 19 Jul 2016 15:42:19 +0200 Subject: dt-bindings: clock: add DT binding for the TBG clocks on Armada 3700 This commit adds the DT binding documentation for the Time Base Generator clock used in the Marvell Armada 3700 SoCs. Signed-off-by: Gregory CLEMENT Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/armada3700-tbg-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-tbg-clock.txt new file mode 100644 index 0000000..0ba1d83 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/armada3700-tbg-clock.txt @@ -0,0 +1,27 @@ +* Time Base Generator Clock bindings for Marvell Armada 37xx SoCs + +Marvell Armada 37xx SoCs provde Time Base Generator clocks which are +used as parent clocks for the peripheral clocks. + +The TBG clock consumer should specify the desired clock by having the +clock ID in its "clocks" phandle cell. + +The following is a list of provided IDs and clock names on Armada 3700: + 0 = TBG A P + 1 = TBG B P + 2 = TBG A S + 3 = TBG B S + +Required properties: +- compatible : shall be "marvell,armada-3700-tbg-clock" +- reg : must be the register address of North Bridge PLL register +- #clock-cells : from common clock binding; shall be set to 1 + +Example: + +tbg: tbg@13200 { + compatible = "marvell,armada-3700-tbg-clock"; + reg = <0x13200 0x1000>; + clocks = <&xtalclk>; + #clock-cells = <1>; +}; -- cgit v0.10.2 From 96265523ace51b71dc1b2fd445a93c4b2f9bedb8 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 19 Jul 2016 15:42:20 +0200 Subject: clk: mvebu Add the time base generator clocks for Armada 3700 These clocks are children of the xtal clock and each one can be selected as a source for the peripheral clocks. According to the datasheet it should be possible to modify their rate, but currently it is not supported. Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 4257a36..72e3512 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-xtal.o +obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-tbg.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c new file mode 100644 index 0000000..aa80db1 --- /dev/null +++ b/drivers/clk/mvebu/armada-37xx-tbg.c @@ -0,0 +1,158 @@ +/* + * Marvell Armada 37xx SoC Time Base Generator clocks + * + * Copyright (C) 2016 Marvell + * + * Gregory CLEMENT + * + * This file is licensed under the terms of the GNU General Public + * License version 2 or later. This program is licensed "as is" + * without any warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#define NUM_TBG 4 + +#define TBG_CTRL0 0x4 +#define TBG_CTRL1 0x8 +#define TBG_CTRL7 0x20 +#define TBG_CTRL8 0x30 + +#define TBG_DIV_MASK 0x1FF + +#define TBG_A_REFDIV 0 +#define TBG_B_REFDIV 16 + +#define TBG_A_FBDIV 2 +#define TBG_B_FBDIV 18 + +#define TBG_A_VCODIV_SE 0 +#define TBG_B_VCODIV_SE 16 + +#define TBG_A_VCODIV_DIFF 1 +#define TBG_B_VCODIV_DIFF 17 + +struct tbg_def { + char *name; + u32 refdiv_offset; + u32 fbdiv_offset; + u32 vcodiv_reg; + u32 vcodiv_offset; +}; + +static const struct tbg_def tbg[NUM_TBG] = { + {"TBG-A-P", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL8, TBG_A_VCODIV_DIFF}, + {"TBG-B-P", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL8, TBG_B_VCODIV_DIFF}, + {"TBG-A-S", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL1, TBG_A_VCODIV_SE}, + {"TBG-B-S", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL1, TBG_B_VCODIV_SE}, +}; + +static unsigned int tbg_get_mult(void __iomem *reg, const struct tbg_def *ptbg) +{ + u32 val; + + val = readl(reg + TBG_CTRL0); + + return ((val >> ptbg->fbdiv_offset) & TBG_DIV_MASK) << 2; +} + +static unsigned int tbg_get_div(void __iomem *reg, const struct tbg_def *ptbg) +{ + u32 val; + unsigned int div; + + val = readl(reg + TBG_CTRL7); + + div = (val >> ptbg->refdiv_offset) & TBG_DIV_MASK; + if (div == 0) + div = 1; + val = readl(reg + ptbg->vcodiv_reg); + + div *= 1 << ((val >> ptbg->vcodiv_offset) & TBG_DIV_MASK); + + return div; +} + + +static int armada_3700_tbg_clock_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct clk_hw_onecell_data *hw_tbg_data; + struct device *dev = &pdev->dev; + const char *parent_name; + struct resource *res; + struct clk *parent; + void __iomem *reg; + int i, ret; + + hw_tbg_data = devm_kzalloc(&pdev->dev, sizeof(*hw_tbg_data) + + sizeof(*hw_tbg_data->hws) * NUM_TBG, + GFP_KERNEL); + if (!hw_tbg_data) + return -ENOMEM; + hw_tbg_data->num = NUM_TBG; + platform_set_drvdata(pdev, hw_tbg_data); + + parent = devm_clk_get(dev, NULL); + if (IS_ERR(parent)) { + dev_err(dev, "Could get the clock parent\n"); + return -EINVAL; + } + parent_name = __clk_get_name(parent); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(dev, res); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + for (i = 0; i < NUM_TBG; i++) { + const char *name; + unsigned int mult, div; + + name = tbg[i].name; + mult = tbg_get_mult(reg, &tbg[i]); + div = tbg_get_div(reg, &tbg[i]); + hw_tbg_data->hws[i] = clk_hw_register_fixed_factor(NULL, name, + parent_name, 0, mult, div); + if (IS_ERR(hw_tbg_data->hws[i])) + dev_err(dev, "Can't register TBG clock %s\n", name); + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, hw_tbg_data); + + return ret; +} + +static int armada_3700_tbg_clock_remove(struct platform_device *pdev) +{ + int i; + struct clk_hw_onecell_data *hw_tbg_data = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + for (i = 0; i < hw_tbg_data->num; i++) + clk_hw_unregister_fixed_factor(hw_tbg_data->hws[i]); + + return 0; +} + +static const struct of_device_id armada_3700_tbg_clock_of_match[] = { + { .compatible = "marvell,armada-3700-tbg-clock", }, + { } +}; + +static struct platform_driver armada_3700_tbg_clock_driver = { + .probe = armada_3700_tbg_clock_probe, + .remove = armada_3700_tbg_clock_remove, + .driver = { + .name = "marvell-armada-3700-tbg-clock", + .of_match_table = armada_3700_tbg_clock_of_match, + }, +}; + +builtin_platform_driver(armada_3700_tbg_clock_driver); -- cgit v0.10.2 From c6d591c14e45e7ca8e158f2e0e5449371e23055c Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 19 Jul 2016 15:42:21 +0200 Subject: dt-bindings: clock: add DT binding for the peripheral clocks on Armada 3700 This commit adds the DT binding documentation for the peripheral clocks used in the Marvell Armada 3700 SoCs. Signed-off-by: Gregory CLEMENT Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/armada3700-periph-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-periph-clock.txt new file mode 100644 index 0000000..1e3370b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/armada3700-periph-clock.txt @@ -0,0 +1,70 @@ +* Peripheral Clock bindings for Marvell Armada 37xx SoCs + +Marvell Armada 37xx SoCs provide peripheral clocks which are +used as clock source for the peripheral of the SoC. + +There are two different blocks associated to north bridge and south +bridge. + +The peripheral clock consumer should specify the desired clock by +having the clock ID in its "clocks" phandle cell. + +The following is a list of provided IDs for Armada 370 North bridge clocks: +ID Clock name Description +----------------------------------- +0 mmc MMC controller +1 sata_host Sata Host +2 sec_at Security AT +3 sac_dap Security DAP +4 tsecm Security Engine +5 setm_tmx Serial Embedded Trace Module +6 avs Adaptive Voltage Scaling +7 sqf SPI +8 pwm PWM +9 i2c_2 I2C 2 +10 i2c_1 I2C 1 +11 ddr_phy DDR PHY +12 ddr_fclk DDR F clock +13 trace Trace +14 counter Counter +15 eip97 EIP 97 +16 cpu CPU + +The following is a list of provided IDs for Armada 370 South bridge clocks: +ID Clock name Description +----------------------------------- +0 gbe-50 50 MHz parent clock for Gigabit Ethernet +1 gbe-core parent clock for Gigabit Ethernet core +2 gbe-125 125 MHz parent clock for Gigabit Ethernet +3 gbe1-50 50 MHz clock for Gigabit Ethernet port 1 +4 gbe0-50 50 MHz clock for Gigabit Ethernet port 0 +5 gbe1-125 125 MHz clock for Gigabit Ethernet port 1 +6 gbe0-125 125 MHz clock for Gigabit Ethernet port 0 +7 gbe1-core Gigabit Ethernet core port 1 +8 gbe0-core Gigabit Ethernet core port 0 +9 gbe-bm Gigabit Ethernet Buffer Manager +10 sdio SDIO +11 usb32-sub2-sys USB 2 clock +12 usb32-ss-sys USB 3 clock + +Required properties: + +- compatible : shall be "marvell,armada-3700-periph-clock-nb" for the + north bridge block, or + "marvell,armada-3700-periph-clock-sb" for the south bridge block +- reg : must be the register address of North/South Bridge Clock register +- #clock-cells : from common clock binding; shall be set to 1 + +- clocks : list of the parent clock phandle in the following order: + TBG-A P, TBG-B P, TBG-A S, TBG-B S and finally the xtal clock. + + +Example: + +nb_perih_clk: nb-periph-clk@13000{ + compatible = "marvell,armada-3700-periph-clock-nb"; + reg = <0x13000 0x1000>; + clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, + <&tbg 3>, <&xtalclk>; + #clock-cells = <1>; +}; -- cgit v0.10.2 From 8ca4746a78abc39cc0496654068eaaadb0f3c4d0 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 19 Jul 2016 15:42:22 +0200 Subject: clk: mvebu: Add the peripheral clock driver for Armada 3700 These clocks are the ones which will be used as source for the peripherals of the Armada 3700 SoC. On this SoC there is two blocks of clocks: the North bridge one and the South bridge one. Most of them are gatable. Most of the time their rate are their parent rated divided by a ratio depending of two registers. Their parent can be choose between the TBG clocks for most of them. However, some of them can't choose their parent or directly depend of the xtal clocks. Other ones do not use exactly the same pattern to find the ratio between their parent rate and their rate. For these reason each clock is a composite clock and the operations they use are different depending of the clock. According to the datasheet it would be possible to select the parent clock and the ratio, however currently the driver does not support it. Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 72e3512..d9ae97f 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-xtal.o obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-tbg.o +obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-periph.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c new file mode 100644 index 0000000..5bb13c9 --- /dev/null +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -0,0 +1,449 @@ +/* + * Marvell Armada 37xx SoC Peripheral clocks + * + * Copyright (C) 2016 Marvell + * + * Gregory CLEMENT + * + * This file is licensed under the terms of the GNU General Public + * License version 2 or later. This program is licensed "as is" + * without any warranty of any kind, whether express or implied. + * + * Most of the peripheral clocks can be modelled like this: + * _____ _______ _______ + * TBG-A-P --| | | | | | ______ + * TBG-B-P --| Mux |--| /div1 |--| /div2 |--| Gate |--> perip_clk + * TBG-A-S --| | | | | | |______| + * TBG-B-S --|_____| |_______| |_______| + * + * However some clocks may use only one or two block or and use the + * xtal clock as parent. + */ + +#include +#include +#include +#include +#include + +#define TBG_SEL 0x0 +#define DIV_SEL0 0x4 +#define DIV_SEL1 0x8 +#define DIV_SEL2 0xC +#define CLK_SEL 0x10 +#define CLK_DIS 0x14 + +struct clk_periph_driver_data { + struct clk_hw_onecell_data *hw_data; + spinlock_t lock; +}; + +struct clk_double_div { + struct clk_hw hw; + void __iomem *reg1; + u8 shift1; + void __iomem *reg2; + u8 shift2; +}; + +#define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw) + +struct clk_periph_data { + const char *name; + const char * const *parent_names; + int num_parents; + struct clk_hw *mux_hw; + struct clk_hw *rate_hw; + struct clk_hw *gate_hw; + bool is_double_div; +}; + +static const struct clk_div_table clk_table6[] = { + { .val = 1, .div = 1, }, + { .val = 2, .div = 2, }, + { .val = 3, .div = 3, }, + { .val = 4, .div = 4, }, + { .val = 5, .div = 5, }, + { .val = 6, .div = 6, }, + { .val = 0, .div = 0, }, /* last entry */ +}; + +static const struct clk_div_table clk_table1[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 0, }, /* last entry */ +}; + +static const struct clk_div_table clk_table2[] = { + { .val = 0, .div = 2, }, + { .val = 1, .div = 4, }, + { .val = 0, .div = 0, }, /* last entry */ +}; +static const struct clk_ops clk_double_div_ops; + +#define PERIPH_GATE(_name, _bit) \ +struct clk_gate gate_##_name = { \ + .reg = (void *)CLK_DIS, \ + .bit_idx = _bit, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_gate_ops, \ + } \ +}; + +#define PERIPH_MUX(_name, _shift) \ +struct clk_mux mux_##_name = { \ + .reg = (void *)TBG_SEL, \ + .shift = _shift, \ + .mask = 3, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_mux_ro_ops, \ + } \ +}; + +#define PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2) \ +struct clk_double_div rate_##_name = { \ + .reg1 = (void *)_reg1, \ + .reg2 = (void *)_reg2, \ + .shift1 = _shift1, \ + .shift2 = _shift2, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_double_div_ops, \ + } \ +}; + +#define PERIPH_DIV(_name, _reg, _shift, _table) \ +struct clk_divider rate_##_name = { \ + .reg = (void *)_reg, \ + .table = _table, \ + .shift = _shift, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_divider_ro_ops, \ + } \ +}; + +#define PERIPH_CLK_FULL_DD(_name, _bit, _shift, _reg1, _reg2, _shift1, _shift2)\ +static PERIPH_GATE(_name, _bit); \ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2); + +#define PERIPH_CLK_FULL(_name, _bit, _shift, _reg, _shift1, _table) \ +static PERIPH_GATE(_name, _bit); \ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DIV(_name, _reg, _shift1, _table); + +#define PERIPH_CLK_GATE_DIV(_name, _bit, _reg, _shift, _table) \ +static PERIPH_GATE(_name, _bit); \ +static PERIPH_DIV(_name, _reg, _shift, _table); + +#define PERIPH_CLK_MUX_DIV(_name, _shift, _reg, _shift_div, _table) \ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DIV(_name, _reg, _shift_div, _table); + +#define PERIPH_CLK_MUX_DD(_name, _shift, _reg1, _reg2, _shift1, _shift2)\ +static PERIPH_MUX(_name, _shift); \ +static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2); + +#define REF_CLK_FULL(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .gate_hw = &gate_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + } + +#define REF_CLK_FULL_DD(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .gate_hw = &gate_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + .is_double_div = true, \ + } + +#define REF_CLK_GATE(_name, _parent_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ _parent_name}, \ + .num_parents = 1, \ + .gate_hw = &gate_##_name.hw, \ + } + +#define REF_CLK_GATE_DIV(_name, _parent_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ _parent_name}, \ + .num_parents = 1, \ + .gate_hw = &gate_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + } + +#define REF_CLK_MUX_DIV(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + } + +#define REF_CLK_MUX_DD(_name) \ + { .name = #_name, \ + .parent_names = (const char *[]){ "TBG-A-P", \ + "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ + .num_parents = 4, \ + .mux_hw = &mux_##_name.hw, \ + .rate_hw = &rate_##_name.hw, \ + .is_double_div = true, \ + } + +/* NB periph clocks */ +PERIPH_CLK_FULL_DD(mmc, 2, 0, DIV_SEL2, DIV_SEL2, 16, 13); +PERIPH_CLK_FULL_DD(sata_host, 3, 2, DIV_SEL2, DIV_SEL2, 10, 7); +PERIPH_CLK_FULL_DD(sec_at, 6, 4, DIV_SEL1, DIV_SEL1, 3, 0); +PERIPH_CLK_FULL_DD(sec_dap, 7, 6, DIV_SEL1, DIV_SEL1, 9, 6); +PERIPH_CLK_FULL_DD(tscem, 8, 8, DIV_SEL1, DIV_SEL1, 15, 12); +PERIPH_CLK_FULL(tscem_tmx, 10, 10, DIV_SEL1, 18, clk_table6); +static PERIPH_GATE(avs, 11); +PERIPH_CLK_FULL_DD(pwm, 13, 14, DIV_SEL0, DIV_SEL0, 3, 0); +PERIPH_CLK_FULL_DD(sqf, 12, 12, DIV_SEL1, DIV_SEL1, 27, 24); +static PERIPH_GATE(i2c_2, 16); +static PERIPH_GATE(i2c_1, 17); +PERIPH_CLK_GATE_DIV(ddr_phy, 19, DIV_SEL0, 18, clk_table2); +PERIPH_CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12); +PERIPH_CLK_FULL(trace, 22, 18, DIV_SEL0, 20, clk_table6); +PERIPH_CLK_FULL(counter, 23, 20, DIV_SEL0, 23, clk_table6); +PERIPH_CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19); +PERIPH_CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, clk_table6); + +static struct clk_periph_data data_nb[] ={ + REF_CLK_FULL_DD(mmc), + REF_CLK_FULL_DD(sata_host), + REF_CLK_FULL_DD(sec_at), + REF_CLK_FULL_DD(sec_dap), + REF_CLK_FULL_DD(tscem), + REF_CLK_FULL(tscem_tmx), + REF_CLK_GATE(avs, "xtal"), + REF_CLK_FULL_DD(sqf), + REF_CLK_FULL_DD(pwm), + REF_CLK_GATE(i2c_2, "xtal"), + REF_CLK_GATE(i2c_1, "xtal"), + REF_CLK_GATE_DIV(ddr_phy, "TBG-A-S"), + REF_CLK_FULL_DD(ddr_fclk), + REF_CLK_FULL(trace), + REF_CLK_FULL(counter), + REF_CLK_FULL_DD(eip97), + REF_CLK_MUX_DIV(cpu), + { }, +}; + +/* SB periph clocks */ +PERIPH_CLK_MUX_DD(gbe_50, 6, DIV_SEL2, DIV_SEL2, 6, 9); +PERIPH_CLK_MUX_DD(gbe_core, 8, DIV_SEL1, DIV_SEL1, 18, 21); +PERIPH_CLK_MUX_DD(gbe_125, 10, DIV_SEL1, DIV_SEL1, 6, 9); +static PERIPH_GATE(gbe1_50, 0); +static PERIPH_GATE(gbe0_50, 1); +static PERIPH_GATE(gbe1_125, 2); +static PERIPH_GATE(gbe0_125, 3); +PERIPH_CLK_GATE_DIV(gbe1_core, 4, DIV_SEL1, 13, clk_table1); +PERIPH_CLK_GATE_DIV(gbe0_core, 5, DIV_SEL1, 14, clk_table1); +PERIPH_CLK_GATE_DIV(gbe_bm, 12, DIV_SEL1, 0, clk_table1); +PERIPH_CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6); +PERIPH_CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12); +PERIPH_CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18); + +static struct clk_periph_data data_sb[] = { + REF_CLK_MUX_DD(gbe_50), + REF_CLK_MUX_DD(gbe_core), + REF_CLK_MUX_DD(gbe_125), + REF_CLK_GATE(gbe1_50, "gbe_50"), + REF_CLK_GATE(gbe0_50, "gbe_50"), + REF_CLK_GATE(gbe1_125, "gbe_125"), + REF_CLK_GATE(gbe0_125, "gbe_125"), + REF_CLK_GATE_DIV(gbe1_core, "gbe_core"), + REF_CLK_GATE_DIV(gbe0_core, "gbe_core"), + REF_CLK_GATE_DIV(gbe_bm, "gbe_core"), + REF_CLK_FULL_DD(sdio), + REF_CLK_FULL_DD(usb32_usb2_sys), + REF_CLK_FULL_DD(usb32_ss_sys), + { }, +}; + +static unsigned int get_div(void __iomem *reg, int shift) +{ + u32 val; + + val = (readl(reg) >> shift) & 0x7; + if (val > 6) + return 0; + return val; +} + +static unsigned long clk_double_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_double_div *double_div = to_clk_double_div(hw); + unsigned int div; + + div = get_div(double_div->reg1, double_div->shift1); + div *= get_div(double_div->reg2, double_div->shift2); + + return DIV_ROUND_UP_ULL((u64)parent_rate, div); +} + +static const struct clk_ops clk_double_div_ops = { + .recalc_rate = clk_double_div_recalc_rate, +}; + +static const struct of_device_id armada_3700_periph_clock_of_match[] = { + { .compatible = "marvell,armada-3700-periph-clock-nb", + .data = data_nb, }, + { .compatible = "marvell,armada-3700-periph-clock-sb", + .data = data_sb, }, + { } +}; +static int armada_3700_add_composite_clk(const struct clk_periph_data *data, + void __iomem *reg, spinlock_t *lock, + struct device *dev, struct clk_hw *hw) +{ + const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, + *rate_ops = NULL; + struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *rate_hw = NULL; + + if (data->mux_hw) { + struct clk_mux *mux; + + mux_hw = data->mux_hw; + mux = to_clk_mux(mux_hw); + mux->lock = lock; + mux_ops = mux_hw->init->ops; + mux->reg = reg + (u64)mux->reg; + } + + if (data->gate_hw) { + struct clk_gate *gate; + + gate_hw = data->gate_hw; + gate = to_clk_gate(gate_hw); + gate->lock = lock; + gate_ops = gate_hw->init->ops; + gate->reg = reg + (u64)gate->reg; + } + + if (data->rate_hw) { + rate_hw = data->rate_hw; + rate_ops = rate_hw->init->ops; + if (data->is_double_div) { + struct clk_double_div *rate; + + rate = to_clk_double_div(rate_hw); + rate->reg1 = reg + (u64)rate->reg1; + rate->reg2 = reg + (u64)rate->reg2; + } else { + struct clk_divider *rate = to_clk_divider(rate_hw); + const struct clk_div_table *clkt; + int table_size = 0; + + rate->reg = reg + (u64)rate->reg; + for (clkt = rate->table; clkt->div; clkt++) + table_size++; + rate->width = order_base_2(table_size); + rate->lock = lock; + } + } + + hw = clk_hw_register_composite(dev, data->name, data->parent_names, + data->num_parents, mux_hw, + mux_ops, rate_hw, rate_ops, + gate_hw, gate_ops, CLK_IGNORE_UNUSED); + + if (IS_ERR(hw)) + return PTR_ERR(hw); + + return 0; +} + +static int armada_3700_periph_clock_probe(struct platform_device *pdev) +{ + struct clk_periph_driver_data *driver_data; + struct device_node *np = pdev->dev.of_node; + const struct clk_periph_data *data; + struct device *dev = &pdev->dev; + int num_periph = 0, i, ret; + struct resource *res; + void __iomem *reg; + + data = of_device_get_match_data(dev); + if (!data) + return -ENODEV; + + while (data[num_periph].name) + num_periph++; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(dev, res); + if (IS_ERR(reg)) { + dev_err(dev, "Could not map the periph clock registers\n"); + return PTR_ERR(reg); + } + + driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL); + if (!driver_data) + return -ENOMEM; + + driver_data->hw_data = devm_kzalloc(dev, sizeof(*driver_data->hw_data) + + sizeof(*driver_data->hw_data->hws) * num_periph, + GFP_KERNEL); + if (!driver_data->hw_data) + return -ENOMEM; + driver_data->hw_data->num = num_periph; + + spin_lock_init(&driver_data->lock); + + for (i = 0; i < num_periph; i++) { + struct clk_hw *hw = driver_data->hw_data->hws[i]; + + if (armada_3700_add_composite_clk(&data[i], reg, + &driver_data->lock, dev, hw)) + dev_err(dev, "Can't register periph clock %s\n", + data[i].name); + + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + driver_data->hw_data); + if (ret) { + for (i = 0; i < num_periph; i++) + clk_hw_unregister(driver_data->hw_data->hws[i]); + return ret; + } + + platform_set_drvdata(pdev, driver_data); + return 0; +} + +static int armada_3700_periph_clock_remove(struct platform_device *pdev) +{ + struct clk_periph_driver_data *data = platform_get_drvdata(pdev); + struct clk_hw_onecell_data *hw_data = data->hw_data; + int i; + + of_clk_del_provider(pdev->dev.of_node); + + for (i = 0; i < hw_data->num; i++) + clk_hw_unregister(hw_data->hws[i]); + + return 0; +} + +static struct platform_driver armada_3700_periph_clock_driver = { + .probe = armada_3700_periph_clock_probe, + .remove = armada_3700_periph_clock_remove, + .driver = { + .name = "marvell-armada-3700-periph-clock", + .of_match_table = armada_3700_periph_clock_of_match, + }, +}; + +builtin_platform_driver(armada_3700_periph_clock_driver); -- cgit v0.10.2 From 00746f104420e79efb2dd30467a3546c790b30eb Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 8 Aug 2016 13:55:20 +0000 Subject: clk: gxbb: use builtin_platform_driver to simplify the code Use the builtin_platform_driver() macro to make the code simpler. Signed-off-by: Wei Yongjun Signed-off-by: Stephen Boyd diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index a4c6684b..a6afc3e 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -937,8 +937,4 @@ static struct platform_driver gxbb_driver = { }, }; -static int __init gxbb_clkc_init(void) -{ - return platform_driver_register(&gxbb_driver); -} -device_initcall(gxbb_clkc_init); +builtin_platform_driver(gxbb_driver); -- cgit v0.10.2 From f155d15b64e36b45ca89e3521fe0c1ccad5e5ff0 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 15 Aug 2016 14:32:23 -0700 Subject: clk: Return errors from clk providers in __of_clk_get_from_provider() Before commit 0861e5b8cf80 (clk: Add clk_hw OF clk providers, 2016-02-05) __of_clk_get_from_provider() would return an error pointer of the provider's choosing if there was a provider registered and EPROBE_DEFER otherwise. After that commit, it would return EPROBE_DEFER regardless of whether or not the provider returned an error. This is odd and can lead to behavior where clk consumers keep probe deferring when they should be seeing some other error. Let's restore the previous behavior where we only return EPROBE_DEFER when there isn't a provider in our of_clk_providers list. Otherwise, return the error from the last provider we find that matches the node. Reported-by: Masahiro Yamada Fixes: 0861e5b8cf80 ("clk: Add clk_hw OF clk providers") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 6298715..71cc567 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3194,7 +3194,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, { struct of_clk_provider *provider; struct clk *clk = ERR_PTR(-EPROBE_DEFER); - struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); + struct clk_hw *hw; if (!clkspec) return ERR_PTR(-EINVAL); @@ -3202,12 +3202,13 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, /* Check if we have such a provider in our array */ mutex_lock(&of_clk_mutex); list_for_each_entry(provider, &of_clk_providers, link) { - if (provider->node == clkspec->np) + if (provider->node == clkspec->np) { hw = __of_clk_get_hw_from_provider(provider, clkspec); - if (!IS_ERR(hw)) { clk = __clk_create_clk(hw, dev_id, con_id); + } - if (!IS_ERR(clk) && !__clk_get(clk)) { + if (!IS_ERR(clk)) { + if (!__clk_get(clk)) { __clk_free_clk(clk); clk = ERR_PTR(-ENOENT); } -- cgit v0.10.2 From 1caadde436d230bc37b3caaaef850580c25010e6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Aug 2016 18:50:22 -0700 Subject: clk: fixed-factor: Remove export symbol on setup function This function is marked __init, so it can't possibly need to be exported to modules. Remove the marking. Cc: Gregory CLEMENT Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 070d0d7..a5d402d 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -196,7 +196,6 @@ void __init of_fixed_factor_clk_setup(struct device_node *node) { _of_fixed_factor_clk_setup(node); } -EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup); CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock", of_fixed_factor_clk_setup); -- cgit v0.10.2 From d336e9a71eedb1970b81bc8c042334b70fd4ddf7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Aug 2016 18:50:23 -0700 Subject: clk: fixed-rate: Remove export symbol on setup function This function is only called by builtin code, but we always exported it and had marked it as __init before commit e4eda8e0654c (clk: remove exported function from __init section, 2013-01-06) removed that marking. Given that it isn't used by modules, lets unexport it and add back __init. Cc: Denis Efremov Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index c735272..b5c46b3 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -190,11 +190,10 @@ static struct clk *_of_fixed_clk_setup(struct device_node *node) /** * of_fixed_clk_setup() - Setup function for simple fixed rate clock */ -void of_fixed_clk_setup(struct device_node *node) +void __init of_fixed_clk_setup(struct device_node *node) { _of_fixed_clk_setup(node); } -EXPORT_SYMBOL_GPL(of_fixed_clk_setup); CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); static int of_fixed_clk_remove(struct platform_device *pdev) -- cgit v0.10.2 From 8ad313fe4e0016bac5dc6a7fbb323b8551977bd9 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Jun 2016 16:21:04 +0530 Subject: clk: max77686: Combine Maxim max77686 and max77802 driver The clock IP used on the Maxim PMICs max77686 and max77802 are same. The configuration of clock register is also same except the number of clocks. Part of common code utilisation, there is 3 files for these chips clock driver, one for common and two files for driver registration. Combine both drivers into single file and move common code into same common file reduces the 2 files and make max77686 and max77802 clock driver in single fine. This driver does not depends on the parent driver structure. The regmap handle is acquired through regmap APIs for the register access. This combination of driver helps on adding clock driver for different Maxim PMICs which has similar clock IP like MAX77620 and MAX20024. Signed-off-by: Laxman Dewangan CC: Krzysztof Kozlowski CC: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e2d9bd7..d7d2993 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -31,22 +31,11 @@ config COMMON_CLK_WM831X source "drivers/clk/versatile/Kconfig" -config COMMON_CLK_MAX_GEN - bool - config COMMON_CLK_MAX77686 - tristate "Clock driver for Maxim 77686 MFD" - depends on MFD_MAX77686 - select COMMON_CLK_MAX_GEN - ---help--- - This driver supports Maxim 77686 crystal oscillator clock. - -config COMMON_CLK_MAX77802 - tristate "Clock driver for Maxim 77802 PMIC" + tristate "Clock driver for Maxim 77686/77802 MFD" depends on MFD_MAX77686 - select COMMON_CLK_MAX_GEN ---help--- - This driver supports Maxim 77802 crystal oscillator clock. + This driver supports Maxim 77686/77802 crystal oscillator clock. config COMMON_CLK_RK808 tristate "Clock driver for RK808/RK818" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 3b6f9cf..e775a83 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,9 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o -obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o -obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c deleted file mode 100644 index 35af9cb..0000000 --- a/drivers/clk/clk-max-gen.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks - * - * Copyright (C) 2014 Google, Inc - * - * Copyright (C) 2012 Samsung Electornics - * Jonghwa Lee - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This driver is based on clk-max77686.c - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clk-max-gen.h" - -struct max_gen_clk { - struct regmap *regmap; - u32 mask; - u32 reg; - struct clk_hw hw; -}; - -static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw) -{ - return container_of(hw, struct max_gen_clk, hw); -} - -static int max_gen_clk_prepare(struct clk_hw *hw) -{ - struct max_gen_clk *max_gen = to_max_gen_clk(hw); - - return regmap_update_bits(max_gen->regmap, max_gen->reg, - max_gen->mask, max_gen->mask); -} - -static void max_gen_clk_unprepare(struct clk_hw *hw) -{ - struct max_gen_clk *max_gen = to_max_gen_clk(hw); - - regmap_update_bits(max_gen->regmap, max_gen->reg, - max_gen->mask, ~max_gen->mask); -} - -static int max_gen_clk_is_prepared(struct clk_hw *hw) -{ - struct max_gen_clk *max_gen = to_max_gen_clk(hw); - int ret; - u32 val; - - ret = regmap_read(max_gen->regmap, max_gen->reg, &val); - - if (ret < 0) - return -EINVAL; - - return val & max_gen->mask; -} - -static unsigned long max_gen_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - return 32768; -} - -struct clk_ops max_gen_clk_ops = { - .prepare = max_gen_clk_prepare, - .unprepare = max_gen_clk_unprepare, - .is_prepared = max_gen_clk_is_prepared, - .recalc_rate = max_gen_recalc_rate, -}; -EXPORT_SYMBOL_GPL(max_gen_clk_ops); - -static struct clk *max_gen_clk_register(struct device *dev, - struct max_gen_clk *max_gen) -{ - struct clk *clk; - struct clk_hw *hw = &max_gen->hw; - int ret; - - clk = devm_clk_register(dev, hw); - if (IS_ERR(clk)) - return clk; - - ret = clk_register_clkdev(clk, hw->init->name, NULL); - - if (ret) - return ERR_PTR(ret); - - return clk; -} - -int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, - u32 reg, struct clk_init_data *clks_init, int num_init) -{ - int i, ret; - struct max_gen_clk *max_gen_clks; - struct clk **clocks; - struct device *dev = pdev->dev.parent; - const char *clk_name; - struct clk_init_data *init; - - clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL); - if (!clocks) - return -ENOMEM; - - max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk) - * num_init, GFP_KERNEL); - if (!max_gen_clks) - return -ENOMEM; - - for (i = 0; i < num_init; i++) { - max_gen_clks[i].regmap = regmap; - max_gen_clks[i].mask = 1 << i; - max_gen_clks[i].reg = reg; - - init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL); - if (!init) - return -ENOMEM; - - if (dev->of_node && - !of_property_read_string_index(dev->of_node, - "clock-output-names", - i, &clk_name)) - init->name = clk_name; - else - init->name = clks_init[i].name; - - init->ops = clks_init[i].ops; - init->flags = clks_init[i].flags; - - max_gen_clks[i].hw.init = init; - - clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]); - if (IS_ERR(clocks[i])) { - ret = PTR_ERR(clocks[i]); - dev_err(dev, "failed to register %s\n", - max_gen_clks[i].hw.init->name); - return ret; - } - } - - platform_set_drvdata(pdev, clocks); - - if (dev->of_node) { - struct clk_onecell_data *of_data; - - of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL); - if (!of_data) - return -ENOMEM; - - of_data->clks = clocks; - of_data->clk_num = num_init; - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, - of_data); - - if (ret) { - dev_err(dev, "failed to register OF clock provider\n"); - return ret; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(max_gen_clk_probe); - -int max_gen_clk_remove(struct platform_device *pdev, int num_init) -{ - struct device *dev = pdev->dev.parent; - - if (dev->of_node) - of_clk_del_provider(dev->of_node); - - return 0; -} -EXPORT_SYMBOL_GPL(max_gen_clk_remove); diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h deleted file mode 100644 index 997e86f..0000000 --- a/drivers/clk/clk-max-gen.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks - * - * Copyright (C) 2014 Google, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __CLK_MAX_GEN_H__ -#define __CLK_MAX_GEN_H__ - -#include -#include -#include -#include -#include - -int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, - u32 reg, struct clk_init_data *clks_init, int num_init); -int max_gen_clk_remove(struct platform_device *pdev, int num_init); -extern struct clk_ops max_gen_clk_ops; - -#endif /* __CLK_MAX_GEN_H__ */ diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 9b6f277..9aba3a8 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -1,5 +1,5 @@ /* - * clk-max77686.c - Clock driver for Maxim 77686 + * clk-max77686.c - Clock driver for Maxim 77686/MAX77802 * * Copyright (C) 2012 Samsung Electornics * Jonghwa Lee @@ -30,41 +30,261 @@ #include #include #include +#include +#include #include -#include "clk-max-gen.h" +#include -static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { +#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3 + +enum max77686_chip_name { + CHIP_MAX77686, + CHIP_MAX77802, +}; + +struct max77686_hw_clk_info { + const char *name; + u32 clk_reg; + u32 clk_enable_mask; + u32 flags; +}; + +struct max77686_clk_init_data { + struct regmap *regmap; + struct clk_hw hw; + struct clk_init_data clk_idata; + const struct max77686_hw_clk_info *clk_info; +}; + +struct max77686_clk_driver_data { + enum max77686_chip_name chip; + struct clk **clks; + struct max77686_clk_init_data *max_clk_data; + struct clk_onecell_data of_data; +}; + +static const struct +max77686_hw_clk_info max77686_hw_clks_info[MAX77686_CLKS_NUM] = { [MAX77686_CLK_AP] = { .name = "32khz_ap", - .ops = &max_gen_clk_ops, + .clk_reg = MAX77686_REG_32KHZ, + .clk_enable_mask = BIT(MAX77686_CLK_AP), }, [MAX77686_CLK_CP] = { .name = "32khz_cp", - .ops = &max_gen_clk_ops, + .clk_reg = MAX77686_REG_32KHZ, + .clk_enable_mask = BIT(MAX77686_CLK_CP), }, [MAX77686_CLK_PMIC] = { .name = "32khz_pmic", - .ops = &max_gen_clk_ops, + .clk_reg = MAX77686_REG_32KHZ, + .clk_enable_mask = BIT(MAX77686_CLK_PMIC), + }, +}; + +static const struct +max77686_hw_clk_info max77802_hw_clks_info[MAX77802_CLKS_NUM] = { + [MAX77802_CLK_32K_AP] = { + .name = "32khz_ap", + .clk_reg = MAX77802_REG_32KHZ, + .clk_enable_mask = BIT(MAX77802_CLK_32K_AP), + }, + [MAX77802_CLK_32K_CP] = { + .name = "32khz_cp", + .clk_reg = MAX77802_REG_32KHZ, + .clk_enable_mask = BIT(MAX77802_CLK_32K_CP), }, }; +static struct max77686_clk_init_data *to_max77686_clk_init_data( + struct clk_hw *hw) +{ + return container_of(hw, struct max77686_clk_init_data, hw); +} + +static int max77686_clk_prepare(struct clk_hw *hw) +{ + struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw); + + return regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg, + max77686->clk_info->clk_enable_mask, + max77686->clk_info->clk_enable_mask); +} + +static void max77686_clk_unprepare(struct clk_hw *hw) +{ + struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw); + + regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg, + max77686->clk_info->clk_enable_mask, + ~max77686->clk_info->clk_enable_mask); +} + +static int max77686_clk_is_prepared(struct clk_hw *hw) +{ + struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw); + int ret; + u32 val; + + ret = regmap_read(max77686->regmap, max77686->clk_info->clk_reg, &val); + + if (ret < 0) + return -EINVAL; + + return val & max77686->clk_info->clk_enable_mask; +} + +static unsigned long max77686_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 32768; +} + +static struct clk_ops max77686_clk_ops = { + .prepare = max77686_clk_prepare, + .unprepare = max77686_clk_unprepare, + .is_prepared = max77686_clk_is_prepared, + .recalc_rate = max77686_recalc_rate, +}; + static int max77686_clk_probe(struct platform_device *pdev) { - struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + const struct platform_device_id *id = platform_get_device_id(pdev); + struct max77686_clk_driver_data *drv_data; + const struct max77686_hw_clk_info *hw_clks; + struct regmap *regmap; + int i, ret, num_clks; + + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + regmap = dev_get_regmap(parent, NULL); + if (!regmap) { + dev_err(dev, "Failed to get rtc regmap\n"); + return -ENODEV; + } + + drv_data->chip = id->driver_data; + + switch (drv_data->chip) { + case CHIP_MAX77686: + num_clks = MAX77686_CLKS_NUM; + hw_clks = max77686_hw_clks_info; + break; + + case CHIP_MAX77802: + num_clks = MAX77802_CLKS_NUM; + hw_clks = max77802_hw_clks_info; + break; + + default: + dev_err(dev, "Unknown Chip ID\n"); + return -EINVAL; + } + + drv_data->max_clk_data = devm_kcalloc(dev, num_clks, + sizeof(*drv_data->max_clk_data), + GFP_KERNEL); + if (!drv_data->max_clk_data) + return -ENOMEM; + + drv_data->clks = devm_kcalloc(dev, num_clks, + sizeof(*drv_data->clks), GFP_KERNEL); + if (!drv_data->clks) + return -ENOMEM; - return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ, - max77686_clks_init, MAX77686_CLKS_NUM); + for (i = 0; i < num_clks; i++) { + struct max77686_clk_init_data *max_clk_data; + struct clk *clk; + const char *clk_name; + + max_clk_data = &drv_data->max_clk_data[i]; + + max_clk_data->regmap = regmap; + max_clk_data->clk_info = &hw_clks[i]; + max_clk_data->clk_idata.flags = hw_clks[i].flags; + max_clk_data->clk_idata.ops = &max77686_clk_ops; + + if (parent->of_node && + !of_property_read_string_index(parent->of_node, + "clock-output-names", + i, &clk_name)) + max_clk_data->clk_idata.name = clk_name; + else + max_clk_data->clk_idata.name = hw_clks[i].name; + + max_clk_data->hw.init = &max_clk_data->clk_idata; + + clk = devm_clk_register(dev, &max_clk_data->hw); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev, "Failed to clock register: %d\n", ret); + return ret; + } + + ret = clk_register_clkdev(clk, max_clk_data->clk_idata.name, + NULL); + if (ret < 0) { + dev_err(dev, "Failed to clkdev register: %d\n", ret); + return ret; + } + drv_data->clks[i] = clk; + } + + platform_set_drvdata(pdev, drv_data); + + if (parent->of_node) { + drv_data->of_data.clks = drv_data->clks; + drv_data->of_data.clk_num = num_clks; + ret = of_clk_add_provider(parent->of_node, + of_clk_src_onecell_get, + &drv_data->of_data); + + if (ret < 0) { + dev_err(dev, "Failed to register OF clock provider: %d\n", + ret); + return ret; + } + } + + /* MAX77802: Enable low-jitter mode on the 32khz clocks. */ + if (drv_data->chip == CHIP_MAX77802) { + ret = regmap_update_bits(regmap, MAX77802_REG_32KHZ, + 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT, + 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT); + if (ret < 0) { + dev_err(dev, "Failed to config low-jitter: %d\n", ret); + goto remove_of_clk_provider; + } + } + + return 0; + +remove_of_clk_provider: + if (parent->of_node) + of_clk_del_provider(parent->of_node); + + return ret; } static int max77686_clk_remove(struct platform_device *pdev) { - return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM); + struct device *parent = pdev->dev.parent; + + if (parent->of_node) + of_clk_del_provider(parent->of_node); + + return 0; } static const struct platform_device_id max77686_clk_id[] = { - { "max77686-clk", 0}, - { }, + { "max77686-clk", .driver_data = CHIP_MAX77686, }, + { "max77802-clk", .driver_data = CHIP_MAX77802, }, + {}, }; MODULE_DEVICE_TABLE(platform, max77686_clk_id); diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c deleted file mode 100644 index 355dd2e..0000000 --- a/drivers/clk/clk-max77802.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * clk-max77802.c - Clock driver for Maxim 77802 - * - * Copyright (C) 2014 Google, Inc - * - * Copyright (C) 2012 Samsung Electornics - * Jonghwa Lee - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This driver is based on clk-max77686.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "clk-max-gen.h" - -#define MAX77802_CLOCK_OPMODE_MASK 0x1 -#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3 - -static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = { - [MAX77802_CLK_32K_AP] = { - .name = "32khz_ap", - .ops = &max_gen_clk_ops, - }, - [MAX77802_CLK_32K_CP] = { - .name = "32khz_cp", - .ops = &max_gen_clk_ops, - }, -}; - -static int max77802_clk_probe(struct platform_device *pdev) -{ - struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); - int ret; - - ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ, - max77802_clks_init, MAX77802_CLKS_NUM); - - if (ret) { - dev_err(&pdev->dev, "generic probe failed %d\n", ret); - return ret; - } - - /* Enable low-jitter mode on the 32khz clocks. */ - ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ, - 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT, - 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT); - if (ret < 0) - dev_err(&pdev->dev, "failed to enable low-jitter mode\n"); - - return ret; -} - -static int max77802_clk_remove(struct platform_device *pdev) -{ - return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM); -} - -static const struct platform_device_id max77802_clk_id[] = { - { "max77802-clk", 0}, - { }, -}; -MODULE_DEVICE_TABLE(platform, max77802_clk_id); - -static struct platform_driver max77802_clk_driver = { - .driver = { - .name = "max77802-clk", - }, - .probe = max77802_clk_probe, - .remove = max77802_clk_remove, - .id_table = max77802_clk_id, -}; - -module_platform_driver(max77802_clk_driver); - -MODULE_DESCRIPTION("MAXIM 77802 Clock Driver"); -MODULE_AUTHOR("Javier Martinez Canillas Date: Fri, 17 Jun 2016 16:21:05 +0530 Subject: clk: Combine DT binding doc for max77686 and max77802 The clock IP used on the Maxim PMICs max77686 and max77802 are same. The configuration of clock register is also same except the number of clocks. Define the common DT binding file for the clocks of Maxim PMICs MAX77686 and MAX77802. For this, remove the separate DT binding document file for maxim,max77802 and move all information to maxim,max77686 DT binding document. Signed-off-by: Laxman Dewangan CC: Krzysztof Kozlowski CC: Javier Martinez Canillas Acked-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/maxim,max77686.txt b/Documentation/devicetree/bindings/clock/maxim,max77686.txt index 9c40739..4d973b5 100644 --- a/Documentation/devicetree/bindings/clock/maxim,max77686.txt +++ b/Documentation/devicetree/bindings/clock/maxim,max77686.txt @@ -1,11 +1,15 @@ -Binding for Maxim MAX77686 32k clock generator block +Binding for Maxim MAX77686/MAX77802 32k clock generator block -This is a part of device tree bindings of MAX77686 multi-function device. -More information can be found in bindings/mfd/max77686.txt file. +This is a part of device tree bindings of MAX77686/MAX77802 multi-function +device. More information can be found in bindings/mfd/max77686.txt file for +MAX77686 and bindings/mfd/max77802.txt for MAX77802. The MAX77686 contains three 32.768khz clock outputs that can be controlled (gated/ungated) over I2C. +The MAX77802 contains two 32.768khz clock outputs that can be controlled +(gated/ungated) over I2C. + Following properties should be presend in main device node of the MFD chip. Required properties: @@ -17,30 +21,62 @@ Optional properties: Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. Following indices are allowed: - - 0: 32khz_ap clock, - - 1: 32khz_cp clock, - - 2: 32khz_pmic clock. + - 0: 32khz_ap clock (max77686, max77802), + - 1: 32khz_cp clock (max77686, max77802), + - 2: 32khz_pmic clock (max77686). Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h -header and can be used in device tree sources. +header for MAX77686 and dt-bindings/clock/maxim,max77802.h for MAX77802 and can +be used in device tree sources. + +Example: + +1. With MAX77686: + +#include +/* ... */ + + Node of the MFD chip + max77686: max77686@09 { + compatible = "maxim,max77686"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + #clock-cells = <1>; + + /* ... */ + }; + + Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "my-clock"; + clocks = <&max77686 MAX77686_CLK_PMIC>; + }; + +2. With MAX77802: -Example: Node of the MFD chip +#include +/* ... */ - max77686: max77686@09 { - compatible = "maxim,max77686"; - interrupt-parent = <&wakeup_eint>; - interrupts = <26 0>; - reg = <0x09>; - #clock-cells = <1>; + Node of the MFD chip + max77802: max77802@09 { + compatible = "maxim,max77802"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + #clock-cells = <1>; - /* ... */ - }; + /* ... */ + }; -Example: Clock consumer node + Clock consumer node - foo@0 { - compatible = "bar,foo"; - /* ... */ - clock-names = "my-clock"; - clocks = <&max77686 MAX77686_CLK_PMIC>; - }; + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "my-clock"; + clocks = <&max77802 MAX77802_CLK_32K_AP>; + }; diff --git a/Documentation/devicetree/bindings/clock/maxim,max77802.txt b/Documentation/devicetree/bindings/clock/maxim,max77802.txt deleted file mode 100644 index c6dc783..0000000 --- a/Documentation/devicetree/bindings/clock/maxim,max77802.txt +++ /dev/null @@ -1,44 +0,0 @@ -Binding for Maxim MAX77802 32k clock generator block - -This is a part of device tree bindings of MAX77802 multi-function device. -More information can be found in bindings/mfd/max77802.txt file. - -The MAX77802 contains two 32.768khz clock outputs that can be controlled -(gated/ungated) over I2C. - -Following properties should be present in main device node of the MFD chip. - -Required properties: -- #clock-cells: From common clock binding; shall be set to 1. - -Optional properties: -- clock-output-names: From common clock binding. - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. Following indices are allowed: - - 0: 32khz_ap clock, - - 1: 32khz_cp clock. - -Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77802.h -header and can be used in device tree sources. - -Example: Node of the MFD chip - - max77802: max77802@09 { - compatible = "maxim,max77802"; - interrupt-parent = <&wakeup_eint>; - interrupts = <26 0>; - reg = <0x09>; - #clock-cells = <1>; - - /* ... */ - }; - -Example: Clock consumer node - - foo@0 { - compatible = "bar,foo"; - /* ... */ - clock-names = "my-clock"; - clocks = <&max77802 MAX77802_CLK_32K_AP>; - }; -- cgit v0.10.2 From e581245d8aaf897870afacd4aaf2bbce77cf1f1e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Jun 2016 16:21:06 +0530 Subject: clk: max77686: Add DT binding details for PMIC MAX77620 Maxim has used the same clock IP on multiple PMICs like MAX77686, MAX77802, MAX77620. Only differences are the number of clocks from these PMICs like MAX77686 has 3 clocks output, MAX776802 have two clock output and MAX77620 has one clock output. Add clock binding details and DT example for the MAX77620. Signed-off-by: Laxman Dewangan CC: Krzysztof Kozlowski CC: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/maxim,max77686.txt b/Documentation/devicetree/bindings/clock/maxim,max77686.txt index 4d973b5..8398a3a 100644 --- a/Documentation/devicetree/bindings/clock/maxim,max77686.txt +++ b/Documentation/devicetree/bindings/clock/maxim,max77686.txt @@ -1,14 +1,24 @@ -Binding for Maxim MAX77686/MAX77802 32k clock generator block +Binding for Maxim MAX77686/MAX77802/MAX77620 32k clock generator block -This is a part of device tree bindings of MAX77686/MAX77802 multi-function -device. More information can be found in bindings/mfd/max77686.txt file for -MAX77686 and bindings/mfd/max77802.txt for MAX77802. +This is a part of device tree bindings of MAX77686/MAX77802/MAX77620 +multi-function device. More information can be found in MFD DT binding +doc as follows: + bindings/mfd/max77686.txt for MAX77686 and + bindings/mfd/max77802.txt for MAX77802 and + bindings/mfd/max77620.txt for MAX77620. The MAX77686 contains three 32.768khz clock outputs that can be controlled -(gated/ungated) over I2C. +(gated/ungated) over I2C. Clocks are defined as preprocessor macros in +dt-bindings/clock/maxim,max77686.h. + The MAX77802 contains two 32.768khz clock outputs that can be controlled -(gated/ungated) over I2C. +(gated/ungated) over I2C. Clocks are defined as preprocessor macros in +dt-bindings/clock/maxim,max77802.h. + +The MAX77686 contains one 32.768khz clock outputs that can be controlled +(gated/ungated) over I2C. Clocks are defined as preprocessor macros in +dt-bindings/clock/maxim,max77620.h. Following properties should be presend in main device node of the MFD chip. @@ -21,13 +31,12 @@ Optional properties: Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. Following indices are allowed: - - 0: 32khz_ap clock (max77686, max77802), + - 0: 32khz_ap clock (max77686, max77802), 32khz_out0 (max77620) - 1: 32khz_cp clock (max77686, max77802), - 2: 32khz_pmic clock (max77686). -Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h -header for MAX77686 and dt-bindings/clock/maxim,max77802.h for MAX77802 and can -be used in device tree sources. +Clocks are defined as preprocessor macros in above dt-binding header for +respective chips. Example: @@ -80,3 +89,26 @@ Example: clock-names = "my-clock"; clocks = <&max77802 MAX77802_CLK_32K_AP>; }; + + +3. With MAX77620: + +#include +/* ... */ + + Node of the MFD chip + max77620: max77620@3c { + compatible = "maxim,max77620"; + reg = <0x3c>; + #clock-cells = <1>; + /* ... */ + }; + + Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "my-clock"; + clocks = <&max77620 MAX77620_CLK_32K_OUT0>; + }; diff --git a/include/dt-bindings/clock/maxim,max77620.h b/include/dt-bindings/clock/maxim,max77620.h new file mode 100644 index 0000000..82aba28 --- /dev/null +++ b/include/dt-bindings/clock/maxim,max77620.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. + * + * 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. + * + * Device Tree binding constants clocks for the Maxim 77620 PMIC. + */ + +#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77620_CLOCK_H +#define _DT_BINDINGS_CLOCK_MAXIM_MAX77620_CLOCK_H + +/* Fixed rate clocks. */ + +#define MAX77620_CLK_32K_OUT0 0 + +/* Total number of clocks. */ +#define MAX77620_CLKS_NUM (MAX77620_CLK_32K_OUT0 + 1) + +#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77620_CLOCK_H */ -- cgit v0.10.2 From 5a227cd1ab3693d36ac7a6f1fc4e21a7129f62f0 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Jun 2016 16:21:07 +0530 Subject: clk: max77686: Add support for MAX77620 clocks Maxim Max77620 has one 32KHz clock output and the clock HW IP used on this PMIC is same as what it is there in the MAX77686. Add clock driver support for MAX77620 on the MAX77686 driver. CC: Krzysztof Kozlowski CC: Javier Martinez Canillas Signed-off-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Signed-off-by: Stephen Boyd diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index d7d2993..b3ee99a 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -32,10 +32,11 @@ config COMMON_CLK_WM831X source "drivers/clk/versatile/Kconfig" config COMMON_CLK_MAX77686 - tristate "Clock driver for Maxim 77686/77802 MFD" - depends on MFD_MAX77686 + tristate "Clock driver for Maxim 77620/77686/77802 MFD" + depends on MFD_MAX77686 || MFD_MAX77620 ---help--- - This driver supports Maxim 77686/77802 crystal oscillator clock. + This driver supports Maxim 77620/77686/77802 crystal oscillator + clock. config COMMON_CLK_RK808 tristate "Clock driver for RK808/RK818" diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 9aba3a8..19f6208 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,12 +36,14 @@ #include #include +#include #define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3 enum max77686_chip_name { CHIP_MAX77686, CHIP_MAX77802, + CHIP_MAX77620, }; struct max77686_hw_clk_info { @@ -97,6 +100,15 @@ max77686_hw_clk_info max77802_hw_clks_info[MAX77802_CLKS_NUM] = { }, }; +static const struct +max77686_hw_clk_info max77620_hw_clks_info[MAX77620_CLKS_NUM] = { + [MAX77620_CLK_32K_OUT0] = { + .name = "32khz_out0", + .clk_reg = MAX77620_REG_CNFG1_32K, + .clk_enable_mask = MAX77620_CNFG1_32K_OUT0_EN, + }, +}; + static struct max77686_clk_init_data *to_max77686_clk_init_data( struct clk_hw *hw) { @@ -181,6 +193,11 @@ static int max77686_clk_probe(struct platform_device *pdev) hw_clks = max77802_hw_clks_info; break; + case CHIP_MAX77620: + num_clks = MAX77620_CLKS_NUM; + hw_clks = max77620_hw_clks_info; + break; + default: dev_err(dev, "Unknown Chip ID\n"); return -EINVAL; @@ -284,6 +301,7 @@ static int max77686_clk_remove(struct platform_device *pdev) static const struct platform_device_id max77686_clk_id[] = { { "max77686-clk", .driver_data = CHIP_MAX77686, }, { "max77802-clk", .driver_data = CHIP_MAX77802, }, + { "max77620-clock", .driver_data = CHIP_MAX77620, }, {}, }; MODULE_DEVICE_TABLE(platform, max77686_clk_id); -- cgit v0.10.2 From 33608dcd01d0c0eb3f2442d88c8a97f1195bd2d5 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 2 Aug 2016 14:40:11 -0700 Subject: clk: gxbb: add MMC gate clocks, and expose for DT Add the SD/eMMC gate clocks and expose them for use by DT. While at it, also explose FCLK_DIV2 since this is one of the input clocks to the mux internal to each of the SD/eMMC blocks. Signed-off-by: Kevin Hilman Tested-by: Martin Blumenstingl Signed-off-by: Stephen Boyd diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index a4c6684b..8e36d22 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -583,6 +583,9 @@ static MESON_GATE(sdio, HHI_GCLK_MPEG0, 17); static MESON_GATE(abuf, HHI_GCLK_MPEG0, 18); static MESON_GATE(hiu_iface, HHI_GCLK_MPEG0, 19); static MESON_GATE(assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE(emmc_a, HHI_GCLK_MPEG0, 24); +static MESON_GATE(emmc_b, HHI_GCLK_MPEG0, 25); +static MESON_GATE(emmc_c, HHI_GCLK_MPEG0, 26); static MESON_GATE(spi, HHI_GCLK_MPEG0, 30); static MESON_GATE(i2s_spdif, HHI_GCLK_MPEG1, 2); @@ -748,6 +751,9 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_AO_AHB_BUS] = &gxbb_ao_ahb_bus.hw, [CLKID_AO_IFACE] = &gxbb_ao_iface.hw, [CLKID_AO_I2C] = &gxbb_ao_i2c.hw, + [CLKID_SD_EMMC_A] = &gxbb_emmc_a.hw, + [CLKID_SD_EMMC_B] = &gxbb_emmc_b.hw, + [CLKID_SD_EMMC_C] = &gxbb_emmc_c.hw, }, .num = NR_CLKS, }; @@ -847,6 +853,9 @@ static struct clk_gate *gxbb_clk_gates[] = { &gxbb_ao_ahb_bus, &gxbb_ao_iface, &gxbb_ao_i2c, + &gxbb_emmc_a, + &gxbb_emmc_b, + &gxbb_emmc_c, }; static int gxbb_clkc_probe(struct platform_device *pdev) diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index a2adf34..217df51 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -172,7 +172,7 @@ /* CLKID_CPUCLK */ #define CLKID_HDMI_PLL 2 #define CLKID_FIXED_PLL 3 -#define CLKID_FCLK_DIV2 4 +/* CLKID_FCLK_DIV2 */ #define CLKID_FCLK_DIV3 5 #define CLKID_FCLK_DIV4 6 #define CLKID_FCLK_DIV5 7 @@ -262,8 +262,11 @@ #define CLKID_AO_AHB_BUS 91 #define CLKID_AO_IFACE 92 #define CLKID_AO_I2C 93 +/* CLKID_SD_EMMC_A */ +/* CLKID_SD_EMMC_B */ +/* CLKID_SD_EMMC_C */ -#define NR_CLKS 94 +#define NR_CLKS 97 /* include the CLKIDs that have been made part of the stable DT binding */ #include diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h index f889d80..7d41864 100644 --- a/include/dt-bindings/clock/gxbb-clkc.h +++ b/include/dt-bindings/clock/gxbb-clkc.h @@ -6,7 +6,11 @@ #define __GXBB_CLKC_H #define CLKID_CPUCLK 1 +#define CLKID_FCLK_DIV2 4 #define CLKID_CLK81 12 #define CLKID_ETH 36 +#define CLKID_SD_EMMC_A 94 +#define CLKID_SD_EMMC_B 95 +#define CLKID_SD_EMMC_C 96 #endif /* __GXBB_CLKC_H */ -- cgit v0.10.2 From f7508fedd85e14a9d3c6d4e457231e691618b208 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 11 Aug 2016 14:48:03 +0200 Subject: dt-bindings: Add MDM9615 DT bindings include files for GCC and LCC Signed-off-by: Neil Armstrong Signed-off-by: Stephen Boyd diff --git a/include/dt-bindings/clock/qcom,gcc-mdm9615.h b/include/dt-bindings/clock/qcom,gcc-mdm9615.h new file mode 100644 index 0000000..9ab2c40 --- /dev/null +++ b/include/dt-bindings/clock/qcom,gcc-mdm9615.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) BayLibre, SAS. + * Author : Neil Armstrong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MDM_GCC_9615_H +#define _DT_BINDINGS_CLK_MDM_GCC_9615_H + +#define AFAB_CLK_SRC 0 +#define AFAB_CORE_CLK 1 +#define SFAB_MSS_Q6_SW_A_CLK 2 +#define SFAB_MSS_Q6_FW_A_CLK 3 +#define QDSS_STM_CLK 4 +#define SCSS_A_CLK 5 +#define SCSS_H_CLK 6 +#define SCSS_XO_SRC_CLK 7 +#define AFAB_EBI1_CH0_A_CLK 8 +#define AFAB_EBI1_CH1_A_CLK 9 +#define AFAB_AXI_S0_FCLK 10 +#define AFAB_AXI_S1_FCLK 11 +#define AFAB_AXI_S2_FCLK 12 +#define AFAB_AXI_S3_FCLK 13 +#define AFAB_AXI_S4_FCLK 14 +#define SFAB_CORE_CLK 15 +#define SFAB_AXI_S0_FCLK 16 +#define SFAB_AXI_S1_FCLK 17 +#define SFAB_AXI_S2_FCLK 18 +#define SFAB_AXI_S3_FCLK 19 +#define SFAB_AXI_S4_FCLK 20 +#define SFAB_AHB_S0_FCLK 21 +#define SFAB_AHB_S1_FCLK 22 +#define SFAB_AHB_S2_FCLK 23 +#define SFAB_AHB_S3_FCLK 24 +#define SFAB_AHB_S4_FCLK 25 +#define SFAB_AHB_S5_FCLK 26 +#define SFAB_AHB_S6_FCLK 27 +#define SFAB_AHB_S7_FCLK 28 +#define QDSS_AT_CLK_SRC 29 +#define QDSS_AT_CLK 30 +#define QDSS_TRACECLKIN_CLK_SRC 31 +#define QDSS_TRACECLKIN_CLK 32 +#define QDSS_TSCTR_CLK_SRC 33 +#define QDSS_TSCTR_CLK 34 +#define SFAB_ADM0_M0_A_CLK 35 +#define SFAB_ADM0_M1_A_CLK 36 +#define SFAB_ADM0_M2_H_CLK 37 +#define ADM0_CLK 38 +#define ADM0_PBUS_CLK 39 +#define MSS_XPU_CLK 40 +#define IMEM0_A_CLK 41 +#define QDSS_H_CLK 42 +#define PCIE_A_CLK 43 +#define PCIE_AUX_CLK 44 +#define PCIE_PHY_REF_CLK 45 +#define PCIE_H_CLK 46 +#define SFAB_CLK_SRC 47 +#define MAHB0_CLK 48 +#define Q6SW_CLK_SRC 49 +#define Q6SW_CLK 50 +#define Q6FW_CLK_SRC 51 +#define Q6FW_CLK 52 +#define SFAB_MSS_M_A_CLK 53 +#define SFAB_USB3_M_A_CLK 54 +#define SFAB_LPASS_Q6_A_CLK 55 +#define SFAB_AFAB_M_A_CLK 56 +#define AFAB_SFAB_M0_A_CLK 57 +#define AFAB_SFAB_M1_A_CLK 58 +#define SFAB_SATA_S_H_CLK 59 +#define DFAB_CLK_SRC 60 +#define DFAB_CLK 61 +#define SFAB_DFAB_M_A_CLK 62 +#define DFAB_SFAB_M_A_CLK 63 +#define DFAB_SWAY0_H_CLK 64 +#define DFAB_SWAY1_H_CLK 65 +#define DFAB_ARB0_H_CLK 66 +#define DFAB_ARB1_H_CLK 67 +#define PPSS_H_CLK 68 +#define PPSS_PROC_CLK 69 +#define PPSS_TIMER0_CLK 70 +#define PPSS_TIMER1_CLK 71 +#define PMEM_A_CLK 72 +#define DMA_BAM_H_CLK 73 +#define SIC_H_CLK 74 +#define SPS_TIC_H_CLK 75 +#define SLIMBUS_H_CLK 76 +#define SLIMBUS_XO_SRC_CLK 77 +#define CFPB_2X_CLK_SRC 78 +#define CFPB_CLK 79 +#define CFPB0_H_CLK 80 +#define CFPB1_H_CLK 81 +#define CFPB2_H_CLK 82 +#define SFAB_CFPB_M_H_CLK 83 +#define CFPB_MASTER_H_CLK 84 +#define SFAB_CFPB_S_H_CLK 85 +#define CFPB_SPLITTER_H_CLK 86 +#define TSIF_H_CLK 87 +#define TSIF_INACTIVITY_TIMERS_CLK 88 +#define TSIF_REF_SRC 89 +#define TSIF_REF_CLK 90 +#define CE1_H_CLK 91 +#define CE1_CORE_CLK 92 +#define CE1_SLEEP_CLK 93 +#define CE2_H_CLK 94 +#define CE2_CORE_CLK 95 +#define SFPB_H_CLK_SRC 97 +#define SFPB_H_CLK 98 +#define SFAB_SFPB_M_H_CLK 99 +#define SFAB_SFPB_S_H_CLK 100 +#define RPM_PROC_CLK 101 +#define RPM_BUS_H_CLK 102 +#define RPM_SLEEP_CLK 103 +#define RPM_TIMER_CLK 104 +#define RPM_MSG_RAM_H_CLK 105 +#define PMIC_ARB0_H_CLK 106 +#define PMIC_ARB1_H_CLK 107 +#define PMIC_SSBI2_SRC 108 +#define PMIC_SSBI2_CLK 109 +#define SDC1_H_CLK 110 +#define SDC2_H_CLK 111 +#define SDC3_H_CLK 112 +#define SDC4_H_CLK 113 +#define SDC5_H_CLK 114 +#define SDC1_SRC 115 +#define SDC2_SRC 116 +#define SDC3_SRC 117 +#define SDC4_SRC 118 +#define SDC5_SRC 119 +#define SDC1_CLK 120 +#define SDC2_CLK 121 +#define SDC3_CLK 122 +#define SDC4_CLK 123 +#define SDC5_CLK 124 +#define DFAB_A2_H_CLK 125 +#define USB_HS1_H_CLK 126 +#define USB_HS1_XCVR_SRC 127 +#define USB_HS1_XCVR_CLK 128 +#define USB_HSIC_H_CLK 129 +#define USB_HSIC_XCVR_FS_SRC 130 +#define USB_HSIC_XCVR_FS_CLK 131 +#define USB_HSIC_SYSTEM_CLK_SRC 132 +#define USB_HSIC_SYSTEM_CLK 133 +#define CFPB0_C0_H_CLK 134 +#define CFPB0_C1_H_CLK 135 +#define CFPB0_D0_H_CLK 136 +#define CFPB0_D1_H_CLK 137 +#define USB_FS1_H_CLK 138 +#define USB_FS1_XCVR_FS_SRC 139 +#define USB_FS1_XCVR_FS_CLK 140 +#define USB_FS1_SYSTEM_CLK 141 +#define USB_FS2_H_CLK 142 +#define USB_FS2_XCVR_FS_SRC 143 +#define USB_FS2_XCVR_FS_CLK 144 +#define USB_FS2_SYSTEM_CLK 145 +#define GSBI_COMMON_SIM_SRC 146 +#define GSBI1_H_CLK 147 +#define GSBI2_H_CLK 148 +#define GSBI3_H_CLK 149 +#define GSBI4_H_CLK 150 +#define GSBI5_H_CLK 151 +#define GSBI6_H_CLK 152 +#define GSBI7_H_CLK 153 +#define GSBI8_H_CLK 154 +#define GSBI9_H_CLK 155 +#define GSBI10_H_CLK 156 +#define GSBI11_H_CLK 157 +#define GSBI12_H_CLK 158 +#define GSBI1_UART_SRC 159 +#define GSBI1_UART_CLK 160 +#define GSBI2_UART_SRC 161 +#define GSBI2_UART_CLK 162 +#define GSBI3_UART_SRC 163 +#define GSBI3_UART_CLK 164 +#define GSBI4_UART_SRC 165 +#define GSBI4_UART_CLK 166 +#define GSBI5_UART_SRC 167 +#define GSBI5_UART_CLK 168 +#define GSBI6_UART_SRC 169 +#define GSBI6_UART_CLK 170 +#define GSBI7_UART_SRC 171 +#define GSBI7_UART_CLK 172 +#define GSBI8_UART_SRC 173 +#define GSBI8_UART_CLK 174 +#define GSBI9_UART_SRC 175 +#define GSBI9_UART_CLK 176 +#define GSBI10_UART_SRC 177 +#define GSBI10_UART_CLK 178 +#define GSBI11_UART_SRC 179 +#define GSBI11_UART_CLK 180 +#define GSBI12_UART_SRC 181 +#define GSBI12_UART_CLK 182 +#define GSBI1_QUP_SRC 183 +#define GSBI1_QUP_CLK 184 +#define GSBI2_QUP_SRC 185 +#define GSBI2_QUP_CLK 186 +#define GSBI3_QUP_SRC 187 +#define GSBI3_QUP_CLK 188 +#define GSBI4_QUP_SRC 189 +#define GSBI4_QUP_CLK 190 +#define GSBI5_QUP_SRC 191 +#define GSBI5_QUP_CLK 192 +#define GSBI6_QUP_SRC 193 +#define GSBI6_QUP_CLK 194 +#define GSBI7_QUP_SRC 195 +#define GSBI7_QUP_CLK 196 +#define GSBI8_QUP_SRC 197 +#define GSBI8_QUP_CLK 198 +#define GSBI9_QUP_SRC 199 +#define GSBI9_QUP_CLK 200 +#define GSBI10_QUP_SRC 201 +#define GSBI10_QUP_CLK 202 +#define GSBI11_QUP_SRC 203 +#define GSBI11_QUP_CLK 204 +#define GSBI12_QUP_SRC 205 +#define GSBI12_QUP_CLK 206 +#define GSBI1_SIM_CLK 207 +#define GSBI2_SIM_CLK 208 +#define GSBI3_SIM_CLK 209 +#define GSBI4_SIM_CLK 210 +#define GSBI5_SIM_CLK 211 +#define GSBI6_SIM_CLK 212 +#define GSBI7_SIM_CLK 213 +#define GSBI8_SIM_CLK 214 +#define GSBI9_SIM_CLK 215 +#define GSBI10_SIM_CLK 216 +#define GSBI11_SIM_CLK 217 +#define GSBI12_SIM_CLK 218 +#define USB_HSIC_HSIC_CLK_SRC 219 +#define USB_HSIC_HSIC_CLK 220 +#define USB_HSIC_HSIO_CAL_CLK 221 +#define SPDM_CFG_H_CLK 222 +#define SPDM_MSTR_H_CLK 223 +#define SPDM_FF_CLK_SRC 224 +#define SPDM_FF_CLK 225 +#define SEC_CTRL_CLK 226 +#define SEC_CTRL_ACC_CLK_SRC 227 +#define SEC_CTRL_ACC_CLK 228 +#define TLMM_H_CLK 229 +#define TLMM_CLK 230 +#define SFAB_MSS_S_H_CLK 231 +#define MSS_SLP_CLK 232 +#define MSS_Q6SW_JTAG_CLK 233 +#define MSS_Q6FW_JTAG_CLK 234 +#define MSS_S_H_CLK 235 +#define MSS_CXO_SRC_CLK 236 +#define SATA_H_CLK 237 +#define SATA_CLK_SRC 238 +#define SATA_RXOOB_CLK 239 +#define SATA_PMALIVE_CLK 240 +#define SATA_PHY_REF_CLK 241 +#define TSSC_CLK_SRC 242 +#define TSSC_CLK 243 +#define PDM_SRC 244 +#define PDM_CLK 245 +#define GP0_SRC 246 +#define GP0_CLK 247 +#define GP1_SRC 248 +#define GP1_CLK 249 +#define GP2_SRC 250 +#define GP2_CLK 251 +#define MPM_CLK 252 +#define EBI1_CLK_SRC 253 +#define EBI1_CH0_CLK 254 +#define EBI1_CH1_CLK 255 +#define EBI1_2X_CLK 256 +#define EBI1_CH0_DQ_CLK 257 +#define EBI1_CH1_DQ_CLK 258 +#define EBI1_CH0_CA_CLK 259 +#define EBI1_CH1_CA_CLK 260 +#define EBI1_XO_CLK 261 +#define SFAB_SMPSS_S_H_CLK 262 +#define PRNG_SRC 263 +#define PRNG_CLK 264 +#define PXO_SRC 265 +#define LPASS_CXO_CLK 266 +#define LPASS_PXO_CLK 267 +#define SPDM_CY_PORT0_CLK 268 +#define SPDM_CY_PORT1_CLK 269 +#define SPDM_CY_PORT2_CLK 270 +#define SPDM_CY_PORT3_CLK 271 +#define SPDM_CY_PORT4_CLK 272 +#define SPDM_CY_PORT5_CLK 273 +#define SPDM_CY_PORT6_CLK 274 +#define SPDM_CY_PORT7_CLK 275 +#define PLL0 276 +#define PLL0_VOTE 277 +#define PLL3 278 +#define PLL3_VOTE 279 +#define PLL4_VOTE 280 +#define PLL5 281 +#define PLL5_VOTE 282 +#define PLL6 283 +#define PLL6_VOTE 284 +#define PLL7_VOTE 285 +#define PLL8 286 +#define PLL8_VOTE 287 +#define PLL9 288 +#define PLL10 289 +#define PLL11 290 +#define PLL12 291 +#define PLL13 292 +#define PLL14 293 +#define PLL14_VOTE 294 +#define USB_HS3_H_CLK 295 +#define USB_HS3_XCVR_SRC 296 +#define USB_HS3_XCVR_CLK 297 +#define USB_HS4_H_CLK 298 +#define USB_HS4_XCVR_SRC 299 +#define USB_HS4_XCVR_CLK 300 +#define SATA_PHY_CFG_CLK 301 +#define SATA_A_CLK 302 +#define CE3_SRC 303 +#define CE3_CORE_CLK 304 +#define CE3_H_CLK 305 +#define USB_HS1_SYSTEM_CLK_SRC 306 +#define USB_HS1_SYSTEM_CLK 307 + +#endif diff --git a/include/dt-bindings/clock/qcom,lcc-mdm9615.h b/include/dt-bindings/clock/qcom,lcc-mdm9615.h new file mode 100644 index 0000000..cac963a --- /dev/null +++ b/include/dt-bindings/clock/qcom,lcc-mdm9615.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) BayLibre, SAS. + * Author : Neil Armstrong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_LCC_MDM9615_H +#define _DT_BINDINGS_CLK_LCC_MDM9615_H + +#define PLL4 0 +#define MI2S_OSR_SRC 1 +#define MI2S_OSR_CLK 2 +#define MI2S_DIV_CLK 3 +#define MI2S_BIT_DIV_CLK 4 +#define MI2S_BIT_CLK 5 +#define PCM_SRC 6 +#define PCM_CLK_OUT 7 +#define PCM_CLK 8 +#define SLIMBUS_SRC 9 +#define AUDIO_SLIMBUS_CLK 10 +#define SPS_SLIMBUS_CLK 11 +#define CODEC_I2S_MIC_OSR_SRC 12 +#define CODEC_I2S_MIC_OSR_CLK 13 +#define CODEC_I2S_MIC_DIV_CLK 14 +#define CODEC_I2S_MIC_BIT_DIV_CLK 15 +#define CODEC_I2S_MIC_BIT_CLK 16 +#define SPARE_I2S_MIC_OSR_SRC 17 +#define SPARE_I2S_MIC_OSR_CLK 18 +#define SPARE_I2S_MIC_DIV_CLK 19 +#define SPARE_I2S_MIC_BIT_DIV_CLK 20 +#define SPARE_I2S_MIC_BIT_CLK 21 +#define CODEC_I2S_SPKR_OSR_SRC 22 +#define CODEC_I2S_SPKR_OSR_CLK 23 +#define CODEC_I2S_SPKR_DIV_CLK 24 +#define CODEC_I2S_SPKR_BIT_DIV_CLK 25 +#define CODEC_I2S_SPKR_BIT_CLK 26 +#define SPARE_I2S_SPKR_OSR_SRC 27 +#define SPARE_I2S_SPKR_OSR_CLK 28 +#define SPARE_I2S_SPKR_DIV_CLK 29 +#define SPARE_I2S_SPKR_BIT_DIV_CLK 30 +#define SPARE_I2S_SPKR_BIT_CLK 31 + +#endif diff --git a/include/dt-bindings/reset/qcom,gcc-mdm9615.h b/include/dt-bindings/reset/qcom,gcc-mdm9615.h new file mode 100644 index 0000000..7f86e9a --- /dev/null +++ b/include/dt-bindings/reset/qcom,gcc-mdm9615.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) BayLibre, SAS. + * Author : Neil Armstrong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_RESET_GCC_MDM9615_H +#define _DT_BINDINGS_RESET_GCC_MDM9615_H + +#define SFAB_MSS_Q6_SW_RESET 0 +#define SFAB_MSS_Q6_FW_RESET 1 +#define QDSS_STM_RESET 2 +#define AFAB_SMPSS_S_RESET 3 +#define AFAB_SMPSS_M1_RESET 4 +#define AFAB_SMPSS_M0_RESET 5 +#define AFAB_EBI1_CH0_RESET 6 +#define AFAB_EBI1_CH1_RESET 7 +#define SFAB_ADM0_M0_RESET 8 +#define SFAB_ADM0_M1_RESET 9 +#define SFAB_ADM0_M2_RESET 10 +#define ADM0_C2_RESET 11 +#define ADM0_C1_RESET 12 +#define ADM0_C0_RESET 13 +#define ADM0_PBUS_RESET 14 +#define ADM0_RESET 15 +#define QDSS_CLKS_SW_RESET 16 +#define QDSS_POR_RESET 17 +#define QDSS_TSCTR_RESET 18 +#define QDSS_HRESET_RESET 19 +#define QDSS_AXI_RESET 20 +#define QDSS_DBG_RESET 21 +#define PCIE_A_RESET 22 +#define PCIE_AUX_RESET 23 +#define PCIE_H_RESET 24 +#define SFAB_PCIE_M_RESET 25 +#define SFAB_PCIE_S_RESET 26 +#define SFAB_MSS_M_RESET 27 +#define SFAB_USB3_M_RESET 28 +#define SFAB_RIVA_M_RESET 29 +#define SFAB_LPASS_RESET 30 +#define SFAB_AFAB_M_RESET 31 +#define AFAB_SFAB_M0_RESET 32 +#define AFAB_SFAB_M1_RESET 33 +#define SFAB_SATA_S_RESET 34 +#define SFAB_DFAB_M_RESET 35 +#define DFAB_SFAB_M_RESET 36 +#define DFAB_SWAY0_RESET 37 +#define DFAB_SWAY1_RESET 38 +#define DFAB_ARB0_RESET 39 +#define DFAB_ARB1_RESET 40 +#define PPSS_PROC_RESET 41 +#define PPSS_RESET 42 +#define DMA_BAM_RESET 43 +#define SPS_TIC_H_RESET 44 +#define SLIMBUS_H_RESET 45 +#define SFAB_CFPB_M_RESET 46 +#define SFAB_CFPB_S_RESET 47 +#define TSIF_H_RESET 48 +#define CE1_H_RESET 49 +#define CE1_CORE_RESET 50 +#define CE1_SLEEP_RESET 51 +#define CE2_H_RESET 52 +#define CE2_CORE_RESET 53 +#define SFAB_SFPB_M_RESET 54 +#define SFAB_SFPB_S_RESET 55 +#define RPM_PROC_RESET 56 +#define PMIC_SSBI2_RESET 57 +#define SDC1_RESET 58 +#define SDC2_RESET 59 +#define SDC3_RESET 60 +#define SDC4_RESET 61 +#define SDC5_RESET 62 +#define DFAB_A2_RESET 63 +#define USB_HS1_RESET 64 +#define USB_HSIC_RESET 65 +#define USB_FS1_XCVR_RESET 66 +#define USB_FS1_RESET 67 +#define USB_FS2_XCVR_RESET 68 +#define USB_FS2_RESET 69 +#define GSBI1_RESET 70 +#define GSBI2_RESET 71 +#define GSBI3_RESET 72 +#define GSBI4_RESET 73 +#define GSBI5_RESET 74 +#define GSBI6_RESET 75 +#define GSBI7_RESET 76 +#define GSBI8_RESET 77 +#define GSBI9_RESET 78 +#define GSBI10_RESET 79 +#define GSBI11_RESET 80 +#define GSBI12_RESET 81 +#define SPDM_RESET 82 +#define TLMM_H_RESET 83 +#define SFAB_MSS_S_RESET 84 +#define MSS_SLP_RESET 85 +#define MSS_Q6SW_JTAG_RESET 86 +#define MSS_Q6FW_JTAG_RESET 87 +#define MSS_RESET 88 +#define SATA_H_RESET 89 +#define SATA_RXOOB_RESE 90 +#define SATA_PMALIVE_RESET 91 +#define SATA_SFAB_M_RESET 92 +#define TSSC_RESET 93 +#define PDM_RESET 94 +#define MPM_H_RESET 95 +#define MPM_RESET 96 +#define SFAB_SMPSS_S_RESET 97 +#define PRNG_RESET 98 +#define RIVA_RESET 99 +#define USB_HS3_RESET 100 +#define USB_HS4_RESET 101 +#define CE3_RESET 102 +#define PCIE_EXT_PCI_RESET 103 +#define PCIE_PHY_RESET 104 +#define PCIE_PCI_RESET 105 +#define PCIE_POR_RESET 106 +#define PCIE_HCLK_RESET 107 +#define PCIE_ACLK_RESET 108 +#define CE3_H_RESET 109 +#define SFAB_CE3_M_RESET 110 +#define SFAB_CE3_S_RESET 111 +#define SATA_RESET 112 +#define CE3_SLEEP_RESET 113 +#define GSS_SLP_RESET 114 +#define GSS_RESET 115 + +#endif -- cgit v0.10.2 From 7792a8d6713c33758636c252bd6ff7c8c001de12 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 11 Aug 2016 14:48:04 +0200 Subject: clk: mdm9615: Add support for MDM9615 Clock Controllers In order to support the Qualcomm MDM9615 SoC, add support for the Global and LPASS Clock Controllers. Signed-off-by: Neil Armstrong Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 95e3b3e..1e7c86f 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -87,6 +87,23 @@ config MSM_LCC_8960 Say Y if you want to use audio devices such as i2s, pcm, SLIMBus, etc. +config MDM_GCC_9615 + tristate "MDM9615 Global Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on mdm9615 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2c, USB, SD/eMMC, etc. + +config MDM_LCC_9615 + tristate "MDM9615 LPASS Clock Controller" + select MDM_GCC_9615 + depends on COMMON_CLK_QCOM + help + Support for the LPASS clock controller on mdm9615 devices. + Say Y if you want to use audio devices such as i2s, pcm, + SLIMBus, etc. + config MSM_MMCC_8960 tristate "MSM8960 Multimedia Clock Controller" select MSM_GCC_8960 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 2a25f4e..15ab44e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -26,3 +26,5 @@ obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o +obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o +obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c new file mode 100644 index 0000000..0f648fc --- /dev/null +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -0,0 +1,1727 @@ +/* + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) BayLibre, SAS. + * Author : Neil Armstrong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" + +static struct clk_fixed_factor cxo = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "cxo", + .parent_names = (const char *[]){ "cxo_board" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_pll pll0 = { + .l_reg = 0x30c4, + .m_reg = 0x30c8, + .n_reg = 0x30cc, + .config_reg = 0x30d4, + .mode_reg = 0x30c0, + .status_reg = 0x30d8, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll0", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap pll0_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "pll0_vote", + .parent_names = (const char *[]){ "pll8" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static struct clk_regmap pll4_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "pll4_vote", + .parent_names = (const char *[]){ "pll4" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static struct clk_pll pll8 = { + .l_reg = 0x3144, + .m_reg = 0x3148, + .n_reg = 0x314c, + .config_reg = 0x3154, + .mode_reg = 0x3140, + .status_reg = 0x3158, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll8", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap pll8_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "pll8_vote", + .parent_names = (const char *[]){ "pll8" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static struct clk_pll pll14 = { + .l_reg = 0x31c4, + .m_reg = 0x31c8, + .n_reg = 0x31cc, + .config_reg = 0x31d4, + .mode_reg = 0x31c0, + .status_reg = 0x31d8, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll14", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap pll14_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pll14_vote", + .parent_names = (const char *[]){ "pll14" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +enum { + P_CXO, + P_PLL8, + P_PLL14, +}; + +static const struct parent_map gcc_cxo_pll8_map[] = { + { P_CXO, 0 }, + { P_PLL8, 3 } +}; + +static const char * const gcc_cxo_pll8[] = { + "cxo", + "pll8_vote", +}; + +static const struct parent_map gcc_cxo_pll14_map[] = { + { P_CXO, 0 }, + { P_PLL14, 4 } +}; + +static const char * const gcc_cxo_pll14[] = { + "cxo", + "pll14_vote", +}; + +static const struct parent_map gcc_cxo_map[] = { + { P_CXO, 0 }, +}; + +static const char * const gcc_cxo[] = { + "cxo", +}; + +static struct freq_tbl clk_tbl_gsbi_uart[] = { + { 1843200, P_PLL8, 2, 6, 625 }, + { 3686400, P_PLL8, 2, 12, 625 }, + { 7372800, P_PLL8, 2, 24, 625 }, + { 14745600, P_PLL8, 2, 48, 625 }, + { 16000000, P_PLL8, 4, 1, 6 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 32000000, P_PLL8, 4, 1, 3 }, + { 40000000, P_PLL8, 1, 5, 48 }, + { 46400000, P_PLL8, 1, 29, 240 }, + { 48000000, P_PLL8, 4, 1, 2 }, + { 51200000, P_PLL8, 1, 2, 15 }, + { 56000000, P_PLL8, 1, 7, 48 }, + { 58982400, P_PLL8, 1, 96, 625 }, + { 64000000, P_PLL8, 2, 1, 3 }, + { } +}; + +static struct clk_rcg gsbi1_uart_src = { + .ns_reg = 0x29d4, + .md_reg = 0x29d0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x29d4, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi1_uart_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x29d4, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_uart_clk", + .parent_names = (const char *[]){ + "gsbi1_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi2_uart_src = { + .ns_reg = 0x29f4, + .md_reg = 0x29f0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x29f4, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi2_uart_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 6, + .clkr = { + .enable_reg = 0x29f4, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_uart_clk", + .parent_names = (const char *[]){ + "gsbi2_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi3_uart_src = { + .ns_reg = 0x2a14, + .md_reg = 0x2a10, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x2a14, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi3_uart_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 2, + .clkr = { + .enable_reg = 0x2a14, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_uart_clk", + .parent_names = (const char *[]){ + "gsbi3_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi4_uart_src = { + .ns_reg = 0x2a34, + .md_reg = 0x2a30, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x2a34, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi4_uart_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 26, + .clkr = { + .enable_reg = 0x2a34, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_uart_clk", + .parent_names = (const char *[]){ + "gsbi4_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi5_uart_src = { + .ns_reg = 0x2a54, + .md_reg = 0x2a50, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_uart, + .clkr = { + .enable_reg = 0x2a54, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_uart_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi5_uart_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 22, + .clkr = { + .enable_reg = 0x2a54, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_uart_clk", + .parent_names = (const char *[]){ + "gsbi5_uart_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl clk_tbl_gsbi_qup[] = { + { 960000, P_CXO, 4, 1, 5 }, + { 4800000, P_CXO, 4, 0, 1 }, + { 9600000, P_CXO, 2, 0, 1 }, + { 15060000, P_PLL8, 1, 2, 51 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 25600000, P_PLL8, 1, 1, 15 }, + { 48000000, P_PLL8, 4, 1, 2 }, + { 51200000, P_PLL8, 1, 2, 15 }, + { } +}; + +static struct clk_rcg gsbi1_qup_src = { + .ns_reg = 0x29cc, + .md_reg = 0x29c8, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x29cc, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi1_qup_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 9, + .clkr = { + .enable_reg = 0x29cc, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_qup_clk", + .parent_names = (const char *[]){ "gsbi1_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi2_qup_src = { + .ns_reg = 0x29ec, + .md_reg = 0x29e8, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x29ec, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi2_qup_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 4, + .clkr = { + .enable_reg = 0x29ec, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_qup_clk", + .parent_names = (const char *[]){ "gsbi2_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi3_qup_src = { + .ns_reg = 0x2a0c, + .md_reg = 0x2a08, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x2a0c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi3_qup_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 0, + .clkr = { + .enable_reg = 0x2a0c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_qup_clk", + .parent_names = (const char *[]){ "gsbi3_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi4_qup_src = { + .ns_reg = 0x2a2c, + .md_reg = 0x2a28, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x2a2c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi4_qup_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 24, + .clkr = { + .enable_reg = 0x2a2c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_qup_clk", + .parent_names = (const char *[]){ "gsbi4_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gsbi5_qup_src = { + .ns_reg = 0x2a4c, + .md_reg = 0x2a48, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_gsbi_qup, + .clkr = { + .enable_reg = 0x2a4c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_qup_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + }, +}; + +static struct clk_branch gsbi5_qup_clk = { + .halt_reg = 0x2fd0, + .halt_bit = 20, + .clkr = { + .enable_reg = 0x2a4c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_qup_clk", + .parent_names = (const char *[]){ "gsbi5_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_gp[] = { + { 9600000, P_CXO, 2, 0, 0 }, + { 19200000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct clk_rcg gp0_src = { + .ns_reg = 0x2d24, + .md_reg = 0x2d00, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_map, + }, + .freq_tbl = clk_tbl_gp, + .clkr = { + .enable_reg = 0x2d24, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp0_src", + .parent_names = gcc_cxo, + .num_parents = 1, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, + } +}; + +static struct clk_branch gp0_clk = { + .halt_reg = 0x2fd8, + .halt_bit = 7, + .clkr = { + .enable_reg = 0x2d24, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp0_clk", + .parent_names = (const char *[]){ "gp0_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gp1_src = { + .ns_reg = 0x2d44, + .md_reg = 0x2d40, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_map, + }, + .freq_tbl = clk_tbl_gp, + .clkr = { + .enable_reg = 0x2d44, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp1_src", + .parent_names = gcc_cxo, + .num_parents = 1, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch gp1_clk = { + .halt_reg = 0x2fd8, + .halt_bit = 6, + .clkr = { + .enable_reg = 0x2d44, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp1_clk", + .parent_names = (const char *[]){ "gp1_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg gp2_src = { + .ns_reg = 0x2d64, + .md_reg = 0x2d60, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_map, + }, + .freq_tbl = clk_tbl_gp, + .clkr = { + .enable_reg = 0x2d64, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp2_src", + .parent_names = gcc_cxo, + .num_parents = 1, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch gp2_clk = { + .halt_reg = 0x2fd8, + .halt_bit = 5, + .clkr = { + .enable_reg = 0x2d64, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp2_clk", + .parent_names = (const char *[]){ "gp2_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch pmem_clk = { + .hwcg_reg = 0x25a0, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 20, + .clkr = { + .enable_reg = 0x25a0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "pmem_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_rcg prng_src = { + .ns_reg = 0x2e80, + .p = { + .pre_div_shift = 3, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "prng_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch prng_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "prng_clk", + .parent_names = (const char *[]){ "prng_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + }, + }, +}; + +static const struct freq_tbl clk_tbl_sdc[] = { + { 144000, P_CXO, 1, 1, 133 }, + { 400000, P_PLL8, 4, 1, 240 }, + { 16000000, P_PLL8, 4, 1, 6 }, + { 17070000, P_PLL8, 1, 2, 45 }, + { 20210000, P_PLL8, 1, 1, 19 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 38400000, P_PLL8, 2, 1, 5 }, + { 48000000, P_PLL8, 4, 1, 2 }, + { 64000000, P_PLL8, 3, 1, 2 }, + { 76800000, P_PLL8, 1, 1, 5 }, + { } +}; + +static struct clk_rcg sdc1_src = { + .ns_reg = 0x282c, + .md_reg = 0x2828, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_sdc, + .clkr = { + .enable_reg = 0x282c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch sdc1_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 6, + .clkr = { + .enable_reg = 0x282c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_clk", + .parent_names = (const char *[]){ "sdc1_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg sdc2_src = { + .ns_reg = 0x284c, + .md_reg = 0x2848, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_sdc, + .clkr = { + .enable_reg = 0x284c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "sdc2_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch sdc2_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 5, + .clkr = { + .enable_reg = 0x284c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "sdc2_clk", + .parent_names = (const char *[]){ "sdc2_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb[] = { + { 60000000, P_PLL8, 1, 5, 32 }, + { } +}; + +static struct clk_rcg usb_hs1_xcvr_src = { + .ns_reg = 0x290c, + .md_reg = 0x2908, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb, + .clkr = { + .enable_reg = 0x290c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hs1_xcvr_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 0, + .clkr = { + .enable_reg = 0x290c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_clk", + .parent_names = (const char *[]){ "usb_hs1_xcvr_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg usb_hsic_xcvr_fs_src = { + .ns_reg = 0x2928, + .md_reg = 0x2924, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb, + .clkr = { + .enable_reg = 0x2928, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_xcvr_fs_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hsic_xcvr_fs_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 9, + .clkr = { + .enable_reg = 0x2928, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_xcvr_fs_clk", + .parent_names = + (const char *[]){ "usb_hsic_xcvr_fs_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb_hs1_system[] = { + { 60000000, P_PLL8, 1, 5, 32 }, + { } +}; + +static struct clk_rcg usb_hs1_system_src = { + .ns_reg = 0x36a4, + .md_reg = 0x36a0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb_hs1_system, + .clkr = { + .enable_reg = 0x36a4, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_system_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hs1_system_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 4, + .clkr = { + .enable_reg = 0x36a4, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .parent_names = + (const char *[]){ "usb_hs1_system_src" }, + .num_parents = 1, + .name = "usb_hs1_system_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb_hsic_system[] = { + { 64000000, P_PLL8, 1, 1, 6 }, + { } +}; + +static struct clk_rcg usb_hsic_system_src = { + .ns_reg = 0x2b58, + .md_reg = 0x2b54, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll8_map, + }, + .freq_tbl = clk_tbl_usb_hsic_system, + .clkr = { + .enable_reg = 0x2b58, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_system_src", + .parent_names = gcc_cxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hsic_system_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 7, + .clkr = { + .enable_reg = 0x2b58, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .parent_names = + (const char *[]){ "usb_hsic_system_src" }, + .num_parents = 1, + .name = "usb_hsic_system_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_usb_hsic_hsic[] = { + { 48000000, P_PLL14, 1, 0, 0 }, + { } +}; + +static struct clk_rcg usb_hsic_hsic_src = { + .ns_reg = 0x2b50, + .md_reg = 0x2b4c, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = gcc_cxo_pll14_map, + }, + .freq_tbl = clk_tbl_usb_hsic_hsic, + .clkr = { + .enable_reg = 0x2b50, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_hsic_src", + .parent_names = gcc_cxo_pll14, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + } +}; + +static struct clk_branch usb_hsic_hsic_clk = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x2b50, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "usb_hsic_hsic_src" }, + .num_parents = 1, + .name = "usb_hsic_hsic_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch usb_hsic_hsio_cal_clk = { + .halt_reg = 0x2fc8, + .halt_bit = 8, + .clkr = { + .enable_reg = 0x2b48, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .name = "usb_hsic_hsio_cal_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch ce1_core_clk = { + .hwcg_reg = 0x2724, + .hwcg_bit = 6, + .halt_reg = 0x2fd4, + .halt_bit = 27, + .clkr = { + .enable_reg = 0x2724, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "ce1_core_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch ce1_h_clk = { + .halt_reg = 0x2fd4, + .halt_bit = 1, + .clkr = { + .enable_reg = 0x2720, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "ce1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch dma_bam_h_clk = { + .hwcg_reg = 0x25c0, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 12, + .clkr = { + .enable_reg = 0x25c0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "dma_bam_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi1_h_clk = { + .hwcg_reg = 0x29c0, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 11, + .clkr = { + .enable_reg = 0x29c0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi2_h_clk = { + .hwcg_reg = 0x29e0, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 7, + .clkr = { + .enable_reg = 0x29e0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi3_h_clk = { + .hwcg_reg = 0x2a00, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 3, + .clkr = { + .enable_reg = 0x2a00, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi3_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi4_h_clk = { + .hwcg_reg = 0x2a20, + .hwcg_bit = 6, + .halt_reg = 0x2fd0, + .halt_bit = 27, + .clkr = { + .enable_reg = 0x2a20, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch gsbi5_h_clk = { + .hwcg_reg = 0x2a40, + .hwcg_bit = 6, + .halt_reg = 0x2fd0, + .halt_bit = 23, + .clkr = { + .enable_reg = 0x2a40, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch usb_hs1_h_clk = { + .hwcg_reg = 0x2900, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 1, + .clkr = { + .enable_reg = 0x2900, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch usb_hsic_h_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 28, + .clkr = { + .enable_reg = 0x2920, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb_hsic_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch sdc1_h_clk = { + .hwcg_reg = 0x2820, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 11, + .clkr = { + .enable_reg = 0x2820, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch sdc2_h_clk = { + .hwcg_reg = 0x2840, + .hwcg_bit = 6, + .halt_reg = 0x2fc8, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x2840, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "sdc2_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch adm0_clk = { + .halt_reg = 0x2fdc, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 14, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "adm0_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch adm0_pbus_clk = { + .hwcg_reg = 0x2208, + .hwcg_bit = 6, + .halt_reg = 0x2fdc, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 13, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "adm0_pbus_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch pmic_arb0_h_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 22, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "pmic_arb0_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch pmic_arb1_h_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 21, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pmic_arb1_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch pmic_ssbi2_clk = { + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 23, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "pmic_ssbi2_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_branch rpm_msg_ram_h_clk = { + .hwcg_reg = 0x27e0, + .hwcg_bit = 6, + .halt_reg = 0x2fd8, + .halt_check = BRANCH_HALT_VOTED, + .halt_bit = 12, + .clkr = { + .enable_reg = 0x3080, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "rpm_msg_ram_h_clk", + .ops = &clk_branch_ops, + }, + }, +}; + +static struct clk_hw *gcc_mdm9615_hws[] = { + &cxo.hw, +}; + +static struct clk_regmap *gcc_mdm9615_clks[] = { + [PLL0] = &pll0.clkr, + [PLL0_VOTE] = &pll0_vote, + [PLL4_VOTE] = &pll4_vote, + [PLL8] = &pll8.clkr, + [PLL8_VOTE] = &pll8_vote, + [PLL14] = &pll14.clkr, + [PLL14_VOTE] = &pll14_vote, + [GSBI1_UART_SRC] = &gsbi1_uart_src.clkr, + [GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr, + [GSBI2_UART_SRC] = &gsbi2_uart_src.clkr, + [GSBI2_UART_CLK] = &gsbi2_uart_clk.clkr, + [GSBI3_UART_SRC] = &gsbi3_uart_src.clkr, + [GSBI3_UART_CLK] = &gsbi3_uart_clk.clkr, + [GSBI4_UART_SRC] = &gsbi4_uart_src.clkr, + [GSBI4_UART_CLK] = &gsbi4_uart_clk.clkr, + [GSBI5_UART_SRC] = &gsbi5_uart_src.clkr, + [GSBI5_UART_CLK] = &gsbi5_uart_clk.clkr, + [GSBI1_QUP_SRC] = &gsbi1_qup_src.clkr, + [GSBI1_QUP_CLK] = &gsbi1_qup_clk.clkr, + [GSBI2_QUP_SRC] = &gsbi2_qup_src.clkr, + [GSBI2_QUP_CLK] = &gsbi2_qup_clk.clkr, + [GSBI3_QUP_SRC] = &gsbi3_qup_src.clkr, + [GSBI3_QUP_CLK] = &gsbi3_qup_clk.clkr, + [GSBI4_QUP_SRC] = &gsbi4_qup_src.clkr, + [GSBI4_QUP_CLK] = &gsbi4_qup_clk.clkr, + [GSBI5_QUP_SRC] = &gsbi5_qup_src.clkr, + [GSBI5_QUP_CLK] = &gsbi5_qup_clk.clkr, + [GP0_SRC] = &gp0_src.clkr, + [GP0_CLK] = &gp0_clk.clkr, + [GP1_SRC] = &gp1_src.clkr, + [GP1_CLK] = &gp1_clk.clkr, + [GP2_SRC] = &gp2_src.clkr, + [GP2_CLK] = &gp2_clk.clkr, + [PMEM_A_CLK] = &pmem_clk.clkr, + [PRNG_SRC] = &prng_src.clkr, + [PRNG_CLK] = &prng_clk.clkr, + [SDC1_SRC] = &sdc1_src.clkr, + [SDC1_CLK] = &sdc1_clk.clkr, + [SDC2_SRC] = &sdc2_src.clkr, + [SDC2_CLK] = &sdc2_clk.clkr, + [USB_HS1_XCVR_SRC] = &usb_hs1_xcvr_src.clkr, + [USB_HS1_XCVR_CLK] = &usb_hs1_xcvr_clk.clkr, + [USB_HS1_SYSTEM_CLK_SRC] = &usb_hs1_system_src.clkr, + [USB_HS1_SYSTEM_CLK] = &usb_hs1_system_clk.clkr, + [USB_HSIC_XCVR_FS_SRC] = &usb_hsic_xcvr_fs_src.clkr, + [USB_HSIC_XCVR_FS_CLK] = &usb_hsic_xcvr_fs_clk.clkr, + [USB_HSIC_SYSTEM_CLK_SRC] = &usb_hsic_system_src.clkr, + [USB_HSIC_SYSTEM_CLK] = &usb_hsic_system_clk.clkr, + [USB_HSIC_HSIC_CLK_SRC] = &usb_hsic_hsic_src.clkr, + [USB_HSIC_HSIC_CLK] = &usb_hsic_hsic_clk.clkr, + [USB_HSIC_HSIO_CAL_CLK] = &usb_hsic_hsio_cal_clk.clkr, + [CE1_CORE_CLK] = &ce1_core_clk.clkr, + [CE1_H_CLK] = &ce1_h_clk.clkr, + [DMA_BAM_H_CLK] = &dma_bam_h_clk.clkr, + [GSBI1_H_CLK] = &gsbi1_h_clk.clkr, + [GSBI2_H_CLK] = &gsbi2_h_clk.clkr, + [GSBI3_H_CLK] = &gsbi3_h_clk.clkr, + [GSBI4_H_CLK] = &gsbi4_h_clk.clkr, + [GSBI5_H_CLK] = &gsbi5_h_clk.clkr, + [USB_HS1_H_CLK] = &usb_hs1_h_clk.clkr, + [USB_HSIC_H_CLK] = &usb_hsic_h_clk.clkr, + [SDC1_H_CLK] = &sdc1_h_clk.clkr, + [SDC2_H_CLK] = &sdc2_h_clk.clkr, + [ADM0_CLK] = &adm0_clk.clkr, + [ADM0_PBUS_CLK] = &adm0_pbus_clk.clkr, + [PMIC_ARB0_H_CLK] = &pmic_arb0_h_clk.clkr, + [PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr, + [PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr, + [RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr, +}; + +static const struct qcom_reset_map gcc_mdm9615_resets[] = { + [DMA_BAM_RESET] = { 0x25c0, 7 }, + [CE1_H_RESET] = { 0x2720, 7 }, + [CE1_CORE_RESET] = { 0x2724, 7 }, + [SDC1_RESET] = { 0x2830 }, + [SDC2_RESET] = { 0x2850 }, + [ADM0_C2_RESET] = { 0x220c, 4 }, + [ADM0_C1_RESET] = { 0x220c, 3 }, + [ADM0_C0_RESET] = { 0x220c, 2 }, + [ADM0_PBUS_RESET] = { 0x220c, 1 }, + [ADM0_RESET] = { 0x220c }, + [USB_HS1_RESET] = { 0x2910 }, + [USB_HSIC_RESET] = { 0x2934 }, + [GSBI1_RESET] = { 0x29dc }, + [GSBI2_RESET] = { 0x29fc }, + [GSBI3_RESET] = { 0x2a1c }, + [GSBI4_RESET] = { 0x2a3c }, + [GSBI5_RESET] = { 0x2a5c }, + [PDM_RESET] = { 0x2CC0, 12 }, +}; + +static const struct regmap_config gcc_mdm9615_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x3660, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_mdm9615_desc = { + .config = &gcc_mdm9615_regmap_config, + .clks = gcc_mdm9615_clks, + .num_clks = ARRAY_SIZE(gcc_mdm9615_clks), + .resets = gcc_mdm9615_resets, + .num_resets = ARRAY_SIZE(gcc_mdm9615_resets), +}; + +static const struct of_device_id gcc_mdm9615_match_table[] = { + { .compatible = "qcom,gcc-mdm9615" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_mdm9615_match_table); + +static int gcc_mdm9615_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *regmap; + struct clk *clk; + int i; + + regmap = qcom_cc_map(pdev, &gcc_mdm9615_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + for (i = 0; i < ARRAY_SIZE(gcc_mdm9615_hws); i++) { + clk = devm_clk_register(dev, gcc_mdm9615_hws[i]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + } + + return qcom_cc_really_probe(pdev, &gcc_mdm9615_desc, regmap); +} + +static struct platform_driver gcc_mdm9615_driver = { + .probe = gcc_mdm9615_probe, + .driver = { + .name = "gcc-mdm9615", + .of_match_table = gcc_mdm9615_match_table, + }, +}; + +static int __init gcc_mdm9615_init(void) +{ + return platform_driver_register(&gcc_mdm9615_driver); +} +core_initcall(gcc_mdm9615_init); + +static void __exit gcc_mdm9615_exit(void) +{ + platform_driver_unregister(&gcc_mdm9615_driver); +} +module_exit(gcc_mdm9615_exit); + +MODULE_DESCRIPTION("QCOM GCC MDM9615 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gcc-mdm9615"); diff --git a/drivers/clk/qcom/lcc-mdm9615.c b/drivers/clk/qcom/lcc-mdm9615.c new file mode 100644 index 0000000..3237ef4 --- /dev/null +++ b/drivers/clk/qcom/lcc-mdm9615.c @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) BayLibre, SAS. + * Author : Neil Armstrong + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" + +static struct clk_pll pll4 = { + .l_reg = 0x4, + .m_reg = 0x8, + .n_reg = 0xc, + .config_reg = 0x14, + .mode_reg = 0x0, + .status_reg = 0x18, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll4", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +enum { + P_CXO, + P_PLL4, +}; + +static const struct parent_map lcc_cxo_pll4_map[] = { + { P_CXO, 0 }, + { P_PLL4, 2 } +}; + +static const char * const lcc_cxo_pll4[] = { + "cxo", + "pll4_vote", +}; + +static struct freq_tbl clk_tbl_aif_osr_492[] = { + { 512000, P_PLL4, 4, 1, 240 }, + { 768000, P_PLL4, 4, 1, 160 }, + { 1024000, P_PLL4, 4, 1, 120 }, + { 1536000, P_PLL4, 4, 1, 80 }, + { 2048000, P_PLL4, 4, 1, 60 }, + { 3072000, P_PLL4, 4, 1, 40 }, + { 4096000, P_PLL4, 4, 1, 30 }, + { 6144000, P_PLL4, 4, 1, 20 }, + { 8192000, P_PLL4, 4, 1, 15 }, + { 12288000, P_PLL4, 4, 1, 10 }, + { 24576000, P_PLL4, 4, 1, 5 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct freq_tbl clk_tbl_aif_osr_393[] = { + { 512000, P_PLL4, 4, 1, 192 }, + { 768000, P_PLL4, 4, 1, 128 }, + { 1024000, P_PLL4, 4, 1, 96 }, + { 1536000, P_PLL4, 4, 1, 64 }, + { 2048000, P_PLL4, 4, 1, 48 }, + { 3072000, P_PLL4, 4, 1, 32 }, + { 4096000, P_PLL4, 4, 1, 24 }, + { 6144000, P_PLL4, 4, 1, 16 }, + { 8192000, P_PLL4, 4, 1, 12 }, + { 12288000, P_PLL4, 4, 1, 8 }, + { 24576000, P_PLL4, 4, 1, 4 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct clk_rcg mi2s_osr_src = { + .ns_reg = 0x48, + .md_reg = 0x4c, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = lcc_cxo_pll4_map, + }, + .freq_tbl = clk_tbl_aif_osr_393, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_osr_src", + .parent_names = lcc_cxo_pll4, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, +}; + +static const char * const lcc_mi2s_parents[] = { + "mi2s_osr_src", +}; + +static struct clk_branch mi2s_osr_clk = { + .halt_reg = 0x50, + .halt_bit = 1, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_osr_clk", + .parent_names = lcc_mi2s_parents, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap_div mi2s_div_clk = { + .reg = 0x48, + .shift = 10, + .width = 4, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_div_clk", + .parent_names = lcc_mi2s_parents, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_branch mi2s_bit_div_clk = { + .halt_reg = 0x50, + .halt_bit = 0, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0x48, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_bit_div_clk", + .parent_names = (const char *[]){ "mi2s_div_clk" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap_mux mi2s_bit_clk = { + .reg = 0x48, + .shift = 14, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mi2s_bit_clk", + .parent_names = (const char *[]){ + "mi2s_bit_div_clk", + "mi2s_codec_clk", + }, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr) \ +static struct clk_rcg prefix##_osr_src = { \ + .ns_reg = _ns, \ + .md_reg = _md, \ + .mn = { \ + .mnctr_en_bit = 8, \ + .mnctr_reset_bit = 7, \ + .mnctr_mode_shift = 5, \ + .n_val_shift = 24, \ + .m_val_shift = 8, \ + .width = 8, \ + }, \ + .p = { \ + .pre_div_shift = 3, \ + .pre_div_width = 2, \ + }, \ + .s = { \ + .src_sel_shift = 0, \ + .parent_map = lcc_cxo_pll4_map, \ + }, \ + .freq_tbl = clk_tbl_aif_osr_393, \ + .clkr = { \ + .enable_reg = _ns, \ + .enable_mask = BIT(9), \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_osr_src", \ + .parent_names = lcc_cxo_pll4, \ + .num_parents = 2, \ + .ops = &clk_rcg_ops, \ + .flags = CLK_SET_RATE_GATE, \ + }, \ + }, \ +}; \ + \ +static const char * const lcc_##prefix##_parents[] = { \ + #prefix "_osr_src", \ +}; \ + \ +static struct clk_branch prefix##_osr_clk = { \ + .halt_reg = hr, \ + .halt_bit = 1, \ + .halt_check = BRANCH_HALT_ENABLE, \ + .clkr = { \ + .enable_reg = _ns, \ + .enable_mask = BIT(21), \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_osr_clk", \ + .parent_names = lcc_##prefix##_parents, \ + .num_parents = 1, \ + .ops = &clk_branch_ops, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ + }, \ +}; \ + \ +static struct clk_regmap_div prefix##_div_clk = { \ + .reg = _ns, \ + .shift = 10, \ + .width = 8, \ + .clkr = { \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_div_clk", \ + .parent_names = lcc_##prefix##_parents, \ + .num_parents = 1, \ + .ops = &clk_regmap_div_ops, \ + }, \ + }, \ +}; \ + \ +static struct clk_branch prefix##_bit_div_clk = { \ + .halt_reg = hr, \ + .halt_bit = 0, \ + .halt_check = BRANCH_HALT_ENABLE, \ + .clkr = { \ + .enable_reg = _ns, \ + .enable_mask = BIT(19), \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_bit_div_clk", \ + .parent_names = (const char *[]){ \ + #prefix "_div_clk" \ + }, \ + .num_parents = 1, \ + .ops = &clk_branch_ops, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ + }, \ +}; \ + \ +static struct clk_regmap_mux prefix##_bit_clk = { \ + .reg = _ns, \ + .shift = 18, \ + .width = 1, \ + .clkr = { \ + .hw.init = &(struct clk_init_data){ \ + .name = #prefix "_bit_clk", \ + .parent_names = (const char *[]){ \ + #prefix "_bit_div_clk", \ + #prefix "_codec_clk", \ + }, \ + .num_parents = 2, \ + .ops = &clk_regmap_mux_closest_ops, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ + }, \ +} + +CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68); +CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80); +CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74); +CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c); + +static struct freq_tbl clk_tbl_pcm_492[] = { + { 256000, P_PLL4, 4, 1, 480 }, + { 512000, P_PLL4, 4, 1, 240 }, + { 768000, P_PLL4, 4, 1, 160 }, + { 1024000, P_PLL4, 4, 1, 120 }, + { 1536000, P_PLL4, 4, 1, 80 }, + { 2048000, P_PLL4, 4, 1, 60 }, + { 3072000, P_PLL4, 4, 1, 40 }, + { 4096000, P_PLL4, 4, 1, 30 }, + { 6144000, P_PLL4, 4, 1, 20 }, + { 8192000, P_PLL4, 4, 1, 15 }, + { 12288000, P_PLL4, 4, 1, 10 }, + { 24576000, P_PLL4, 4, 1, 5 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct freq_tbl clk_tbl_pcm_393[] = { + { 256000, P_PLL4, 4, 1, 384 }, + { 512000, P_PLL4, 4, 1, 192 }, + { 768000, P_PLL4, 4, 1, 128 }, + { 1024000, P_PLL4, 4, 1, 96 }, + { 1536000, P_PLL4, 4, 1, 64 }, + { 2048000, P_PLL4, 4, 1, 48 }, + { 3072000, P_PLL4, 4, 1, 32 }, + { 4096000, P_PLL4, 4, 1, 24 }, + { 6144000, P_PLL4, 4, 1, 16 }, + { 8192000, P_PLL4, 4, 1, 12 }, + { 12288000, P_PLL4, 4, 1, 8 }, + { 24576000, P_PLL4, 4, 1, 4 }, + { 27000000, P_CXO, 1, 0, 0 }, + { } +}; + +static struct clk_rcg pcm_src = { + .ns_reg = 0x54, + .md_reg = 0x58, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 16, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = lcc_cxo_pll4_map, + }, + .freq_tbl = clk_tbl_pcm_393, + .clkr = { + .enable_reg = 0x54, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pcm_src", + .parent_names = lcc_cxo_pll4, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, +}; + +static struct clk_branch pcm_clk_out = { + .halt_reg = 0x5c, + .halt_bit = 0, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0x54, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pcm_clk_out", + .parent_names = (const char *[]){ "pcm_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap_mux pcm_clk = { + .reg = 0x54, + .shift = 10, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "pcm_clk", + .parent_names = (const char *[]){ + "pcm_clk_out", + "pcm_codec_clk", + }, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg slimbus_src = { + .ns_reg = 0xcc, + .md_reg = 0xd0, + .mn = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = lcc_cxo_pll4_map, + }, + .freq_tbl = clk_tbl_aif_osr_393, + .clkr = { + .enable_reg = 0xcc, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "slimbus_src", + .parent_names = lcc_cxo_pll4, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, +}; + +static const char * const lcc_slimbus_parents[] = { + "slimbus_src", +}; + +static struct clk_branch audio_slimbus_clk = { + .halt_reg = 0xd4, + .halt_bit = 0, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0xcc, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "audio_slimbus_clk", + .parent_names = lcc_slimbus_parents, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch sps_slimbus_clk = { + .halt_reg = 0xd4, + .halt_bit = 1, + .halt_check = BRANCH_HALT_ENABLE, + .clkr = { + .enable_reg = 0xcc, + .enable_mask = BIT(12), + .hw.init = &(struct clk_init_data){ + .name = "sps_slimbus_clk", + .parent_names = lcc_slimbus_parents, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap *lcc_mdm9615_clks[] = { + [PLL4] = &pll4.clkr, + [MI2S_OSR_SRC] = &mi2s_osr_src.clkr, + [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr, + [MI2S_DIV_CLK] = &mi2s_div_clk.clkr, + [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr, + [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr, + [PCM_SRC] = &pcm_src.clkr, + [PCM_CLK_OUT] = &pcm_clk_out.clkr, + [PCM_CLK] = &pcm_clk.clkr, + [SLIMBUS_SRC] = &slimbus_src.clkr, + [AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr, + [SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr, + [CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr, + [CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr, + [CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr, + [CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr, + [CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr, + [SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr, + [SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr, + [SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr, + [SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr, + [SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr, + [CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr, + [CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr, + [CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr, + [CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr, + [CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr, + [SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr, + [SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr, + [SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr, + [SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr, + [SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr, +}; + +static const struct regmap_config lcc_mdm9615_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xfc, + .fast_io = true, +}; + +static const struct qcom_cc_desc lcc_mdm9615_desc = { + .config = &lcc_mdm9615_regmap_config, + .clks = lcc_mdm9615_clks, + .num_clks = ARRAY_SIZE(lcc_mdm9615_clks), +}; + +static const struct of_device_id lcc_mdm9615_match_table[] = { + { .compatible = "qcom,lcc-mdm9615" }, + { } +}; +MODULE_DEVICE_TABLE(of, lcc_mdm9615_match_table); + +static int lcc_mdm9615_probe(struct platform_device *pdev) +{ + u32 val; + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &lcc_mdm9615_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Use the correct frequency plan depending on speed of PLL4 */ + regmap_read(regmap, 0x4, &val); + if (val == 0x12) { + slimbus_src.freq_tbl = clk_tbl_aif_osr_492; + mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492; + codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492; + spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492; + codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492; + spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492; + pcm_src.freq_tbl = clk_tbl_pcm_492; + } + /* Enable PLL4 source on the LPASS Primary PLL Mux */ + regmap_write(regmap, 0xc4, 0x1); + + return qcom_cc_really_probe(pdev, &lcc_mdm9615_desc, regmap); +} + +static struct platform_driver lcc_mdm9615_driver = { + .probe = lcc_mdm9615_probe, + .driver = { + .name = "lcc-mdm9615", + .of_match_table = lcc_mdm9615_match_table, + }, +}; +module_platform_driver(lcc_mdm9615_driver); + +MODULE_DESCRIPTION("QCOM LCC MDM9615 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:lcc-mdm9615"); -- cgit v0.10.2 From 3e99c7ab16af52be826cfd4a8be5b525dd38ccc9 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 11 Aug 2016 14:48:05 +0200 Subject: dt-bindings: clock: Update bindings for MDM9615 GCC and LCC Acked-by: Rob Herring Signed-off-by: Neil Armstrong Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 9a60fde..869a2f0 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -15,6 +15,7 @@ Required properties : "qcom,gcc-msm8974pro" "qcom,gcc-msm8974pro-ac" "qcom,gcc-msm8996" + "qcom,gcc-mdm9615" - reg : shall contain base register location and length - #clock-cells : shall contain 1 diff --git a/Documentation/devicetree/bindings/clock/qcom,lcc.txt b/Documentation/devicetree/bindings/clock/qcom,lcc.txt index dd755be..a3c78aa 100644 --- a/Documentation/devicetree/bindings/clock/qcom,lcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,lcc.txt @@ -7,6 +7,7 @@ Required properties : "qcom,lcc-msm8960" "qcom,lcc-apq8064" "qcom,lcc-ipq8064" + "qcom,lcc-mdm9615" - reg : shall contain base register location and length - #clock-cells : shall contain 1 -- cgit v0.10.2 From 7e6a3a1d79fe9bb9b9daacb59e9b5c35f71570f5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 15 Aug 2016 16:09:04 -0700 Subject: clk: qcom: Sort Makefile alphabetically We've started getting out of order, fix it. Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 15ab44e..1fb1f54 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -12,19 +12,20 @@ clk-qcom-y += clk-regmap-mux.o clk-qcom-y += reset.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o +# Keep alphabetically sorted by config obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o +obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o +obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o -obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o +obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o -obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o -obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o -- cgit v0.10.2 From 57c4a2ac8f55e6648c36a1df8c4919f06d08d66e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 16 Aug 2016 08:53:10 +0200 Subject: clk: gcc-ipq4019: Delete unnecessary assignment for the field "owner" The field "owner" is set by the core. Thus delete an unneeded initialisation. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Markus Elfring Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index 3cd1af0..b593065 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -1332,7 +1332,6 @@ static struct platform_driver gcc_ipq4019_driver = { .probe = gcc_ipq4019_probe, .driver = { .name = "qcom,gcc-ipq4019", - .owner = THIS_MODULE, .of_match_table = gcc_ipq4019_match_table, }, }; -- cgit v0.10.2 From f6475e29829775fb2d28add14246f755b44cd68d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Aug 2016 15:40:52 -0700 Subject: clk: berlin: Migrate to clk_hw based registration and OF APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. We also remove some __init markings in header files as they're useless and we're in the area. Tested-by: Jisheng Zhang Cc: Alexandre Belloni Acked-by: Sebastian Hesselbarth Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/berlin/berlin2-avpll.c b/drivers/clk/berlin/berlin2-avpll.c index fd0f26c..cfcae46 100644 --- a/drivers/clk/berlin/berlin2-avpll.c +++ b/drivers/clk/berlin/berlin2-avpll.c @@ -188,7 +188,7 @@ static const struct clk_ops berlin2_avpll_vco_ops = { .recalc_rate = berlin2_avpll_vco_recalc_rate, }; -struct clk * __init berlin2_avpll_vco_register(void __iomem *base, +int __init berlin2_avpll_vco_register(void __iomem *base, const char *name, const char *parent_name, u8 vco_flags, unsigned long flags) { @@ -197,7 +197,7 @@ struct clk * __init berlin2_avpll_vco_register(void __iomem *base, vco = kzalloc(sizeof(*vco), GFP_KERNEL); if (!vco) - return ERR_PTR(-ENOMEM); + return -ENOMEM; vco->base = base; vco->flags = vco_flags; @@ -208,7 +208,7 @@ struct clk * __init berlin2_avpll_vco_register(void __iomem *base, init.num_parents = 1; init.flags = flags; - return clk_register(NULL, &vco->hw); + return clk_hw_register(NULL, &vco->hw); } struct berlin2_avpll_channel { @@ -364,7 +364,7 @@ static const struct clk_ops berlin2_avpll_channel_ops = { */ static const u8 quirk_index[] __initconst = { 0, 6, 5, 4, 3, 2, 1, 7 }; -struct clk * __init berlin2_avpll_channel_register(void __iomem *base, +int __init berlin2_avpll_channel_register(void __iomem *base, const char *name, u8 index, const char *parent_name, u8 ch_flags, unsigned long flags) { @@ -373,7 +373,7 @@ struct clk * __init berlin2_avpll_channel_register(void __iomem *base, ch = kzalloc(sizeof(*ch), GFP_KERNEL); if (!ch) - return ERR_PTR(-ENOMEM); + return -ENOMEM; ch->base = base; if (ch_flags & BERLIN2_AVPLL_SCRAMBLE_QUIRK) @@ -389,5 +389,5 @@ struct clk * __init berlin2_avpll_channel_register(void __iomem *base, init.num_parents = 1; init.flags = flags; - return clk_register(NULL, &ch->hw); + return clk_hw_register(NULL, &ch->hw); } diff --git a/drivers/clk/berlin/berlin2-avpll.h b/drivers/clk/berlin/berlin2-avpll.h index a37f506..17e3111 100644 --- a/drivers/clk/berlin/berlin2-avpll.h +++ b/drivers/clk/berlin/berlin2-avpll.h @@ -19,17 +19,13 @@ #ifndef __BERLIN2_AVPLL_H #define __BERLIN2_AVPLL_H -struct clk; - #define BERLIN2_AVPLL_BIT_QUIRK BIT(0) #define BERLIN2_AVPLL_SCRAMBLE_QUIRK BIT(1) -struct clk * __init -berlin2_avpll_vco_register(void __iomem *base, const char *name, +int berlin2_avpll_vco_register(void __iomem *base, const char *name, const char *parent_name, u8 vco_flags, unsigned long flags); -struct clk * __init -berlin2_avpll_channel_register(void __iomem *base, const char *name, +int berlin2_avpll_channel_register(void __iomem *base, const char *name, u8 index, const char *parent_name, u8 ch_flags, unsigned long flags); diff --git a/drivers/clk/berlin/berlin2-div.c b/drivers/clk/berlin/berlin2-div.c index 81ff97f..41ab2d3 100644 --- a/drivers/clk/berlin/berlin2-div.c +++ b/drivers/clk/berlin/berlin2-div.c @@ -234,7 +234,7 @@ static const struct clk_ops berlin2_div_mux_ops = { .get_parent = berlin2_div_get_parent, }; -struct clk * __init +struct clk_hw * __init berlin2_div_register(const struct berlin2_div_map *map, void __iomem *base, const char *name, u8 div_flags, const char **parent_names, int num_parents, @@ -259,7 +259,7 @@ berlin2_div_register(const struct berlin2_div_map *map, if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0) mux_ops = NULL; - return clk_register_composite(NULL, name, parent_names, num_parents, + return clk_hw_register_composite(NULL, name, parent_names, num_parents, &div->hw, mux_ops, &div->hw, rate_ops, &div->hw, gate_ops, flags); } diff --git a/drivers/clk/berlin/berlin2-div.h b/drivers/clk/berlin/berlin2-div.h index 15e3384..e835ddf 100644 --- a/drivers/clk/berlin/berlin2-div.h +++ b/drivers/clk/berlin/berlin2-div.h @@ -19,7 +19,7 @@ #ifndef __BERLIN2_DIV_H #define __BERLIN2_DIV_H -struct clk; +struct clk_hw; #define BERLIN2_DIV_HAS_GATE BIT(0) #define BERLIN2_DIV_HAS_MUX BIT(1) @@ -80,7 +80,7 @@ struct berlin2_div_data { u8 div_flags; }; -struct clk * __init +struct clk_hw * berlin2_div_register(const struct berlin2_div_map *map, void __iomem *base, const char *name, u8 div_flags, const char **parent_names, int num_parents, diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c index 1c2294d..4ffbe80 100644 --- a/drivers/clk/berlin/berlin2-pll.c +++ b/drivers/clk/berlin/berlin2-pll.c @@ -84,7 +84,7 @@ static const struct clk_ops berlin2_pll_ops = { .recalc_rate = berlin2_pll_recalc_rate, }; -struct clk * __init +int __init berlin2_pll_register(const struct berlin2_pll_map *map, void __iomem *base, const char *name, const char *parent_name, unsigned long flags) @@ -94,7 +94,7 @@ berlin2_pll_register(const struct berlin2_pll_map *map, pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) - return ERR_PTR(-ENOMEM); + return -ENOMEM; /* copy pll_map to allow __initconst */ memcpy(&pll->map, map, sizeof(*map)); @@ -106,5 +106,5 @@ berlin2_pll_register(const struct berlin2_pll_map *map, init.num_parents = 1; init.flags = flags; - return clk_register(NULL, &pll->hw); + return clk_hw_register(NULL, &pll->hw); } diff --git a/drivers/clk/berlin/berlin2-pll.h b/drivers/clk/berlin/berlin2-pll.h index 8831ce2..583e024 100644 --- a/drivers/clk/berlin/berlin2-pll.h +++ b/drivers/clk/berlin/berlin2-pll.h @@ -19,8 +19,6 @@ #ifndef __BERLIN2_PLL_H #define __BERLIN2_PLL_H -struct clk; - struct berlin2_pll_map { const u8 vcodiv[16]; u8 mult; @@ -29,9 +27,8 @@ struct berlin2_pll_map { u8 divsel_shift; }; -struct clk * __init -berlin2_pll_register(const struct berlin2_pll_map *map, - void __iomem *base, const char *name, - const char *parent_name, unsigned long flags); +int berlin2_pll_register(const struct berlin2_pll_map *map, + void __iomem *base, const char *name, + const char *parent_name, unsigned long flags); #endif /* __BERLIN2_PLL_H */ diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c index 23e0e3b..edf3b96 100644 --- a/drivers/clk/berlin/bg2.c +++ b/drivers/clk/berlin/bg2.c @@ -92,8 +92,7 @@ */ #define MAX_CLKS 41 -static struct clk *clks[MAX_CLKS]; -static struct clk_onecell_data clk_data; +static struct clk_hw_onecell_data *clk_data; static DEFINE_SPINLOCK(lock); static void __iomem *gbase; @@ -505,8 +504,17 @@ static void __init berlin2_clock_setup(struct device_node *np) struct device_node *parent_np = of_get_parent(np); const char *parent_names[9]; struct clk *clk; + struct clk_hw *hw; + struct clk_hw **hws; u8 avpll_flags = 0; - int n; + int n, ret; + + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + if (!clk_data) + return; + clk_data->num = MAX_CLKS; + hws = clk_data->hws; gbase = of_iomap(parent_np, 0); if (!gbase) @@ -526,118 +534,118 @@ static void __init berlin2_clock_setup(struct device_node *np) } /* simple register PLLs */ - clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, + ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, clk_names[SYSPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; - clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, + ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, clk_names[MEMPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; - clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, + ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, clk_names[CPUPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; if (of_device_is_compatible(np, "marvell,berlin2-global-register")) avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK; /* audio/video VCOs */ - clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", + ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", clk_names[REFCLK], avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; for (n = 0; n < 8; n++) { - clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, + ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, clk_names[AVPLL_A1 + n], n, "avpll_vcoA", avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; } - clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", + ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; for (n = 0; n < 8; n++) { - clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, + ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, clk_names[AVPLL_B1 + n], n, "avpll_vcoB", BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); - if (IS_ERR(clk)) + if (ret) goto bg2_fail; } /* reference clock bypass switches */ parent_names[0] = clk_names[SYSPLL]; parent_names[1] = clk_names[REFCLK]; - clk = clk_register_mux(NULL, "syspll_byp", parent_names, 2, + hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; - clk_names[SYSPLL] = __clk_get_name(clk); + clk_names[SYSPLL] = clk_hw_get_name(hw); parent_names[0] = clk_names[MEMPLL]; parent_names[1] = clk_names[REFCLK]; - clk = clk_register_mux(NULL, "mempll_byp", parent_names, 2, + hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; - clk_names[MEMPLL] = __clk_get_name(clk); + clk_names[MEMPLL] = clk_hw_get_name(hw); parent_names[0] = clk_names[CPUPLL]; parent_names[1] = clk_names[REFCLK]; - clk = clk_register_mux(NULL, "cpupll_byp", parent_names, 2, + hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; - clk_names[CPUPLL] = __clk_get_name(clk); + clk_names[CPUPLL] = clk_hw_get_name(hw); /* clock muxes */ parent_names[0] = clk_names[AVPLL_B3]; parent_names[1] = clk_names[AVPLL_A3]; - clk = clk_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO0_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; - clk = clk_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO1_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; - clk = clk_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[AVPLL_A2]; parent_names[1] = clk_names[AVPLL_B2]; - clk = clk_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO2_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; - clk = clk_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[AVPLL_B1]; parent_names[1] = clk_names[AVPLL_A5]; - clk = clk_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, + hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto bg2_fail; /* clock divider cells */ @@ -648,7 +656,7 @@ static void __init berlin2_clock_setup(struct device_node *np) for (k = 0; k < dd->num_parents; k++) parent_names[k] = clk_names[dd->parent_ids[k]]; - clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, + hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, dd->name, dd->div_flags, parent_names, dd->num_parents, dd->flags, &lock); } @@ -657,18 +665,18 @@ static void __init berlin2_clock_setup(struct device_node *np) for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) { const struct berlin2_gate_data *gd = &bg2_gates[n]; - clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name, + hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags, gbase + REG_CLKENABLE, gd->bit_idx, 0, &lock); } /* twdclk is derived from cpu/3 */ - clks[CLKID_TWD] = - clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); + hws[CLKID_TWD] = + clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { - if (!IS_ERR(clks[n])) + if (!IS_ERR(hws[n])) continue; pr_err("%s: Unable to register leaf clock %d\n", @@ -677,9 +685,7 @@ static void __init berlin2_clock_setup(struct device_node *np) } /* register clk-provider */ - clk_data.clks = clks; - clk_data.clk_num = MAX_CLKS; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); return; diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c index f144547..0718e83 100644 --- a/drivers/clk/berlin/bg2q.c +++ b/drivers/clk/berlin/bg2q.c @@ -46,8 +46,7 @@ #define REG_SDIO1XIN_CLKCTL 0x015c #define MAX_CLKS 28 -static struct clk *clks[MAX_CLKS]; -static struct clk_onecell_data clk_data; +static struct clk_hw_onecell_data *clk_data; static DEFINE_SPINLOCK(lock); static void __iomem *gbase; static void __iomem *cpupll_base; @@ -293,7 +292,15 @@ static void __init berlin2q_clock_setup(struct device_node *np) struct device_node *parent_np = of_get_parent(np); const char *parent_names[9]; struct clk *clk; - int n; + struct clk_hw **hws; + int n, ret; + + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + if (!clk_data) + return; + clk_data->num = MAX_CLKS; + hws = clk_data->hws; gbase = of_iomap(parent_np, 0); if (!gbase) { @@ -317,14 +324,14 @@ static void __init berlin2q_clock_setup(struct device_node *np) } /* simple register PLLs */ - clk = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, + ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, clk_names[SYSPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2q_fail; - clk = berlin2_pll_register(&bg2q_pll_map, cpupll_base, + ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base, clk_names[CPUPLL], clk_names[REFCLK], 0); - if (IS_ERR(clk)) + if (ret) goto bg2q_fail; /* TODO: add BG2Q AVPLL */ @@ -342,7 +349,7 @@ static void __init berlin2q_clock_setup(struct device_node *np) for (k = 0; k < dd->num_parents; k++) parent_names[k] = clk_names[dd->parent_ids[k]]; - clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, + hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, dd->name, dd->div_flags, parent_names, dd->num_parents, dd->flags, &lock); } @@ -351,22 +358,22 @@ static void __init berlin2q_clock_setup(struct device_node *np) for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) { const struct berlin2_gate_data *gd = &bg2q_gates[n]; - clks[CLKID_GFX2DAXI + n] = clk_register_gate(NULL, gd->name, + hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags, gbase + REG_CLKENABLE, gd->bit_idx, 0, &lock); } /* cpuclk divider is fixed to 1 */ - clks[CLKID_CPU] = - clk_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL], + hws[CLKID_CPU] = + clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL], 0, 1, 1); /* twdclk is derived from cpu/3 */ - clks[CLKID_TWD] = - clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); + hws[CLKID_TWD] = + clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { - if (!IS_ERR(clks[n])) + if (!IS_ERR(hws[n])) continue; pr_err("%s: Unable to register leaf clock %d\n", @@ -375,9 +382,7 @@ static void __init berlin2q_clock_setup(struct device_node *np) } /* register clk-provider */ - clk_data.clks = clks; - clk_data.clk_num = MAX_CLKS; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); return; -- cgit v0.10.2 From 9b4cac33adc7716bb232b3a82a5ed0806286fe9a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Aug 2016 15:38:56 -0700 Subject: clk: max77686: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Cc: Laxman Dewangan Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 19f6208..b637f59 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -62,9 +62,8 @@ struct max77686_clk_init_data { struct max77686_clk_driver_data { enum max77686_chip_name chip; - struct clk **clks; struct max77686_clk_init_data *max_clk_data; - struct clk_onecell_data of_data; + size_t num_clks; }; static const struct @@ -160,6 +159,20 @@ static struct clk_ops max77686_clk_ops = { .recalc_rate = max77686_recalc_rate, }; +static struct clk_hw * +of_clk_max77686_get(struct of_phandle_args *clkspec, void *data) +{ + struct max77686_clk_driver_data *drv_data = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= drv_data->num_clks) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &drv_data->max_clk_data[idx].hw; +} + static int max77686_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -209,14 +222,8 @@ static int max77686_clk_probe(struct platform_device *pdev) if (!drv_data->max_clk_data) return -ENOMEM; - drv_data->clks = devm_kcalloc(dev, num_clks, - sizeof(*drv_data->clks), GFP_KERNEL); - if (!drv_data->clks) - return -ENOMEM; - for (i = 0; i < num_clks; i++) { struct max77686_clk_init_data *max_clk_data; - struct clk *clk; const char *clk_name; max_clk_data = &drv_data->max_clk_data[i]; @@ -236,30 +243,23 @@ static int max77686_clk_probe(struct platform_device *pdev) max_clk_data->hw.init = &max_clk_data->clk_idata; - clk = devm_clk_register(dev, &max_clk_data->hw); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + ret = devm_clk_hw_register(dev, &max_clk_data->hw); + if (ret) { dev_err(dev, "Failed to clock register: %d\n", ret); return ret; } - ret = clk_register_clkdev(clk, max_clk_data->clk_idata.name, - NULL); + ret = clk_hw_register_clkdev(&max_clk_data->hw, + max_clk_data->clk_idata.name, NULL); if (ret < 0) { dev_err(dev, "Failed to clkdev register: %d\n", ret); return ret; } - drv_data->clks[i] = clk; } - platform_set_drvdata(pdev, drv_data); - if (parent->of_node) { - drv_data->of_data.clks = drv_data->clks; - drv_data->of_data.clk_num = num_clks; - ret = of_clk_add_provider(parent->of_node, - of_clk_src_onecell_get, - &drv_data->of_data); + ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get, + drv_data); if (ret < 0) { dev_err(dev, "Failed to register OF clock provider: %d\n", -- cgit v0.10.2 From 8964193f6bfda5c4cf14eedb7e94892c1f1c34f0 Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Mon, 15 Aug 2016 15:28:20 +0800 Subject: clk: qoriq: fix a register offset error The offset of Core Cluster clock control/status register on cluster group V3 version is different from others, and should be plus 0x70000. Signed-off-by: Tang Yuantian Reviewed-by: Scott Wood Fixes: 9e19ca2f627e ("clk: qoriq: Add ls2080a support.") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 58566a17..20b1055 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -766,7 +766,11 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx) if (!hwc) return NULL; - hwc->reg = cg->regs + 0x20 * idx; + if (cg->info.flags & CG_VER3) + hwc->reg = cg->regs + 0x70000 + 0x20 * idx; + else + hwc->reg = cg->regs + 0x20 * idx; + hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]]; /* -- cgit v0.10.2 From 944b9a41e004534f3634335aa1d6bec16700028f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:15 -0700 Subject: clk: ls1x: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Kelvin Cheung Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c index 5097831..8430e45 100644 --- a/drivers/clk/clk-ls1x.c +++ b/drivers/clk/clk-ls1x.c @@ -48,13 +48,13 @@ static const struct clk_ops ls1x_pll_clk_ops = { .recalc_rate = ls1x_pll_recalc_rate, }; -static struct clk *__init clk_register_pll(struct device *dev, - const char *name, - const char *parent_name, - unsigned long flags) +static struct clk_hw *__init clk_hw_register_pll(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags) { + int ret; struct clk_hw *hw; - struct clk *clk; struct clk_init_data init; /* allocate the divider */ @@ -72,12 +72,13 @@ static struct clk *__init clk_register_pll(struct device *dev, hw->init = &init; /* register the clock */ - clk = clk_register(dev, hw); - - if (IS_ERR(clk)) + ret = clk_hw_register(dev, hw); + if (ret) { kfree(hw); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; @@ -86,14 +87,14 @@ static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; void __init ls1x_clk_init(void) { - struct clk *clk; + struct clk_hw *hw; - clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); - clk_register_clkdev(clk, "osc_33m_clk", NULL); + hw = clk_hw_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); + clk_hw_register_clkdev(hw, "osc_33m_clk", NULL); /* clock derived from 33 MHz OSC clk */ - clk = clk_register_pll(NULL, "pll_clk", "osc_33m_clk", 0); - clk_register_clkdev(clk, "pll_clk", NULL); + hw = clk_hw_register_pll(NULL, "pll_clk", "osc_33m_clk", 0); + clk_hw_register_clkdev(hw, "pll_clk", NULL); /* clock derived from PLL clk */ /* _____ @@ -102,17 +103,17 @@ void __init ls1x_clk_init(void) * \___ PLL ___ CPU DIV ___| | * |_____| */ - clk = clk_register_divider(NULL, "cpu_clk_div", "pll_clk", + hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT, DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST, &_lock); - clk_register_clkdev(clk, "cpu_clk_div", NULL); - clk = clk_register_mux(NULL, "cpu_clk", cpu_parents, + clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, ARRAY_SIZE(cpu_parents), CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); - clk_register_clkdev(clk, "cpu_clk", NULL); + clk_hw_register_clkdev(hw, "cpu_clk", NULL); /* _____ * _______________________| | @@ -120,15 +121,15 @@ void __init ls1x_clk_init(void) * \___ PLL ___ DC DIV ___| | * |_____| */ - clk = clk_register_divider(NULL, "dc_clk_div", "pll_clk", + hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_register_clkdev(clk, "dc_clk_div", NULL); - clk = clk_register_mux(NULL, "dc_clk", dc_parents, + clk_hw_register_clkdev(hw, "dc_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, ARRAY_SIZE(dc_parents), CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); - clk_register_clkdev(clk, "dc_clk", NULL); + clk_hw_register_clkdev(hw, "dc_clk", NULL); /* _____ * _______________________| | @@ -136,26 +137,26 @@ void __init ls1x_clk_init(void) * \___ PLL ___ DDR DIV ___| | * |_____| */ - clk = clk_register_divider(NULL, "ahb_clk_div", "pll_clk", + hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_register_clkdev(clk, "ahb_clk_div", NULL); - clk = clk_register_mux(NULL, "ahb_clk", ahb_parents, + clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, ARRAY_SIZE(ahb_parents), CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); - clk_register_clkdev(clk, "ahb_clk", NULL); - clk_register_clkdev(clk, "stmmaceth", NULL); + clk_hw_register_clkdev(hw, "ahb_clk", NULL); + clk_hw_register_clkdev(hw, "stmmaceth", NULL); /* clock derived from AHB clk */ /* APB clk is always half of the AHB clk */ - clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, + hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, DIV_APB); - clk_register_clkdev(clk, "apb_clk", NULL); - clk_register_clkdev(clk, "ls1x_i2c", NULL); - clk_register_clkdev(clk, "ls1x_pwmtimer", NULL); - clk_register_clkdev(clk, "ls1x_spi", NULL); - clk_register_clkdev(clk, "ls1x_wdt", NULL); - clk_register_clkdev(clk, "serial8250", NULL); + clk_hw_register_clkdev(hw, "apb_clk", NULL); + clk_hw_register_clkdev(hw, "ls1x_i2c", NULL); + clk_hw_register_clkdev(hw, "ls1x_pwmtimer", NULL); + clk_hw_register_clkdev(hw, "ls1x_spi", NULL); + clk_hw_register_clkdev(hw, "ls1x_wdt", NULL); + clk_hw_register_clkdev(hw, "serial8250", NULL); } -- cgit v0.10.2 From 928f3bfb81e81e7f3ce6d37857a1ae075475678d Mon Sep 17 00:00:00 2001 From: James Liao Date: Tue, 16 Aug 2016 15:30:21 +0800 Subject: clk: mediatek: remove __init from clk registration functions Remove __init from functions that will be used by init functions that support probe deferral. Signed-off-by: James Liao Signed-off-by: Erin Lo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 2a76901..d8787bf 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -97,7 +97,7 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = { .disable = mtk_cg_disable_inv, }; -struct clk * __init mtk_clk_register_gate( +struct clk *mtk_clk_register_gate( const char *name, const char *parent_name, struct regmap *regmap, diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 5ada644..bb30f70 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -24,7 +24,7 @@ #include "clk-mtk.h" #include "clk-gate.h" -struct clk_onecell_data * __init mtk_alloc_clk_data(unsigned int clk_num) +struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num) { int i; struct clk_onecell_data *clk_data; @@ -49,7 +49,7 @@ err_out: return NULL; } -void __init mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, +void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num, struct clk_onecell_data *clk_data) { int i; @@ -72,7 +72,7 @@ void __init mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, } } -void __init mtk_clk_register_factors(const struct mtk_fixed_factor *clks, +void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, struct clk_onecell_data *clk_data) { int i; @@ -95,7 +95,7 @@ void __init mtk_clk_register_factors(const struct mtk_fixed_factor *clks, } } -int __init mtk_clk_register_gates(struct device_node *node, +int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, int num, struct clk_onecell_data *clk_data) { @@ -135,7 +135,7 @@ int __init mtk_clk_register_gates(struct device_node *node, return 0; } -struct clk * __init mtk_clk_register_composite(const struct mtk_composite *mc, +struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, void __iomem *base, spinlock_t *lock) { struct clk *clk; @@ -222,7 +222,7 @@ err_out: return ERR_PTR(ret); } -void __init mtk_clk_register_composites(const struct mtk_composite *mcs, +void mtk_clk_register_composites(const struct mtk_composite *mcs, int num, void __iomem *base, spinlock_t *lock, struct clk_onecell_data *clk_data) { diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 966cab1..0c2deac 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -313,7 +313,7 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, return clk; } -void __init mtk_clk_register_plls(struct device_node *node, +void mtk_clk_register_plls(struct device_node *node, const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data) { void __iomem *base; -- cgit v0.10.2 From 4e09508a8912b8d2183240bdda14e2e48b4e3176 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Wed, 17 Aug 2016 13:31:50 +0200 Subject: clk: renesas: r8a7796: Add GPIO clocks Add GPIO clocks for the R8A7796 SoC. Signed-off-by: Takeshi Kihara Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index c0dee76..999955c 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -106,6 +106,14 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("scif2", 310, R8A7796_CLK_S3D4), DEF_MOD("rwdt0", 402, R8A7796_CLK_R), DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1), + DEF_MOD("gpio7", 905, R8A7796_CLK_S3D4), + DEF_MOD("gpio6", 906, R8A7796_CLK_S3D4), + DEF_MOD("gpio5", 907, R8A7796_CLK_S3D4), + DEF_MOD("gpio4", 908, R8A7796_CLK_S3D4), + DEF_MOD("gpio3", 909, R8A7796_CLK_S3D4), + DEF_MOD("gpio2", 910, R8A7796_CLK_S3D4), + DEF_MOD("gpio1", 911, R8A7796_CLK_S3D4), + DEF_MOD("gpio0", 912, R8A7796_CLK_S3D4), }; static const unsigned int r8a7796_crit_mod_clks[] __initconst = { -- cgit v0.10.2 From 2886c84681c4a10a8fecdea58bf749af09406a33 Mon Sep 17 00:00:00 2001 From: James Liao Date: Fri, 19 Aug 2016 13:34:49 +0800 Subject: clk: mediatek: Refine the makefile to support multiple clock drivers Add a Kconfig to define clock configuration for each SoC, and modify the Makefile to build drivers that only selected in config. Signed-off-by: Shunli Wang Signed-off-by: James Liao Signed-off-by: Erin Lo Tested-by: John Crispin Reviewed-by: Matthias Brugger Signed-off-by: Stephen Boyd diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index b3ee99a..bf7d540 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -200,6 +200,7 @@ config COMMON_CLK_OXNAS source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" +source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig new file mode 100644 index 0000000..380c372 --- /dev/null +++ b/drivers/clk/mediatek/Kconfig @@ -0,0 +1,21 @@ +# +# MediaTek SoC drivers +# +config COMMON_CLK_MEDIATEK + bool + ---help--- + Mediatek SoCs' clock support. + +config COMMON_CLK_MT8135 + bool "Clock driver for Mediatek MT8135" + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + ---help--- + This driver supports Mediatek MT8135 clocks. + +config COMMON_CLK_MT8173 + bool "Clock driver for Mediatek MT8173" + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + ---help--- + This driver supports Mediatek MT8173 clocks. diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 95fdfac..32e7222 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -1,4 +1,4 @@ -obj-y += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o +obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o -obj-y += clk-mt8135.o -obj-y += clk-mt8173.o +obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o +obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o -- cgit v0.10.2 From 6a5887030a4a92cd27cfa1aee5be2a8c137975fa Mon Sep 17 00:00:00 2001 From: James Liao Date: Fri, 19 Aug 2016 13:34:50 +0800 Subject: dt-bindings: ARM: Mediatek: Document bindings for MT2701 This patch adds the binding documentation for apmixedsys, bdpsys, ethsys, hifsys, imgsys, infracfg, mmsys, pericfg, topckgen and vdecsys for Mediatek MT2701. Signed-off-by: James Liao Signed-off-by: Erin Lo Tested-by: John Crispin Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt index 936166f..cb0054a 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt @@ -5,7 +5,8 @@ The Mediatek apmixedsys controller provides the PLLs to the system. Required Properties: -- compatible: Should be: +- compatible: Should be one of: + - "mediatek,mt2701-apmixedsys" - "mediatek,mt8135-apmixedsys" - "mediatek,mt8173-apmixedsys" - #clock-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt new file mode 100644 index 0000000..4137196 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt @@ -0,0 +1,22 @@ +Mediatek bdpsys controller +============================ + +The Mediatek bdpsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2701-bdpsys", "syscon" +- #clock-cells: Must be 1 + +The bdpsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +bdpsys: clock-controller@1c000000 { + compatible = "mediatek,mt2701-bdpsys", "syscon"; + reg = <0 0x1c000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt new file mode 100644 index 0000000..768f3a5 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt @@ -0,0 +1,22 @@ +Mediatek ethsys controller +============================ + +The Mediatek ethsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2701-ethsys", "syscon" +- #clock-cells: Must be 1 + +The ethsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +ethsys: clock-controller@1b000000 { + compatible = "mediatek,mt2701-ethsys", "syscon"; + reg = <0 0x1b000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt new file mode 100644 index 0000000..beed7b5 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt @@ -0,0 +1,24 @@ +Mediatek hifsys controller +============================ + +The Mediatek hifsys controller provides various clocks and reset +outputs to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2701-hifsys", "syscon" +- #clock-cells: Must be 1 + +The hifsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +hifsys: clock-controller@1a000000 { + compatible = "mediatek,mt2701-hifsys", "syscon"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt index b1f2ce1..f6a9166 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt @@ -5,7 +5,8 @@ The Mediatek imgsys controller provides various clocks to the system. Required Properties: -- compatible: Should be: +- compatible: Should be one of: + - "mediatek,mt2701-imgsys", "syscon" - "mediatek,mt8173-imgsys", "syscon" - #clock-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt index aaf8d14..1620ec2 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt @@ -6,7 +6,8 @@ outputs to the system. Required Properties: -- compatible: Should be: +- compatible: Should be one of: + - "mediatek,mt2701-infracfg", "syscon" - "mediatek,mt8135-infracfg", "syscon" - "mediatek,mt8173-infracfg", "syscon" - #clock-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt index 4385946..67dd2e4 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt @@ -5,7 +5,8 @@ The Mediatek mmsys controller provides various clocks to the system. Required Properties: -- compatible: Should be: +- compatible: Should be one of: + - "mediatek,mt2701-mmsys", "syscon" - "mediatek,mt8173-mmsys", "syscon" - #clock-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt index 2f6ff86..e494366 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt @@ -6,7 +6,8 @@ outputs to the system. Required Properties: -- compatible: Should be: +- compatible: Should be one of: + - "mediatek,mt2701-pericfg", "syscon" - "mediatek,mt8135-pericfg", "syscon" - "mediatek,mt8173-pericfg", "syscon" - #clock-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt index f9e9179..9f2fe78 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt @@ -5,7 +5,8 @@ The Mediatek topckgen controller provides various clocks to the system. Required Properties: -- compatible: Should be: +- compatible: Should be one of: + - "mediatek,mt2701-topckgen" - "mediatek,mt8135-topckgen" - "mediatek,mt8173-topckgen" - #clock-cells: Must be 1 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt index 1faacf1..2440f73 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt @@ -5,7 +5,8 @@ The Mediatek vdecsys controller provides various clocks to the system. Required Properties: -- compatible: Should be: +- compatible: Should be one of: + - "mediatek,mt2701-vdecsys", "syscon" - "mediatek,mt8173-vdecsys", "syscon" - #clock-cells: Must be 1 -- cgit v0.10.2 From 1de9b21633d669668b089bc88a67c4cd74a89a1c Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Fri, 19 Aug 2016 13:34:51 +0800 Subject: clk: mediatek: Add dt-bindings for MT2701 clocks Add MT2701 clock dt-bindings, include topckgen, apmixedsys, infracfg, pericfg and subsystem clocks. Signed-off-by: Shunli Wang Signed-off-by: James Liao Signed-off-by: Erin Lo Tested-by: John Crispin Reviewed-by: Matthias Brugger Signed-off-by: Stephen Boyd diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h new file mode 100644 index 0000000..2062c67 --- /dev/null +++ b/include/dt-bindings/clock/mt2701-clk.h @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MT2701_H +#define _DT_BINDINGS_CLK_MT2701_H + +/* TOPCKGEN */ +#define CLK_TOP_SYSPLL 1 +#define CLK_TOP_SYSPLL_D2 2 +#define CLK_TOP_SYSPLL_D3 3 +#define CLK_TOP_SYSPLL_D5 4 +#define CLK_TOP_SYSPLL_D7 5 +#define CLK_TOP_SYSPLL1_D2 6 +#define CLK_TOP_SYSPLL1_D4 7 +#define CLK_TOP_SYSPLL1_D8 8 +#define CLK_TOP_SYSPLL1_D16 9 +#define CLK_TOP_SYSPLL2_D2 10 +#define CLK_TOP_SYSPLL2_D4 11 +#define CLK_TOP_SYSPLL2_D8 12 +#define CLK_TOP_SYSPLL3_D2 13 +#define CLK_TOP_SYSPLL3_D4 14 +#define CLK_TOP_SYSPLL4_D2 15 +#define CLK_TOP_SYSPLL4_D4 16 +#define CLK_TOP_UNIVPLL 17 +#define CLK_TOP_UNIVPLL_D2 18 +#define CLK_TOP_UNIVPLL_D3 19 +#define CLK_TOP_UNIVPLL_D5 20 +#define CLK_TOP_UNIVPLL_D7 21 +#define CLK_TOP_UNIVPLL_D26 22 +#define CLK_TOP_UNIVPLL_D52 23 +#define CLK_TOP_UNIVPLL_D108 24 +#define CLK_TOP_USB_PHY48M 25 +#define CLK_TOP_UNIVPLL1_D2 26 +#define CLK_TOP_UNIVPLL1_D4 27 +#define CLK_TOP_UNIVPLL1_D8 28 +#define CLK_TOP_UNIVPLL2_D2 29 +#define CLK_TOP_UNIVPLL2_D4 30 +#define CLK_TOP_UNIVPLL2_D8 31 +#define CLK_TOP_UNIVPLL2_D16 32 +#define CLK_TOP_UNIVPLL2_D32 33 +#define CLK_TOP_UNIVPLL3_D2 34 +#define CLK_TOP_UNIVPLL3_D4 35 +#define CLK_TOP_UNIVPLL3_D8 36 +#define CLK_TOP_MSDCPLL 37 +#define CLK_TOP_MSDCPLL_D2 38 +#define CLK_TOP_MSDCPLL_D4 39 +#define CLK_TOP_MSDCPLL_D8 40 +#define CLK_TOP_MMPLL 41 +#define CLK_TOP_MMPLL_D2 42 +#define CLK_TOP_DMPLL 43 +#define CLK_TOP_DMPLL_D2 44 +#define CLK_TOP_DMPLL_D4 45 +#define CLK_TOP_DMPLL_X2 46 +#define CLK_TOP_TVDPLL 47 +#define CLK_TOP_TVDPLL_D2 48 +#define CLK_TOP_TVDPLL_D4 49 +#define CLK_TOP_TVD2PLL 50 +#define CLK_TOP_TVD2PLL_D2 51 +#define CLK_TOP_HADDS2PLL_98M 52 +#define CLK_TOP_HADDS2PLL_294M 53 +#define CLK_TOP_HADDS2_FB 54 +#define CLK_TOP_MIPIPLL_D2 55 +#define CLK_TOP_MIPIPLL_D4 56 +#define CLK_TOP_HDMIPLL 57 +#define CLK_TOP_HDMIPLL_D2 58 +#define CLK_TOP_HDMIPLL_D3 59 +#define CLK_TOP_HDMI_SCL_RX 60 +#define CLK_TOP_HDMI_0_PIX340M 61 +#define CLK_TOP_HDMI_0_DEEP340M 62 +#define CLK_TOP_HDMI_0_PLL340M 63 +#define CLK_TOP_AUD1PLL_98M 64 +#define CLK_TOP_AUD2PLL_90M 65 +#define CLK_TOP_AUDPLL 66 +#define CLK_TOP_AUDPLL_D4 67 +#define CLK_TOP_AUDPLL_D8 68 +#define CLK_TOP_AUDPLL_D16 69 +#define CLK_TOP_AUDPLL_D24 70 +#define CLK_TOP_ETHPLL_500M 71 +#define CLK_TOP_VDECPLL 72 +#define CLK_TOP_VENCPLL 73 +#define CLK_TOP_MIPIPLL 74 +#define CLK_TOP_ARMPLL_1P3G 75 + +#define CLK_TOP_MM_SEL 76 +#define CLK_TOP_DDRPHYCFG_SEL 77 +#define CLK_TOP_MEM_SEL 78 +#define CLK_TOP_AXI_SEL 79 +#define CLK_TOP_CAMTG_SEL 80 +#define CLK_TOP_MFG_SEL 81 +#define CLK_TOP_VDEC_SEL 82 +#define CLK_TOP_PWM_SEL 83 +#define CLK_TOP_MSDC30_0_SEL 84 +#define CLK_TOP_USB20_SEL 85 +#define CLK_TOP_SPI0_SEL 86 +#define CLK_TOP_UART_SEL 87 +#define CLK_TOP_AUDINTBUS_SEL 88 +#define CLK_TOP_AUDIO_SEL 89 +#define CLK_TOP_MSDC30_2_SEL 90 +#define CLK_TOP_MSDC30_1_SEL 91 +#define CLK_TOP_DPI1_SEL 92 +#define CLK_TOP_DPI0_SEL 93 +#define CLK_TOP_SCP_SEL 94 +#define CLK_TOP_PMICSPI_SEL 95 +#define CLK_TOP_APLL_SEL 96 +#define CLK_TOP_HDMI_SEL 97 +#define CLK_TOP_TVE_SEL 98 +#define CLK_TOP_EMMC_HCLK_SEL 99 +#define CLK_TOP_NFI2X_SEL 100 +#define CLK_TOP_RTC_SEL 101 +#define CLK_TOP_OSD_SEL 102 +#define CLK_TOP_NR_SEL 103 +#define CLK_TOP_DI_SEL 104 +#define CLK_TOP_FLASH_SEL 105 +#define CLK_TOP_ASM_M_SEL 106 +#define CLK_TOP_ASM_I_SEL 107 +#define CLK_TOP_INTDIR_SEL 108 +#define CLK_TOP_HDMIRX_BIST_SEL 109 +#define CLK_TOP_ETHIF_SEL 110 +#define CLK_TOP_MS_CARD_SEL 111 +#define CLK_TOP_ASM_H_SEL 112 +#define CLK_TOP_SPI1_SEL 113 +#define CLK_TOP_CMSYS_SEL 114 +#define CLK_TOP_MSDC30_3_SEL 115 +#define CLK_TOP_HDMIRX26_24_SEL 116 +#define CLK_TOP_AUD2DVD_SEL 117 +#define CLK_TOP_8BDAC_SEL 118 +#define CLK_TOP_SPI2_SEL 119 +#define CLK_TOP_AUD_MUX1_SEL 120 +#define CLK_TOP_AUD_MUX2_SEL 121 +#define CLK_TOP_AUDPLL_MUX_SEL 122 +#define CLK_TOP_AUD_K1_SRC_SEL 123 +#define CLK_TOP_AUD_K2_SRC_SEL 124 +#define CLK_TOP_AUD_K3_SRC_SEL 125 +#define CLK_TOP_AUD_K4_SRC_SEL 126 +#define CLK_TOP_AUD_K5_SRC_SEL 127 +#define CLK_TOP_AUD_K6_SRC_SEL 128 +#define CLK_TOP_PADMCLK_SEL 129 +#define CLK_TOP_AUD_EXTCK1_DIV 130 +#define CLK_TOP_AUD_EXTCK2_DIV 131 +#define CLK_TOP_AUD_MUX1_DIV 132 +#define CLK_TOP_AUD_MUX2_DIV 133 +#define CLK_TOP_AUD_K1_SRC_DIV 134 +#define CLK_TOP_AUD_K2_SRC_DIV 135 +#define CLK_TOP_AUD_K3_SRC_DIV 136 +#define CLK_TOP_AUD_K4_SRC_DIV 137 +#define CLK_TOP_AUD_K5_SRC_DIV 138 +#define CLK_TOP_AUD_K6_SRC_DIV 139 +#define CLK_TOP_AUD_I2S1_MCLK 140 +#define CLK_TOP_AUD_I2S2_MCLK 141 +#define CLK_TOP_AUD_I2S3_MCLK 142 +#define CLK_TOP_AUD_I2S4_MCLK 143 +#define CLK_TOP_AUD_I2S5_MCLK 144 +#define CLK_TOP_AUD_I2S6_MCLK 145 +#define CLK_TOP_AUD_48K_TIMING 146 +#define CLK_TOP_AUD_44K_TIMING 147 + +#define CLK_TOP_32K_INTERNAL 148 +#define CLK_TOP_32K_EXTERNAL 149 +#define CLK_TOP_CLK26M_D8 150 +#define CLK_TOP_8BDAC 151 +#define CLK_TOP_WBG_DIG_416M 152 +#define CLK_TOP_DPI 153 +#define CLK_TOP_HDMITX_CLKDIG_CTS 154 +#define CLK_TOP_DSI0_LNTC_DSI 155 +#define CLK_TOP_AUD_EXT1 156 +#define CLK_TOP_AUD_EXT2 157 +#define CLK_TOP_NFI1X_PAD 158 +#define CLK_TOP_NR 159 + +/* APMIXEDSYS */ + +#define CLK_APMIXED_ARMPLL 1 +#define CLK_APMIXED_MAINPLL 2 +#define CLK_APMIXED_UNIVPLL 3 +#define CLK_APMIXED_MMPLL 4 +#define CLK_APMIXED_MSDCPLL 5 +#define CLK_APMIXED_TVDPLL 6 +#define CLK_APMIXED_AUD1PLL 7 +#define CLK_APMIXED_TRGPLL 8 +#define CLK_APMIXED_ETHPLL 9 +#define CLK_APMIXED_VDECPLL 10 +#define CLK_APMIXED_HADDS2PLL 11 +#define CLK_APMIXED_AUD2PLL 12 +#define CLK_APMIXED_TVD2PLL 13 +#define CLK_APMIXED_NR 14 + +/* DDRPHY */ + +#define CLK_DDRPHY_VENCPLL 1 +#define CLK_DDRPHY_NR 2 + +/* INFRACFG */ + +#define CLK_INFRA_DBG 1 +#define CLK_INFRA_SMI 2 +#define CLK_INFRA_QAXI_CM4 3 +#define CLK_INFRA_AUD_SPLIN_B 4 +#define CLK_INFRA_AUDIO 5 +#define CLK_INFRA_EFUSE 6 +#define CLK_INFRA_L2C_SRAM 7 +#define CLK_INFRA_M4U 8 +#define CLK_INFRA_CONNMCU 9 +#define CLK_INFRA_TRNG 10 +#define CLK_INFRA_RAMBUFIF 11 +#define CLK_INFRA_CPUM 12 +#define CLK_INFRA_KP 13 +#define CLK_INFRA_CEC 14 +#define CLK_INFRA_IRRX 15 +#define CLK_INFRA_PMICSPI 16 +#define CLK_INFRA_PMICWRAP 17 +#define CLK_INFRA_DDCCI 18 +#define CLK_INFRA_CLK_13M 19 +#define CLK_INFRA_NR 20 + +/* PERICFG */ + +#define CLK_PERI_NFI 1 +#define CLK_PERI_THERM 2 +#define CLK_PERI_PWM1 3 +#define CLK_PERI_PWM2 4 +#define CLK_PERI_PWM3 5 +#define CLK_PERI_PWM4 6 +#define CLK_PERI_PWM5 7 +#define CLK_PERI_PWM6 8 +#define CLK_PERI_PWM7 9 +#define CLK_PERI_PWM 10 +#define CLK_PERI_USB0 11 +#define CLK_PERI_USB1 12 +#define CLK_PERI_AP_DMA 13 +#define CLK_PERI_MSDC30_0 14 +#define CLK_PERI_MSDC30_1 15 +#define CLK_PERI_MSDC30_2 16 +#define CLK_PERI_MSDC30_3 17 +#define CLK_PERI_MSDC50_3 18 +#define CLK_PERI_NLI 19 +#define CLK_PERI_UART0 20 +#define CLK_PERI_UART1 21 +#define CLK_PERI_UART2 22 +#define CLK_PERI_UART3 23 +#define CLK_PERI_BTIF 24 +#define CLK_PERI_I2C0 25 +#define CLK_PERI_I2C1 26 +#define CLK_PERI_I2C2 27 +#define CLK_PERI_I2C3 28 +#define CLK_PERI_AUXADC 29 +#define CLK_PERI_SPI0 30 +#define CLK_PERI_ETH 31 +#define CLK_PERI_USB0_MCU 32 + +#define CLK_PERI_USB1_MCU 33 +#define CLK_PERI_USB_SLV 34 +#define CLK_PERI_GCPU 35 +#define CLK_PERI_NFI_ECC 36 +#define CLK_PERI_NFI_PAD 37 +#define CLK_PERI_FLASH 38 +#define CLK_PERI_HOST89_INT 39 +#define CLK_PERI_HOST89_SPI 40 +#define CLK_PERI_HOST89_DVD 41 +#define CLK_PERI_SPI1 42 +#define CLK_PERI_SPI2 43 +#define CLK_PERI_FCI 44 + +#define CLK_PERI_UART0_SEL 45 +#define CLK_PERI_UART1_SEL 46 +#define CLK_PERI_UART2_SEL 47 +#define CLK_PERI_UART3_SEL 48 +#define CLK_PERI_NR 49 + +/* AUDIO */ + +#define CLK_AUD_AFE 1 +#define CLK_AUD_LRCK_DETECT 2 +#define CLK_AUD_I2S 3 +#define CLK_AUD_APLL_TUNER 4 +#define CLK_AUD_HDMI 5 +#define CLK_AUD_SPDF 6 +#define CLK_AUD_SPDF2 7 +#define CLK_AUD_APLL 8 +#define CLK_AUD_TML 9 +#define CLK_AUD_AHB_IDLE_EXT 10 +#define CLK_AUD_AHB_IDLE_INT 11 + +#define CLK_AUD_I2SIN1 12 +#define CLK_AUD_I2SIN2 13 +#define CLK_AUD_I2SIN3 14 +#define CLK_AUD_I2SIN4 15 +#define CLK_AUD_I2SIN5 16 +#define CLK_AUD_I2SIN6 17 +#define CLK_AUD_I2SO1 18 +#define CLK_AUD_I2SO2 19 +#define CLK_AUD_I2SO3 20 +#define CLK_AUD_I2SO4 21 +#define CLK_AUD_I2SO5 22 +#define CLK_AUD_I2SO6 23 +#define CLK_AUD_ASRCI1 24 +#define CLK_AUD_ASRCI2 25 +#define CLK_AUD_ASRCO1 26 +#define CLK_AUD_ASRCO2 27 +#define CLK_AUD_ASRC11 28 +#define CLK_AUD_ASRC12 29 +#define CLK_AUD_HDMIRX 30 +#define CLK_AUD_INTDIR 31 +#define CLK_AUD_A1SYS 32 +#define CLK_AUD_A2SYS 33 +#define CLK_AUD_AFE_CONN 34 +#define CLK_AUD_AFE_PCMIF 35 +#define CLK_AUD_AFE_MRGIF 36 + +#define CLK_AUD_MMIF_UL1 37 +#define CLK_AUD_MMIF_UL2 38 +#define CLK_AUD_MMIF_UL3 39 +#define CLK_AUD_MMIF_UL4 40 +#define CLK_AUD_MMIF_UL5 41 +#define CLK_AUD_MMIF_UL6 42 +#define CLK_AUD_MMIF_DL1 43 +#define CLK_AUD_MMIF_DL2 44 +#define CLK_AUD_MMIF_DL3 45 +#define CLK_AUD_MMIF_DL4 46 +#define CLK_AUD_MMIF_DL5 47 +#define CLK_AUD_MMIF_DL6 48 +#define CLK_AUD_MMIF_DLMCH 49 +#define CLK_AUD_MMIF_ARB1 50 +#define CLK_AUD_MMIF_AWB1 51 +#define CLK_AUD_MMIF_AWB2 52 +#define CLK_AUD_MMIF_DAI 53 + +#define CLK_AUD_DMIC1 54 +#define CLK_AUD_DMIC2 55 +#define CLK_AUD_ASRCI3 56 +#define CLK_AUD_ASRCI4 57 +#define CLK_AUD_ASRCI5 58 +#define CLK_AUD_ASRCI6 59 +#define CLK_AUD_ASRCO3 60 +#define CLK_AUD_ASRCO4 61 +#define CLK_AUD_ASRCO5 62 +#define CLK_AUD_ASRCO6 63 +#define CLK_AUD_MEM_ASRC1 64 +#define CLK_AUD_MEM_ASRC2 65 +#define CLK_AUD_MEM_ASRC3 66 +#define CLK_AUD_MEM_ASRC4 67 +#define CLK_AUD_MEM_ASRC5 68 +#define CLK_AUD_DSD_ENC 69 +#define CLK_AUD_ASRC_BRG 70 +#define CLK_AUD_NR 71 + +/* MMSYS */ + +#define CLK_MM_SMI_COMMON 1 +#define CLK_MM_SMI_LARB0 2 +#define CLK_MM_CMDQ 3 +#define CLK_MM_MUTEX 4 +#define CLK_MM_DISP_COLOR 5 +#define CLK_MM_DISP_BLS 6 +#define CLK_MM_DISP_WDMA 7 +#define CLK_MM_DISP_RDMA 8 +#define CLK_MM_DISP_OVL 9 +#define CLK_MM_MDP_TDSHP 10 +#define CLK_MM_MDP_WROT 11 +#define CLK_MM_MDP_WDMA 12 +#define CLK_MM_MDP_RSZ1 13 +#define CLK_MM_MDP_RSZ0 14 +#define CLK_MM_MDP_RDMA 15 +#define CLK_MM_MDP_BLS_26M 16 +#define CLK_MM_CAM_MDP 17 +#define CLK_MM_FAKE_ENG 18 +#define CLK_MM_MUTEX_32K 19 +#define CLK_MM_DISP_RDMA1 20 +#define CLK_MM_DISP_UFOE 21 + +#define CLK_MM_DSI_ENGINE 22 +#define CLK_MM_DSI_DIG 23 +#define CLK_MM_DPI_DIGL 24 +#define CLK_MM_DPI_ENGINE 25 +#define CLK_MM_DPI1_DIGL 26 +#define CLK_MM_DPI1_ENGINE 27 +#define CLK_MM_TVE_OUTPUT 28 +#define CLK_MM_TVE_INPUT 29 +#define CLK_MM_HDMI_PIXEL 30 +#define CLK_MM_HDMI_PLL 31 +#define CLK_MM_HDMI_AUDIO 32 +#define CLK_MM_HDMI_SPDIF 33 +#define CLK_MM_TVE_FMM 34 +#define CLK_MM_NR 35 + +/* IMGSYS */ + +#define CLK_IMG_SMI_COMM 1 +#define CLK_IMG_RESZ 2 +#define CLK_IMG_JPGDEC_SMI 3 +#define CLK_IMG_JPGDEC 4 +#define CLK_IMG_VENC_LT 5 +#define CLK_IMG_VENC 6 +#define CLK_IMG_NR 7 + +/* VDEC */ + +#define CLK_VDEC_CKGEN 1 +#define CLK_VDEC_LARB 2 +#define CLK_VDEC_NR 3 + +/* HIFSYS */ + +#define CLK_HIFSYS_USB0PHY 1 +#define CLK_HIFSYS_USB1PHY 2 +#define CLK_HIFSYS_PCIE0 3 +#define CLK_HIFSYS_PCIE1 4 +#define CLK_HIFSYS_PCIE2 5 +#define CLK_HIFSYS_NR 6 + +/* ETHSYS */ +#define CLK_ETHSYS_HSDMA 1 +#define CLK_ETHSYS_ESW 2 +#define CLK_ETHSYS_GP2 3 +#define CLK_ETHSYS_GP1 4 +#define CLK_ETHSYS_PCM 5 +#define CLK_ETHSYS_GDMA 6 +#define CLK_ETHSYS_I2S 7 +#define CLK_ETHSYS_CRYPTO 8 +#define CLK_ETHSYS_NR 9 + +/* BDP */ + +#define CLK_BDP_BRG_BA 1 +#define CLK_BDP_BRG_DRAM 2 +#define CLK_BDP_LARB_DRAM 3 +#define CLK_BDP_WR_VDI_PXL 4 +#define CLK_BDP_WR_VDI_DRAM 5 +#define CLK_BDP_WR_B 6 +#define CLK_BDP_DGI_IN 7 +#define CLK_BDP_DGI_OUT 8 +#define CLK_BDP_FMT_MAST_27 9 +#define CLK_BDP_FMT_B 10 +#define CLK_BDP_OSD_B 11 +#define CLK_BDP_OSD_DRAM 12 +#define CLK_BDP_OSD_AGENT 13 +#define CLK_BDP_OSD_PXL 14 +#define CLK_BDP_RLE_B 15 +#define CLK_BDP_RLE_AGENT 16 +#define CLK_BDP_RLE_DRAM 17 +#define CLK_BDP_F27M 18 +#define CLK_BDP_F27M_VDOUT 19 +#define CLK_BDP_F27_74_74 20 +#define CLK_BDP_F2FS 21 +#define CLK_BDP_F2FS74_148 22 +#define CLK_BDP_FB 23 +#define CLK_BDP_VDO_DRAM 24 +#define CLK_BDP_VDO_2FS 25 +#define CLK_BDP_VDO_B 26 +#define CLK_BDP_WR_DI_PXL 27 +#define CLK_BDP_WR_DI_DRAM 28 +#define CLK_BDP_WR_DI_B 29 +#define CLK_BDP_NR_PXL 30 +#define CLK_BDP_NR_DRAM 31 +#define CLK_BDP_NR_B 32 + +#define CLK_BDP_RX_F 33 +#define CLK_BDP_RX_X 34 +#define CLK_BDP_RXPDT 35 +#define CLK_BDP_RX_CSCL_N 36 +#define CLK_BDP_RX_CSCL 37 +#define CLK_BDP_RX_DDCSCL_N 38 +#define CLK_BDP_RX_DDCSCL 39 +#define CLK_BDP_RX_VCO 40 +#define CLK_BDP_RX_DP 41 +#define CLK_BDP_RX_P 42 +#define CLK_BDP_RX_M 43 +#define CLK_BDP_RX_PLL 44 +#define CLK_BDP_BRG_RT_B 45 +#define CLK_BDP_BRG_RT_DRAM 46 +#define CLK_BDP_LARBRT_DRAM 47 +#define CLK_BDP_TMDS_SYN 48 +#define CLK_BDP_HDMI_MON 49 +#define CLK_BDP_NR 50 + +#endif /* _DT_BINDINGS_CLK_MT2701_H */ -- cgit v0.10.2 From c3c5768346c5a27d63c3f3217452ab4b924c3885 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Fri, 19 Aug 2016 13:34:53 +0800 Subject: reset: mediatek: Add MT2701 reset controller dt-binding file Dt-binding file about reset controller is used to provide kinds of definition, which is referenced by dts file and IC-specified reset controller driver code. Signed-off-by: Shunli Wang Signed-off-by: James Liao Signed-off-by: Erin Lo Tested-by: John Crispin Acked-by: Philipp Zabel Signed-off-by: Stephen Boyd diff --git a/include/dt-bindings/reset/mt2701-resets.h b/include/dt-bindings/reset/mt2701-resets.h new file mode 100644 index 0000000..aaf0305 --- /dev/null +++ b/include/dt-bindings/reset/mt2701-resets.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015 MediaTek, Shunli Wang + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT2701 +#define _DT_BINDINGS_RESET_CONTROLLER_MT2701 + +/* INFRACFG resets */ +#define MT2701_INFRA_EMI_REG_RST 0 +#define MT2701_INFRA_DRAMC0_A0_RST 1 +#define MT2701_INFRA_FHCTL_RST 2 +#define MT2701_INFRA_APCIRQ_EINT_RST 3 +#define MT2701_INFRA_APXGPT_RST 4 +#define MT2701_INFRA_SCPSYS_RST 5 +#define MT2701_INFRA_KP_RST 6 +#define MT2701_INFRA_PMIC_WRAP_RST 7 +#define MT2701_INFRA_MIPI_RST 8 +#define MT2701_INFRA_IRRX_RST 9 +#define MT2701_INFRA_CEC_RST 10 +#define MT2701_INFRA_EMI_RST 32 +#define MT2701_INFRA_DRAMC0_RST 34 +#define MT2701_INFRA_TRNG_RST 37 +#define MT2701_INFRA_SYSIRQ_RST 38 + +/* PERICFG resets */ +#define MT2701_PERI_UART0_SW_RST 0 +#define MT2701_PERI_UART1_SW_RST 1 +#define MT2701_PERI_UART2_SW_RST 2 +#define MT2701_PERI_UART3_SW_RST 3 +#define MT2701_PERI_GCPU_SW_RST 5 +#define MT2701_PERI_BTIF_SW_RST 6 +#define MT2701_PERI_PWM_SW_RST 8 +#define MT2701_PERI_AUXADC_SW_RST 10 +#define MT2701_PERI_DMA_SW_RST 11 +#define MT2701_PERI_NFI_SW_RST 14 +#define MT2701_PERI_NLI_SW_RST 15 +#define MT2701_PERI_THERM_SW_RST 16 +#define MT2701_PERI_MSDC2_SW_RST 17 +#define MT2701_PERI_MSDC0_SW_RST 19 +#define MT2701_PERI_MSDC1_SW_RST 20 +#define MT2701_PERI_I2C0_SW_RST 22 +#define MT2701_PERI_I2C1_SW_RST 23 +#define MT2701_PERI_I2C2_SW_RST 24 +#define MT2701_PERI_I2C3_SW_RST 25 +#define MT2701_PERI_USB_SW_RST 28 +#define MT2701_PERI_ETH_SW_RST 29 +#define MT2701_PERI_SPI0_SW_RST 33 + +/* TOPRGU resets */ +#define MT2701_TOPRGU_INFRA_RST 0 +#define MT2701_TOPRGU_MM_RST 1 +#define MT2701_TOPRGU_MFG_RST 2 +#define MT2701_TOPRGU_ETHDMA_RST 3 +#define MT2701_TOPRGU_VDEC_RST 4 +#define MT2701_TOPRGU_VENC_IMG_RST 5 +#define MT2701_TOPRGU_DDRPHY_RST 6 +#define MT2701_TOPRGU_MD_RST 7 +#define MT2701_TOPRGU_INFRA_AO_RST 8 +#define MT2701_TOPRGU_CONN_RST 9 +#define MT2701_TOPRGU_APMIXED_RST 10 +#define MT2701_TOPRGU_HIFSYS_RST 11 +#define MT2701_TOPRGU_CONN_MCU_RST 12 +#define MT2701_TOPRGU_BDP_DISP_RST 13 + +/* HIFSYS resets */ +#define MT2701_HIFSYS_UHOST0_RST 3 +#define MT2701_HIFSYS_UHOST1_RST 4 +#define MT2701_HIFSYS_UPHY0_RST 21 +#define MT2701_HIFSYS_UPHY1_RST 22 +#define MT2701_HIFSYS_PCIE0_RST 24 +#define MT2701_HIFSYS_PCIE1_RST 25 +#define MT2701_HIFSYS_PCIE2_RST 26 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT2701 */ -- cgit v0.10.2 From edb89f126fc006f4346379195b815a0dd727f9e7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 18 Aug 2016 12:08:47 +0200 Subject: dt-bindings: clock: reset: Add GXBB AO Clock and Reset Bindings Add documentations and dt-bindings headers for the AO clock and reset controller. Acked-by: Rob Herring Signed-off-by: Neil Armstrong Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt new file mode 100644 index 0000000..a55d31b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt @@ -0,0 +1,45 @@ +* Amlogic GXBB AO Clock and Reset Unit + +The Amlogic GXBB AO clock controller generates and supplies clock to various +controllers within the Always-On part of the SoC. + +Required Properties: + +- compatible: should be "amlogic,gxbb-aoclkc" +- reg: physical base address of the clock controller and length of memory + mapped region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/gxbb-aoclkc.h header and can be +used in device tree sources. + +- #reset-cells: should be 1. + +Each reset is assigned an identifier and client nodes can use this identifier +to specify the reset which they consume. All available resets are defined as +preprocessor macros in the dt-bindings/reset/gxbb-aoclkc.h header and can be +used in device tree sources. + +Example: AO Clock controller node: + + clkc_AO: clock-controller@040 { + compatible = "amlogic,gxbb-aoclkc"; + reg = <0x0 0x040 0x0 0x4>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock and reset generated + by the clock controller: + + uart_AO: serial@4c0 { + compatible = "amlogic,meson-uart"; + reg = <0x4c0 0x14>; + interrupts = <0 90 1>; + clocks = <&clkc_AO CLKID_AO_UART1>; + resets = <&clkc_AO RESET_AO_UART1>; + status = "disabled"; + }; diff --git a/include/dt-bindings/clock/gxbb-aoclkc.h b/include/dt-bindings/clock/gxbb-aoclkc.h new file mode 100644 index 0000000..3175148 --- /dev/null +++ b/include/dt-bindings/clock/gxbb-aoclkc.h @@ -0,0 +1,66 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * BSD LICENSE + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DT_BINDINGS_CLOCK_AMLOGIC_MESON_GXBB_AOCLK +#define DT_BINDINGS_CLOCK_AMLOGIC_MESON_GXBB_AOCLK + +#define CLKID_AO_REMOTE 0 +#define CLKID_AO_I2C_MASTER 1 +#define CLKID_AO_I2C_SLAVE 2 +#define CLKID_AO_UART1 3 +#define CLKID_AO_UART2 4 +#define CLKID_AO_IR_BLASTER 5 + +#endif diff --git a/include/dt-bindings/reset/gxbb-aoclkc.h b/include/dt-bindings/reset/gxbb-aoclkc.h new file mode 100644 index 0000000..9e3fd60 --- /dev/null +++ b/include/dt-bindings/reset/gxbb-aoclkc.h @@ -0,0 +1,66 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * BSD LICENSE + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DT_BINDINGS_RESET_AMLOGIC_MESON_GXBB_AOCLK +#define DT_BINDINGS_RESET_AMLOGIC_MESON_GXBB_AOCLK + +#define RESET_AO_REMOTE 0 +#define RESET_AO_I2C_MASTER 1 +#define RESET_AO_I2C_SLAVE 2 +#define RESET_AO_UART1 3 +#define RESET_AO_UART2 4 +#define RESET_AO_IR_BLASTER 5 + +#endif -- cgit v0.10.2 From f8c11f79912db52c8d90ce748094b4d411f36782 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 18 Aug 2016 12:08:46 +0200 Subject: clk: meson: Add GXBB AO Clock and Reset controller driver Adds a Clock and Reset controller driver for the Always-On part of the Amlogic Meson GXBB SoC. It exports paired Clocks and Resets lines that will be used by peripherals in the Always-On subsystem. Signed-off-by: Neil Armstrong Signed-off-by: Stephen Boyd diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 197e401..d4cd4a3 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b-clkc.o -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c new file mode 100644 index 0000000..61ef28a --- /dev/null +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -0,0 +1,191 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * BSD LICENSE + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(gxbb_aoclk_lock); + +struct gxbb_aoclk_reset_controller { + struct reset_controller_dev reset; + unsigned int *data; + void __iomem *base; +}; + +static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct gxbb_aoclk_reset_controller *reset = + container_of(rcdev, struct gxbb_aoclk_reset_controller, reset); + + writel(BIT(reset->data[id]), reset->base); + + return 0; +} + +static const struct reset_control_ops gxbb_aoclk_reset_ops = { + .reset = gxbb_aoclk_do_reset, +}; + +#define GXBB_AO_GATE(_name, _bit) \ +static struct clk_gate _name##_ao = { \ + .reg = (void __iomem *)0, \ + .bit_idx = (_bit), \ + .lock = &gxbb_aoclk_lock, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name "_ao", \ + .ops = &clk_gate_ops, \ + .parent_names = (const char *[]){ "clk81" }, \ + .num_parents = 1, \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + }, \ +} + +GXBB_AO_GATE(remote, 0); +GXBB_AO_GATE(i2c_master, 1); +GXBB_AO_GATE(i2c_slave, 2); +GXBB_AO_GATE(uart1, 3); +GXBB_AO_GATE(uart2, 5); +GXBB_AO_GATE(ir_blaster, 6); + +static unsigned int gxbb_aoclk_reset[] = { + [RESET_AO_REMOTE] = 16, + [RESET_AO_I2C_MASTER] = 18, + [RESET_AO_I2C_SLAVE] = 19, + [RESET_AO_UART1] = 17, + [RESET_AO_UART2] = 22, + [RESET_AO_IR_BLASTER] = 23, +}; + +static struct clk_gate *gxbb_aoclk_gate[] = { + [CLKID_AO_REMOTE] = &remote_ao, + [CLKID_AO_I2C_MASTER] = &i2c_master_ao, + [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, + [CLKID_AO_UART1] = &uart1_ao, + [CLKID_AO_UART2] = &uart2_ao, + [CLKID_AO_IR_BLASTER] = &ir_blaster_ao, +}; + +static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { + .hws = { + [CLKID_AO_REMOTE] = &remote_ao.hw, + [CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw, + [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao.hw, + [CLKID_AO_UART1] = &uart1_ao.hw, + [CLKID_AO_UART2] = &uart2_ao.hw, + [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, + }, + .num = ARRAY_SIZE(gxbb_aoclk_gate), +}; + +static int gxbb_aoclkc_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + int ret, clkid; + struct device *dev = &pdev->dev; + struct gxbb_aoclk_reset_controller *rstc; + + rstc = devm_kzalloc(dev, sizeof(rstc), GFP_KERNEL); + if (!rstc) + return -ENOMEM; + + /* Generic clocks */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* Reset Controller */ + rstc->base = base; + rstc->data = gxbb_aoclk_reset; + rstc->reset.ops = &gxbb_aoclk_reset_ops; + rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset); + rstc->reset.of_node = dev->of_node; + ret = devm_reset_controller_register(dev, &rstc->reset); + + /* + * Populate base address and register all clks + */ + for (clkid = 0; clkid < gxbb_aoclk_onecell_data.num; clkid++) { + gxbb_aoclk_gate[clkid]->reg = base; + + ret = devm_clk_hw_register(dev, + gxbb_aoclk_onecell_data.hws[clkid]); + if (ret) + return ret; + } + + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + &gxbb_aoclk_onecell_data); +} + +static const struct of_device_id gxbb_aoclkc_match_table[] = { + { .compatible = "amlogic,gxbb-aoclkc" }, + { } +}; + +static struct platform_driver gxbb_aoclkc_driver = { + .probe = gxbb_aoclkc_probe, + .driver = { + .name = "gxbb-aoclkc", + .of_match_table = gxbb_aoclkc_match_table, + }, +}; +builtin_platform_driver(gxbb_aoclkc_driver); -- cgit v0.10.2 From 96e9dff6ddf0ee436a670cf58d740d40e4088ff9 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 12 Aug 2016 15:26:54 -0300 Subject: clk: imx7d: Add the clock for SDMA Add IMX7D_SDMA_CORE_CLK clock so that SDMA can be functional. Signed-off-by: Fabio Estevam Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 9257972..c24677d 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -779,6 +779,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0); clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0); clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0); + clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0); clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0); clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0); clks[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0); -- cgit v0.10.2 From d5ebf5fabb66d76abb1ce28863f6c5afcc6d5367 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 12 Aug 2016 15:26:55 -0300 Subject: clk: imx: Introduce clk_register_gate2() Introduce imx_clk_gate2_shared2() which is similar to the existing imx_clk_gate2_shared() and passes CLK_OPS_PARENT_ENABLE flag, which is useful for i.MX7 shared clocks. Signed-off-by: Fabio Estevam Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index a81c038..3799ff8 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -134,6 +134,15 @@ static inline struct clk *imx_clk_gate2_shared(const char *name, shift, 0x3, 0, &imx_ccm_lock, share_count); } +static inline struct clk *imx_clk_gate2_shared2(const char *name, + const char *parent, void __iomem *reg, u8 shift, + unsigned int *share_count) +{ + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | + CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, + &imx_ccm_lock, share_count); +} + static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 cgr_val) { -- cgit v0.10.2 From 069810257644c90d891ce659596013201d9d9e7b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 12 Aug 2016 15:26:56 -0300 Subject: clk: imx7d: Add SAI IPG clocks The SAI_IPG clocks are enabled by the same bits that control SAI_ROOT_CLK clocks, so represent them as shared clocks. Signed-off-by: Fabio Estevam Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index c24677d..6bafcaa 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -22,6 +22,10 @@ #include "clk.h" +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; + static struct clk *clks[IMX7D_CLK_END]; static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk", "pll_enet_500m_clk", "pll_dram_main_clk", @@ -787,9 +791,12 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0); clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0); clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0); - clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate4("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0); - clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate4("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0); - clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate4("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0); + clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1); + clks[IMX7D_SAI1_IPG_CLK] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_root_clk", base + 0x48c0, 0, &share_count_sai1); + clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2); + clks[IMX7D_SAI2_IPG_CLK] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_root_clk", base + 0x48d0, 0, &share_count_sai2); + clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3); + clks[IMX7D_SAI3_IPG_CLK] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root_clk", base + 0x48e0, 0, &share_count_sai3); clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0); clks[IMX7D_ENET1_REF_ROOT_CLK] = imx_clk_gate4("enet1_ref_root_clk", "enet1_ref_post_div", base + 0x44e0, 0); clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate4("enet1_time_root_clk", "enet1_time_post_div", base + 0x44f0, 0); -- cgit v0.10.2 From 63bb4fd6a391167f855f9b38b27945bed4015756 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 16 Aug 2016 12:55:48 +0530 Subject: clk: qcom: gdsc: Add the missing BIMC gdsc for msm8996 Add BIMC gdsc data found in MMCC part of msm8996 family of devices. Signed-off-by: Rajendra Nayak Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 847dd9d..1822045 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -2888,6 +2888,14 @@ static struct clk_hw *mmcc_msm8996_hws[] = { &gpll0_div.hw, }; +static struct gdsc mmagic_bimc_gdsc = { + .gdscr = 0x529c, + .pd = { + .name = "mmagic_bimc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct gdsc mmagic_video_gdsc = { .gdscr = 0x119c, .gds_hw_ctrl = 0x120c, @@ -3201,6 +3209,7 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = { }; static struct gdsc *mmcc_msm8996_gdscs[] = { + [MMAGIC_BIMC_GDSC] = &mmagic_bimc_gdsc, [MMAGIC_VIDEO_GDSC] = &mmagic_video_gdsc, [MMAGIC_MDSS_GDSC] = &mmagic_mdss_gdsc, [MMAGIC_CAMSS_GDSC] = &mmagic_camss_gdsc, diff --git a/include/dt-bindings/clock/qcom,mmcc-msm8996.h b/include/dt-bindings/clock/qcom,mmcc-msm8996.h index 7d3a7fa..5abc445 100644 --- a/include/dt-bindings/clock/qcom,mmcc-msm8996.h +++ b/include/dt-bindings/clock/qcom,mmcc-msm8996.h @@ -298,5 +298,6 @@ #define FD_GDSC 12 #define MDSS_GDSC 13 #define GPU_GX_GDSC 14 +#define MMAGIC_BIMC_GDSC 15 #endif -- cgit v0.10.2 From 074969813350cda4c624a585489cc1b3550414bc Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 23 Aug 2016 09:49:44 +0200 Subject: clk: renesas: r8a7796: Add SDIF clocks This patch adds SDIF clocks for R8A7796 SoC. Based on work by Ai Kyuse and Yoshihiro Shimoda for the r8a7795 SoC. Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 999955c..891b353 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -70,6 +70,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1), DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), /* Core Clock Outputs */ DEF_FIXED("ztr", R8A7796_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), @@ -93,6 +94,11 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_FIXED("s3d2", R8A7796_CLK_S3D2, CLK_S3, 2, 1), DEF_FIXED("s3d4", R8A7796_CLK_S3D4, CLK_S3, 4, 1), + DEF_GEN3_SD("sd0", R8A7796_CLK_SD0, CLK_SDSRC, 0x0074), + DEF_GEN3_SD("sd1", R8A7796_CLK_SD1, CLK_SDSRC, 0x0078), + DEF_GEN3_SD("sd2", R8A7796_CLK_SD2, CLK_SDSRC, 0x0268), + DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, CLK_SDSRC, 0x026c), + DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1), DEF_FIXED("cp", R8A7796_CLK_CP, CLK_EXTAL, 2, 1), @@ -104,6 +110,10 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("scif2", 310, R8A7796_CLK_S3D4), + DEF_MOD("sdif3", 311, R8A7796_CLK_SD3), + DEF_MOD("sdif2", 312, R8A7796_CLK_SD2), + DEF_MOD("sdif1", 313, R8A7796_CLK_SD1), + DEF_MOD("sdif0", 314, R8A7796_CLK_SD0), DEF_MOD("rwdt0", 402, R8A7796_CLK_R), DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1), DEF_MOD("gpio7", 905, R8A7796_CLK_S3D4), -- cgit v0.10.2 From 023a8280b8355a0aebe094299afec8d8b7b264cd Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sat, 13 Aug 2016 20:56:18 +0530 Subject: clk: rockchip: handle of_iomap failures in legacy clock driver Check return value of of_iomap and handle errors correctly. Signed-off-by: Arvind Yadav Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c index 4cf838d5..2c9bb81 100644 --- a/drivers/clk/rockchip/clk-rockchip.c +++ b/drivers/clk/rockchip/clk-rockchip.c @@ -49,14 +49,19 @@ static void __init rk2928_gate_clk_init(struct device_node *node) } reg = of_iomap(node, 0); + if (!reg) + return; clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); - if (!clk_data) + if (!clk_data) { + iounmap(reg); return; + } clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) { kfree(clk_data); + iounmap(reg); return; } -- cgit v0.10.2 From 718cc4b60ff279c0d6169d109e22cb107b23e312 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 22 Aug 2016 16:08:21 +0000 Subject: clk: meson: Fix invalid use of sizeof in gxbb_aoclkc_probe() sizeof() when applied to a pointer typed expression gives the size of the pointer, not that of the pointed data. Signed-off-by: Wei Yongjun Acked-by: Neil Armstrong Fixes: f8c11f79912d ("clk: meson: Add GXBB AO Clock and Reset controller driver") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 61ef28a..b45c5fb 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -142,7 +142,7 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct gxbb_aoclk_reset_controller *rstc; - rstc = devm_kzalloc(dev, sizeof(rstc), GFP_KERNEL); + rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); if (!rstc) return -ENOMEM; -- cgit v0.10.2 From 0f7dd7acda0add9cbd39caa6902c9e79ecb0a89d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 20 Aug 2016 15:31:05 +0000 Subject: clk: mvebu: Remove redundant dev_err call in armada_3700_periph_clock_probe() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 5bb13c9..45905fc 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -383,10 +383,8 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg = devm_ioremap_resource(dev, res); - if (IS_ERR(reg)) { - dev_err(dev, "Could not map the periph clock registers\n"); + if (IS_ERR(reg)) return PTR_ERR(reg); - } driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL); if (!driver_data) -- cgit v0.10.2 From 12f53b2432ad1a2a3f09cf9b772a467b2f20e040 Mon Sep 17 00:00:00 2001 From: Purna Chandra Mandal Date: Tue, 17 May 2016 10:35:50 +0530 Subject: clk: microchip: use readl_poll_timeout() in pbclk_set_rate(). pbclk_set_rate() is using readl_poll_timeout_atomic() even though spinlock is released. Fix it by replacing with readl_poll_timeout(). Signed-off-by: Purna Chandra Mandal Signed-off-by: Stephen Boyd diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-core.c index ca85cea..c3b3014 100644 --- a/drivers/clk/microchip/clk-core.c +++ b/drivers/clk/microchip/clk-core.c @@ -199,9 +199,9 @@ static int pbclk_set_rate(struct clk_hw *hw, unsigned long rate, spin_unlock_irqrestore(&pb->core->reg_lock, flags); - /* wait again, for pbdivready */ - err = readl_poll_timeout_atomic(pb->ctrl_reg, v, v & PB_DIV_READY, - 1, LOCK_TIMEOUT_US); + /* wait again for DIV_READY */ + err = readl_poll_timeout(pb->ctrl_reg, v, v & PB_DIV_READY, + 1, LOCK_TIMEOUT_US); if (err) return err; -- cgit v0.10.2 From a38c94106e0dc77490ff820450c0c4af3b57fbc7 Mon Sep 17 00:00:00 2001 From: Purna Chandra Mandal Date: Tue, 17 May 2016 10:35:51 +0530 Subject: clk: microchip: Initialize SOSC clock rate for PIC32MZDA. Optional SOSC is an external fixed clock running at 32768HZ. So Initialize SOSC rate as per PIC32MZDA datasheet. Signed-off-by: Purna Chandra Mandal Signed-off-by: Stephen Boyd diff --git a/drivers/clk/microchip/clk-pic32mzda.c b/drivers/clk/microchip/clk-pic32mzda.c index 51f5438..9f73477 100644 --- a/drivers/clk/microchip/clk-pic32mzda.c +++ b/drivers/clk/microchip/clk-pic32mzda.c @@ -118,6 +118,7 @@ static const struct pic32_sec_osc_data sosc_clk = { .status_reg = 0x1d0, .enable_mask = BIT(1), .status_mask = BIT(4), + .fixed_rate = 32768, .init_data = { .name = "sosc_clk", .parent_names = NULL, -- cgit v0.10.2 From f37fccce4cc19238f0742494a37d3efad346dfe7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:05 -0700 Subject: clk: bcm: kona: Migrate to clk_hw based registration and OF APIs Now that we can use clk_hw pointers we don't need to have two duplicate arrays holding the same mapping of clk index to clk_hw pointer. Implement a custom clk_hw provider function to map the OF specifier to the clk_hw instance for it. Cc: Alex Elder Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index 526b0b0..f2359b3 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -696,77 +696,69 @@ static void bcm_clk_teardown(struct kona_clk *bcm_clk) bcm_clk->type = bcm_clk_none; } -static void kona_clk_teardown(struct clk *clk) +static void kona_clk_teardown(struct clk_hw *hw) { - struct clk_hw *hw; struct kona_clk *bcm_clk; - if (!clk) + if (!hw) return; - hw = __clk_get_hw(clk); - if (!hw) { - pr_err("%s: clk %p has null hw pointer\n", __func__, clk); - return; - } - clk_unregister(clk); + clk_hw_unregister(hw); bcm_clk = to_kona_clk(hw); bcm_clk_teardown(bcm_clk); } -struct clk *kona_clk_setup(struct kona_clk *bcm_clk) +static int kona_clk_setup(struct kona_clk *bcm_clk) { + int ret; struct clk_init_data *init_data = &bcm_clk->init_data; - struct clk *clk = NULL; switch (bcm_clk->type) { case bcm_clk_peri: - if (peri_clk_setup(bcm_clk->u.data, init_data)) - return NULL; + ret = peri_clk_setup(bcm_clk->u.data, init_data); + if (ret) + return ret; break; default: pr_err("%s: clock type %d invalid for %s\n", __func__, (int)bcm_clk->type, init_data->name); - return NULL; + return -EINVAL; } /* Make sure everything makes sense before we set it up */ if (!kona_clk_valid(bcm_clk)) { pr_err("%s: clock data invalid for %s\n", __func__, init_data->name); + ret = -EINVAL; goto out_teardown; } bcm_clk->hw.init = init_data; - clk = clk_register(NULL, &bcm_clk->hw); - if (IS_ERR(clk)) { - pr_err("%s: error registering clock %s (%ld)\n", __func__, - init_data->name, PTR_ERR(clk)); + ret = clk_hw_register(NULL, &bcm_clk->hw); + if (ret) { + pr_err("%s: error registering clock %s (%d)\n", __func__, + init_data->name, ret); goto out_teardown; } - BUG_ON(!clk); - return clk; + return 0; out_teardown: bcm_clk_teardown(bcm_clk); - return NULL; + return ret; } static void ccu_clks_teardown(struct ccu_data *ccu) { u32 i; - for (i = 0; i < ccu->clk_data.clk_num; i++) - kona_clk_teardown(ccu->clk_data.clks[i]); - kfree(ccu->clk_data.clks); + for (i = 0; i < ccu->clk_num; i++) + kona_clk_teardown(&ccu->kona_clks[i].hw); } static void kona_ccu_teardown(struct ccu_data *ccu) { - kfree(ccu->clk_data.clks); - ccu->clk_data.clks = NULL; if (!ccu->base) return; @@ -793,6 +785,20 @@ static bool ccu_data_valid(struct ccu_data *ccu) return true; } +static struct clk_hw * +of_clk_kona_onecell_get(struct of_phandle_args *clkspec, void *data) +{ + struct ccu_data *ccu = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= ccu->clk_num) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &ccu->kona_clks[idx].hw; +} + /* * Set up a CCU. Call the provided ccu_clks_setup callback to * initialize the array of clocks provided by the CCU. @@ -805,18 +811,6 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, unsigned int i; int ret; - if (ccu->clk_data.clk_num) { - size_t size; - - size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks); - ccu->clk_data.clks = kzalloc(size, GFP_KERNEL); - if (!ccu->clk_data.clks) { - pr_err("%s: unable to allocate %u clocks for %s\n", - __func__, ccu->clk_data.clk_num, node->name); - return; - } - } - ret = of_address_to_resource(node, 0, &res); if (ret) { pr_err("%s: no valid CCU registers found for %s\n", __func__, @@ -851,13 +845,13 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, * the clock framework clock array (in ccu->data). Then * register as a provider for these clocks. */ - for (i = 0; i < ccu->clk_data.clk_num; i++) { + for (i = 0; i < ccu->clk_num; i++) { if (!ccu->kona_clks[i].ccu) continue; - ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]); + kona_clk_setup(&ccu->kona_clks[i]); } - ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data); + ret = of_clk_add_hw_provider(node, of_clk_kona_onecell_get, ccu); if (ret) { pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, node->name, ret); diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 3a15347..eee64b9 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1256,19 +1256,18 @@ bool __init kona_ccu_init(struct ccu_data *ccu) { unsigned long flags; unsigned int which; - struct clk **clks = ccu->clk_data.clks; struct kona_clk *kona_clks = ccu->kona_clks; bool success = true; flags = ccu_lock(ccu); __ccu_write_enable(ccu); - for (which = 0; which < ccu->clk_data.clk_num; which++) { - struct kona_clk *bcm_clk; + for (which = 0; which < ccu->clk_num; which++) { + struct kona_clk *bcm_clk = &kona_clks[which]; - if (!clks[which]) + if (!bcm_clk->ccu) continue; - bcm_clk = &kona_clks[which]; + success &= __kona_clk_init(bcm_clk); } diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h index 906576e..f4b39bb 100644 --- a/drivers/clk/bcm/clk-kona.h +++ b/drivers/clk/bcm/clk-kona.h @@ -481,7 +481,7 @@ struct ccu_data { bool write_enabled; /* write access is currently enabled */ struct ccu_policy policy; struct device_node *node; - struct clk_onecell_data clk_data; + size_t clk_num; const char *name; u32 range; /* byte range of address space */ struct kona_clk kona_clks[]; /* must be last */ @@ -491,9 +491,7 @@ struct ccu_data { #define KONA_CCU_COMMON(_prefix, _name, _ccuname) \ .name = #_name "_ccu", \ .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \ - .clk_data = { \ - .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \ - } + .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT /* Exported globals */ @@ -505,7 +503,6 @@ extern u64 scaled_div_max(struct bcm_clk_div *div); extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths); -extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk); extern void __init kona_dt_ccu_setup(struct ccu_data *ccu, struct device_node *node); extern bool __init kona_ccu_init(struct ccu_data *ccu); -- cgit v0.10.2 From 78cf5555e9835726ffa8ff66a943c0aefaa917e9 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:07 -0700 Subject: clk: asm9260: Migrate to clk_hw based registration and OF APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Oleksij Rempel Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c index 90897af..ea85685 100644 --- a/drivers/clk/clk-asm9260.c +++ b/drivers/clk/clk-asm9260.c @@ -68,8 +68,7 @@ #define HW_LCDCLKDIV 0x01fc #define HW_ADCANACLKDIV 0x0200 -static struct clk *clks[MAX_CLKS]; -static struct clk_onecell_data clk_data; +static struct clk_hw_onecell_data *clk_data; static DEFINE_SPINLOCK(asm9260_clk_lock); struct asm9260_div_clk { @@ -267,12 +266,20 @@ static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = { static void __init asm9260_acc_init(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; + struct clk_hw **hws; const char *ref_clk, *pll_clk = "pll"; u32 rate; int n; u32 accuracy = 0; + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + if (!clk_data) + return; + clk_data->num = MAX_CLKS; + hws = clk_data->hws; + base = of_io_request_and_map(np, 0, np->name); if (IS_ERR(base)) panic("%s: unable to map resource", np->name); @@ -282,10 +289,10 @@ static void __init asm9260_acc_init(struct device_node *np) ref_clk = of_clk_get_parent_name(np, 0); accuracy = clk_get_accuracy(__clk_lookup(ref_clk)); - clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk, + hw = clk_hw_register_fixed_rate_with_accuracy(NULL, pll_clk, ref_clk, 0, rate, accuracy); - if (IS_ERR(clk)) + if (IS_ERR(hw)) panic("%s: can't register REFCLK. Check DT!", np->name); for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) { @@ -293,7 +300,7 @@ static void __init asm9260_acc_init(struct device_node *np) mc->parent_names[0] = ref_clk; mc->parent_names[1] = pll_clk; - clk = clk_register_mux_table(NULL, mc->name, mc->parent_names, + hw = clk_hw_register_mux_table(NULL, mc->name, mc->parent_names, mc->num_parents, mc->flags, base + mc->offset, 0, mc->mask, 0, mc->table, &asm9260_clk_lock); } @@ -302,7 +309,7 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) { const struct asm9260_gate_data *gd = &asm9260_mux_gates[n]; - clk = clk_register_gate(NULL, gd->name, + hw = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags | CLK_SET_RATE_PARENT, base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock); } @@ -311,7 +318,7 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) { const struct asm9260_div_clk *dc = &asm9260_div_clks[n]; - clks[dc->idx] = clk_register_divider(NULL, dc->name, + hws[dc->idx] = clk_hw_register_divider(NULL, dc->name, dc->parent_name, CLK_SET_RATE_PARENT, base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED, &asm9260_clk_lock); @@ -321,14 +328,14 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) { const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n]; - clks[gd->idx] = clk_register_gate(NULL, gd->name, + hws[gd->idx] = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags, base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock); } /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { - if (!IS_ERR(clks[n])) + if (!IS_ERR(hws[n])) continue; pr_err("%s: Unable to register leaf clock %d\n", @@ -337,9 +344,7 @@ static void __init asm9260_acc_init(struct device_node *np) } /* register clk-provider */ - clk_data.clks = clks; - clk_data.clk_num = MAX_CLKS; - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); return; fail: iounmap(base); -- cgit v0.10.2 From e0d30bb9230a815eb9ce7971b9cc81378f96e9f2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:08 -0700 Subject: clk: axi-clkgen: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Lars-Peter Clausen Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 3294db3..5e918e7 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -392,8 +392,8 @@ static int axi_clkgen_probe(struct platform_device *pdev) const char *parent_names[2]; const char *clk_name; struct resource *mem; - struct clk *clk; unsigned int i; + int ret; if (!pdev->dev.of_node) return -ENODEV; @@ -433,12 +433,12 @@ static int axi_clkgen_probe(struct platform_device *pdev) axi_clkgen_mmcm_enable(axi_clkgen, false); axi_clkgen->clk_hw.init = &init; - clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(&pdev->dev, &axi_clkgen->clk_hw); + if (ret) + return ret; - return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, - clk); + return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_simple_get, + &axi_clkgen->clk_hw); } static int axi_clkgen_remove(struct platform_device *pdev) -- cgit v0.10.2 From 235d2aaa77325b5db58c69b586a3c3f35897baa9 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:09 -0700 Subject: clk: axm5516: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Make thing simple by using the existing clk_hw array and implementing a custom DT clk provider get function to map the clk spec id to a clk_hw pointer. Cc: Anders Berg Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c index c7c91a5..5d7ae33 100644 --- a/drivers/clk/clk-axm5516.c +++ b/drivers/clk/clk-axm5516.c @@ -516,6 +516,19 @@ static struct axxia_clk *axmclk_clocks[] = { [AXXIA_CLK_MMC] = &clk_mmc_mux.aclk, }; +static struct clk_hw * +of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused) +{ + unsigned int idx = clkspec->args[0]; + + if (idx >= ARRAY_SIZE(axmclk_clocks)) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &axmclk_clocks[idx]->hw; +} + static const struct regmap_config axmclk_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -530,21 +543,14 @@ static const struct of_device_id axmclk_match_table[] = { }; MODULE_DEVICE_TABLE(of, axmclk_match_table); -struct axmclk_priv { - struct clk_onecell_data onecell; - struct clk *clks[]; -}; - static int axmclk_probe(struct platform_device *pdev) { void __iomem *base; struct resource *res; int i, ret; struct device *dev = &pdev->dev; - struct clk *clk; struct regmap *regmap; size_t num_clks; - struct axmclk_priv *priv; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); @@ -557,29 +563,18 @@ static int axmclk_probe(struct platform_device *pdev) num_clks = ARRAY_SIZE(axmclk_clocks); pr_info("axmclk: supporting %zu clocks\n", num_clks); - priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks, - GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->onecell.clks = priv->clks; - priv->onecell.clk_num = num_clks; /* Update each entry with the allocated regmap and register the clock * with the common clock framework */ for (i = 0; i < num_clks; i++) { axmclk_clocks[i]->regmap = regmap; - clk = devm_clk_register(dev, &axmclk_clocks[i]->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); - priv->clks[i] = clk; + ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw); + if (ret) + return ret; } - ret = of_clk_add_provider(dev->of_node, - of_clk_src_onecell_get, &priv->onecell); - - return ret; + return of_clk_add_hw_provider(dev->of_node, of_clk_axmclk_get, NULL); } static int axmclk_remove(struct platform_device *pdev) -- cgit v0.10.2 From 01b5200a6683c428da18fe4936cfe2a412e2233d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:10 -0700 Subject: clk: cdce: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Max Filippov Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index 01877f6..f21d909 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -71,7 +71,6 @@ struct cdce706_hw_data { struct cdce706_dev_data *dev_data; unsigned idx; unsigned parent; - struct clk *clk; struct clk_hw hw; unsigned div; unsigned mul; @@ -81,8 +80,6 @@ struct cdce706_hw_data { struct cdce706_dev_data { struct i2c_client *client; struct regmap *regmap; - struct clk_onecell_data onecell; - struct clk *clks[6]; struct clk *clkin_clk[2]; const char *clkin_name[2]; struct cdce706_hw_data clkin[1]; @@ -455,18 +452,19 @@ static int cdce706_register_hw(struct cdce706_dev_data *cdce, struct clk_init_data *init) { unsigned i; + int ret; for (i = 0; i < num_hw; ++i, ++hw) { init->name = clk_names[i]; hw->dev_data = cdce; hw->idx = i; hw->hw.init = init; - hw->clk = devm_clk_register(&cdce->client->dev, + ret = devm_clk_hw_register(&cdce->client->dev, &hw->hw); - if (IS_ERR(hw->clk)) { + if (ret) { dev_err(&cdce->client->dev, "Failed to register %s\n", clk_names[i]); - return PTR_ERR(hw->clk); + return ret; } } return 0; @@ -613,13 +611,23 @@ static int cdce706_register_clkouts(struct cdce706_dev_data *cdce) cdce->clkout[i].parent); } - ret = cdce706_register_hw(cdce, cdce->clkout, - ARRAY_SIZE(cdce->clkout), - cdce706_clkout_name, &init); - for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) - cdce->clks[i] = cdce->clkout[i].clk; + return cdce706_register_hw(cdce, cdce->clkout, + ARRAY_SIZE(cdce->clkout), + cdce706_clkout_name, &init); +} - return ret; +static struct clk_hw * +of_clk_cdce_get(struct of_phandle_args *clkspec, void *data) +{ + struct cdce706_dev_data *cdce = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= ARRAY_SIZE(cdce->clkout)) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &cdce->clkout[idx].hw; } static int cdce706_probe(struct i2c_client *client, @@ -657,12 +665,8 @@ static int cdce706_probe(struct i2c_client *client, ret = cdce706_register_clkouts(cdce); if (ret < 0) return ret; - cdce->onecell.clks = cdce->clks; - cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks); - ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, - &cdce->onecell); - - return ret; + return of_clk_add_hw_provider(client->dev.of_node, of_clk_cdce_get, + cdce); } static int cdce706_remove(struct i2c_client *client) -- cgit v0.10.2 From a85d11712dd13fc2a389b950d12f6b7f7d8c4c48 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:11 -0700 Subject: clk: cdce925: Migrate to clk_hw based OF and provider APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Mike Looijmans Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index 089bf88..b8459c1 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -62,8 +62,6 @@ struct clk_cdce925_chip { struct i2c_client *i2c_client; struct clk_cdce925_pll pll[NUMBER_OF_PLLS]; struct clk_cdce925_output clk[NUMBER_OF_OUTPUTS]; - struct clk *dt_clk[NUMBER_OF_OUTPUTS]; - struct clk_onecell_data onecell; }; /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ @@ -557,6 +555,20 @@ static int cdce925_regmap_i2c_read(void *context, return -EIO; } +static struct clk_hw * +of_clk_cdce925_get(struct of_phandle_args *clkspec, void *_data) +{ + struct clk_cdce925_chip *data = _data; + unsigned int idx = clkspec->args[0]; + + if (idx >= ARRAY_SIZE(data->clk)) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &data->clk[idx].hw; +} + /* The CDCE925 uses a funky way to read/write registers. Bulk mode is * just weird, so just use the single byte mode exclusively. */ static struct regmap_bus regmap_cdce925_bus = { @@ -572,7 +584,6 @@ static int cdce925_probe(struct i2c_client *client, const char *parent_name; const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,}; struct clk_init_data init; - struct clk *clk; u32 value; int i; int err; @@ -622,10 +633,9 @@ static int cdce925_probe(struct i2c_client *client, data->pll[i].chip = data; data->pll[i].hw.init = &init; data->pll[i].index = i; - clk = devm_clk_register(&client->dev, &data->pll[i].hw); - if (IS_ERR(clk)) { + err = devm_clk_hw_register(&client->dev, &data->pll[i].hw); + if (err) { dev_err(&client->dev, "Failed register PLL %d\n", i); - err = PTR_ERR(clk); goto error; } sprintf(child_name, "PLL%d", i+1); @@ -634,7 +644,7 @@ static int cdce925_probe(struct i2c_client *client, continue; if (!of_property_read_u32(np_output, "clock-frequency", &value)) { - err = clk_set_rate(clk, value); + err = clk_set_rate(data->pll[i].hw.clk, value); if (err) dev_err(&client->dev, "unable to set PLL frequency %ud\n", @@ -663,14 +673,12 @@ static int cdce925_probe(struct i2c_client *client, data->clk[0].hw.init = &init; data->clk[0].index = 0; data->clk[0].pdiv = 1; - clk = devm_clk_register(&client->dev, &data->clk[0].hw); + err = devm_clk_hw_register(&client->dev, &data->clk[0].hw); kfree(init.name); /* clock framework made a copy of the name */ - if (IS_ERR(clk)) { + if (err) { dev_err(&client->dev, "clock registration Y1 failed\n"); - err = PTR_ERR(clk); goto error; } - data->dt_clk[0] = clk; /* Register output clocks Y2 .. Y5*/ init.ops = &cdce925_clk_ops; @@ -695,21 +703,17 @@ static int cdce925_probe(struct i2c_client *client, init.parent_names = &pll_clk_name[1]; break; } - clk = devm_clk_register(&client->dev, &data->clk[i].hw); + err = devm_clk_hw_register(&client->dev, &data->clk[i].hw); kfree(init.name); /* clock framework made a copy of the name */ - if (IS_ERR(clk)) { + if (err) { dev_err(&client->dev, "clock registration failed\n"); - err = PTR_ERR(clk); goto error; } - data->dt_clk[i] = clk; } /* Register the output clocks */ - data->onecell.clk_num = NUMBER_OF_OUTPUTS; - data->onecell.clks = data->dt_clk; - err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, - &data->onecell); + err = of_clk_add_hw_provider(client->dev.of_node, of_clk_cdce925_get, + data); if (err) dev_err(&client->dev, "unable to add OF clock provider\n"); -- cgit v0.10.2 From f48d947a162dfa9d62ebe6d79eb30100cb81751b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:12 -0700 Subject: clk: clps711x: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Alexander Shiyan Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index adaf109..9193f64 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -40,9 +40,8 @@ static const struct clk_div_table timer_div_table[] = { }; struct clps711x_clk { - struct clk_onecell_data clk_data; - spinlock_t lock; - struct clk *clks[CLPS711X_CLK_MAX]; + spinlock_t lock; + struct clk_hw_onecell_data clk_data; }; static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, @@ -55,7 +54,9 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, if (!base) return ERR_PTR(-ENOMEM); - clps711x_clk = kzalloc(sizeof(*clps711x_clk), GFP_KERNEL); + clps711x_clk = kzalloc(sizeof(*clps711x_clk) + + sizeof(*clps711x_clk->clk_data.hws) * CLPS711X_CLK_MAX, + GFP_KERNEL); if (!clps711x_clk) return ERR_PTR(-ENOMEM); @@ -106,40 +107,40 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, tmp |= SYSCON1_TC2M | SYSCON1_TC2S; writel(tmp, base + CLPS711X_SYSCON1); - clps711x_clk->clks[CLPS711X_CLK_DUMMY] = - clk_register_fixed_rate(NULL, "dummy", NULL, 0, 0); - clps711x_clk->clks[CLPS711X_CLK_CPU] = - clk_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu); - clps711x_clk->clks[CLPS711X_CLK_BUS] = - clk_register_fixed_rate(NULL, "bus", NULL, 0, f_bus); - clps711x_clk->clks[CLPS711X_CLK_PLL] = - clk_register_fixed_rate(NULL, "pll", NULL, 0, f_pll); - clps711x_clk->clks[CLPS711X_CLK_TIMERREF] = - clk_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim); - clps711x_clk->clks[CLPS711X_CLK_TIMER1] = - clk_register_divider_table(NULL, "timer1", "timer_ref", 0, + clps711x_clk->clk_data.hws[CLPS711X_CLK_DUMMY] = + clk_hw_register_fixed_rate(NULL, "dummy", NULL, 0, 0); + clps711x_clk->clk_data.hws[CLPS711X_CLK_CPU] = + clk_hw_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu); + clps711x_clk->clk_data.hws[CLPS711X_CLK_BUS] = + clk_hw_register_fixed_rate(NULL, "bus", NULL, 0, f_bus); + clps711x_clk->clk_data.hws[CLPS711X_CLK_PLL] = + clk_hw_register_fixed_rate(NULL, "pll", NULL, 0, f_pll); + clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMERREF] = + clk_hw_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim); + clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1] = + clk_hw_register_divider_table(NULL, "timer1", "timer_ref", 0, base + CLPS711X_SYSCON1, 5, 1, 0, timer_div_table, &clps711x_clk->lock); - clps711x_clk->clks[CLPS711X_CLK_TIMER2] = - clk_register_divider_table(NULL, "timer2", "timer_ref", 0, + clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2] = + clk_hw_register_divider_table(NULL, "timer2", "timer_ref", 0, base + CLPS711X_SYSCON1, 7, 1, 0, timer_div_table, &clps711x_clk->lock); - clps711x_clk->clks[CLPS711X_CLK_PWM] = - clk_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm); - clps711x_clk->clks[CLPS711X_CLK_SPIREF] = - clk_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi); - clps711x_clk->clks[CLPS711X_CLK_SPI] = - clk_register_divider_table(NULL, "spi", "spi_ref", 0, + clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM] = + clk_hw_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm); + clps711x_clk->clk_data.hws[CLPS711X_CLK_SPIREF] = + clk_hw_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi); + clps711x_clk->clk_data.hws[CLPS711X_CLK_SPI] = + clk_hw_register_divider_table(NULL, "spi", "spi_ref", 0, base + CLPS711X_SYSCON1, 16, 2, 0, spi_div_table, &clps711x_clk->lock); - clps711x_clk->clks[CLPS711X_CLK_UART] = - clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); - clps711x_clk->clks[CLPS711X_CLK_TICK] = - clk_register_fixed_rate(NULL, "tick", NULL, 0, 64); + clps711x_clk->clk_data.hws[CLPS711X_CLK_UART] = + clk_hw_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); + clps711x_clk->clk_data.hws[CLPS711X_CLK_TICK] = + clk_hw_register_fixed_rate(NULL, "tick", NULL, 0, 64); for (i = 0; i < CLPS711X_CLK_MAX; i++) - if (IS_ERR(clps711x_clk->clks[i])) + if (IS_ERR(clps711x_clk->clk_data.hws[i])) pr_err("clk %i: register failed with %ld\n", - i, PTR_ERR(clps711x_clk->clks[i])); + i, PTR_ERR(clps711x_clk->clk_data.hws[i])); return clps711x_clk; } @@ -153,17 +154,17 @@ void __init clps711x_clk_init(void __iomem *base) BUG_ON(IS_ERR(clps711x_clk)); /* Clocksource */ - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER1], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1], NULL, "clps711x-timer.0"); - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER2], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2], NULL, "clps711x-timer.1"); /* Drivers */ - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_PWM], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM], NULL, "clps711x-pwm"); - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], NULL, "clps711x-uart.0"); - clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART], + clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], NULL, "clps711x-uart.1"); } @@ -179,10 +180,9 @@ static void __init clps711x_clk_init_dt(struct device_node *np) clps711x_clk = _clps711x_clk_init(base, fref); BUG_ON(IS_ERR(clps711x_clk)); - clps711x_clk->clk_data.clks = clps711x_clk->clks; - clps711x_clk->clk_data.clk_num = CLPS711X_CLK_MAX; - of_clk_add_provider(np, of_clk_src_onecell_get, - &clps711x_clk->clk_data); + clps711x_clk->clk_data.num = CLPS711X_CLK_MAX; + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &clps711x_clk->clk_data); } CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt); #endif -- cgit v0.10.2 From 2ceb3c7aadc4c1a4a16643c2ac1e7b64c40f4fc7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:13 -0700 Subject: clk: cs2000: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Kuninori Morimoto Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index 7379de8..021f3da 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -59,7 +59,6 @@ struct cs2000_priv { struct i2c_client *client; struct clk *clk_in; struct clk *ref_clk; - struct clk *clk_out; }; static const struct of_device_id cs2000_of_match[] = { @@ -371,7 +370,6 @@ static int cs2000_clk_register(struct cs2000_priv *priv) struct device_node *np = dev->of_node; struct clk_init_data init; const char *name = np->name; - struct clk *clk; static const char *parent_names[CLK_MAX]; int ch = 0; /* it uses ch0 only at this point */ int rate; @@ -400,18 +398,16 @@ static int cs2000_clk_register(struct cs2000_priv *priv) priv->hw.init = &init; - clk = clk_register(dev, &priv->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = clk_hw_register(dev, &priv->hw); + if (ret) + return ret; - ret = of_clk_add_provider(np, of_clk_src_simple_get, clk); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw); if (ret < 0) { - clk_unregister(clk); + clk_hw_unregister(&priv->hw); return ret; } - priv->clk_out = clk; - return 0; } @@ -454,7 +450,7 @@ static int cs2000_remove(struct i2c_client *client) of_clk_del_provider(np); - clk_unregister(priv->clk_out); + clk_hw_unregister(&priv->hw); return 0; } -- cgit v0.10.2 From 9337631f52a84742a476383eb3e795ac5773f5ab Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:14 -0700 Subject: clk: efm32gg: Migrate to clk_hw based OF and registration APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Uwe Kleine-König Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c index 22e4c65..8802a2d 100644 --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c @@ -10,24 +10,31 @@ #include #include #include +#include #include #define CMU_HFPERCLKEN0 0x44 +#define CMU_MAX_CLKS 37 -static struct clk *clk[37]; -static struct clk_onecell_data clk_data = { - .clks = clk, - .clk_num = ARRAY_SIZE(clk), -}; +static struct clk_hw_onecell_data *clk_data; static void __init efm32gg_cmu_init(struct device_node *np) { int i; void __iomem *base; + struct clk_hw **hws; - for (i = 0; i < ARRAY_SIZE(clk); ++i) - clk[i] = ERR_PTR(-ENOENT); + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * CMU_MAX_CLKS, GFP_KERNEL); + + if (!clk_data) + return; + + hws = clk_data->hws; + + for (i = 0; i < CMU_MAX_CLKS; ++i) + hws[i] = ERR_PTR(-ENOENT); base = of_iomap(np, 0); if (!base) { @@ -35,46 +42,46 @@ static void __init efm32gg_cmu_init(struct device_node *np) return; } - clk[clk_HFXO] = clk_register_fixed_rate(NULL, "HFXO", NULL, - 0, 48000000); + hws[clk_HFXO] = clk_hw_register_fixed_rate(NULL, "HFXO", NULL, 0, + 48000000); - clk[clk_HFPERCLKUSART0] = clk_register_gate(NULL, "HFPERCLK.USART0", + hws[clk_HFPERCLKUSART0] = clk_hw_register_gate(NULL, "HFPERCLK.USART0", "HFXO", 0, base + CMU_HFPERCLKEN0, 0, 0, NULL); - clk[clk_HFPERCLKUSART1] = clk_register_gate(NULL, "HFPERCLK.USART1", + hws[clk_HFPERCLKUSART1] = clk_hw_register_gate(NULL, "HFPERCLK.USART1", "HFXO", 0, base + CMU_HFPERCLKEN0, 1, 0, NULL); - clk[clk_HFPERCLKUSART2] = clk_register_gate(NULL, "HFPERCLK.USART2", + hws[clk_HFPERCLKUSART2] = clk_hw_register_gate(NULL, "HFPERCLK.USART2", "HFXO", 0, base + CMU_HFPERCLKEN0, 2, 0, NULL); - clk[clk_HFPERCLKUART0] = clk_register_gate(NULL, "HFPERCLK.UART0", + hws[clk_HFPERCLKUART0] = clk_hw_register_gate(NULL, "HFPERCLK.UART0", "HFXO", 0, base + CMU_HFPERCLKEN0, 3, 0, NULL); - clk[clk_HFPERCLKUART1] = clk_register_gate(NULL, "HFPERCLK.UART1", + hws[clk_HFPERCLKUART1] = clk_hw_register_gate(NULL, "HFPERCLK.UART1", "HFXO", 0, base + CMU_HFPERCLKEN0, 4, 0, NULL); - clk[clk_HFPERCLKTIMER0] = clk_register_gate(NULL, "HFPERCLK.TIMER0", + hws[clk_HFPERCLKTIMER0] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER0", "HFXO", 0, base + CMU_HFPERCLKEN0, 5, 0, NULL); - clk[clk_HFPERCLKTIMER1] = clk_register_gate(NULL, "HFPERCLK.TIMER1", + hws[clk_HFPERCLKTIMER1] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER1", "HFXO", 0, base + CMU_HFPERCLKEN0, 6, 0, NULL); - clk[clk_HFPERCLKTIMER2] = clk_register_gate(NULL, "HFPERCLK.TIMER2", + hws[clk_HFPERCLKTIMER2] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER2", "HFXO", 0, base + CMU_HFPERCLKEN0, 7, 0, NULL); - clk[clk_HFPERCLKTIMER3] = clk_register_gate(NULL, "HFPERCLK.TIMER3", + hws[clk_HFPERCLKTIMER3] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER3", "HFXO", 0, base + CMU_HFPERCLKEN0, 8, 0, NULL); - clk[clk_HFPERCLKACMP0] = clk_register_gate(NULL, "HFPERCLK.ACMP0", + hws[clk_HFPERCLKACMP0] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP0", "HFXO", 0, base + CMU_HFPERCLKEN0, 9, 0, NULL); - clk[clk_HFPERCLKACMP1] = clk_register_gate(NULL, "HFPERCLK.ACMP1", + hws[clk_HFPERCLKACMP1] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP1", "HFXO", 0, base + CMU_HFPERCLKEN0, 10, 0, NULL); - clk[clk_HFPERCLKI2C0] = clk_register_gate(NULL, "HFPERCLK.I2C0", + hws[clk_HFPERCLKI2C0] = clk_hw_register_gate(NULL, "HFPERCLK.I2C0", "HFXO", 0, base + CMU_HFPERCLKEN0, 11, 0, NULL); - clk[clk_HFPERCLKI2C1] = clk_register_gate(NULL, "HFPERCLK.I2C1", + hws[clk_HFPERCLKI2C1] = clk_hw_register_gate(NULL, "HFPERCLK.I2C1", "HFXO", 0, base + CMU_HFPERCLKEN0, 12, 0, NULL); - clk[clk_HFPERCLKGPIO] = clk_register_gate(NULL, "HFPERCLK.GPIO", + hws[clk_HFPERCLKGPIO] = clk_hw_register_gate(NULL, "HFPERCLK.GPIO", "HFXO", 0, base + CMU_HFPERCLKEN0, 13, 0, NULL); - clk[clk_HFPERCLKVCMP] = clk_register_gate(NULL, "HFPERCLK.VCMP", + hws[clk_HFPERCLKVCMP] = clk_hw_register_gate(NULL, "HFPERCLK.VCMP", "HFXO", 0, base + CMU_HFPERCLKEN0, 14, 0, NULL); - clk[clk_HFPERCLKPRS] = clk_register_gate(NULL, "HFPERCLK.PRS", + hws[clk_HFPERCLKPRS] = clk_hw_register_gate(NULL, "HFPERCLK.PRS", "HFXO", 0, base + CMU_HFPERCLKEN0, 15, 0, NULL); - clk[clk_HFPERCLKADC0] = clk_register_gate(NULL, "HFPERCLK.ADC0", + hws[clk_HFPERCLKADC0] = clk_hw_register_gate(NULL, "HFPERCLK.ADC0", "HFXO", 0, base + CMU_HFPERCLKEN0, 16, 0, NULL); - clk[clk_HFPERCLKDAC0] = clk_register_gate(NULL, "HFPERCLK.DAC0", + hws[clk_HFPERCLKDAC0] = clk_hw_register_gate(NULL, "HFPERCLK.DAC0", "HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL); - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); } CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init); -- cgit v0.10.2 From 6b212f5a6adc271547279d0140eaf70f8c06e65a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:17 -0700 Subject: clk: mb86s7x: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Jassi Brar Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-mb86s7x.c b/drivers/clk/clk-mb86s7x.c index e081775..2a83a3ff 100644 --- a/drivers/clk/clk-mb86s7x.c +++ b/drivers/clk/clk-mb86s7x.c @@ -327,10 +327,11 @@ static struct clk_ops clk_clc_ops = { .set_rate = clc_set_rate, }; -struct clk *mb86s7x_clclk_register(struct device *cpu_dev) +static struct clk_hw *mb86s7x_clclk_register(struct device *cpu_dev) { struct clk_init_data init; struct cl_clk *clc; + int ret; clc = kzalloc(sizeof(*clc), GFP_KERNEL); if (!clc) @@ -344,14 +345,17 @@ struct clk *mb86s7x_clclk_register(struct device *cpu_dev) init.flags = CLK_GET_RATE_NOCACHE; init.num_parents = 0; - return devm_clk_register(cpu_dev, &clc->hw); + ret = devm_clk_hw_register(cpu_dev, &clc->hw); + if (ret) + return ERR_PTR(ret); + return &clc->hw; } static int mb86s7x_clclk_of_init(void) { int cpu, ret = -ENODEV; struct device_node *np; - struct clk *clk; + struct clk_hw *hw; np = of_find_compatible_node(NULL, NULL, "fujitsu,mb86s70-scb-1.0"); if (!np || !of_device_is_available(np)) @@ -365,12 +369,12 @@ static int mb86s7x_clclk_of_init(void) continue; } - clk = mb86s7x_clclk_register(cpu_dev); - if (IS_ERR(clk)) { + hw = mb86s7x_clclk_register(cpu_dev); + if (IS_ERR(hw)) { pr_err("failed to register cpu%d clock\n", cpu); continue; } - if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) { + if (clk_hw_register_clkdev(hw, NULL, dev_name(cpu_dev))) { pr_err("failed to register cpu%d clock lookup\n", cpu); continue; } -- cgit v0.10.2 From 5a962d2ea2f46adf61ed0f496de058770dc19ae9 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:18 -0700 Subject: clk: moxart: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Jonas Jensen Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c index f37f719..b86dac8 100644 --- a/drivers/clk/clk-moxart.c +++ b/drivers/clk/clk-moxart.c @@ -19,7 +19,8 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) { static void __iomem *base; - struct clk *clk, *ref_clk; + struct clk_hw *hw; + struct clk *ref_clk; unsigned int mul; const char *name = node->name; const char *parent_name; @@ -42,14 +43,14 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) return; } - clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); - if (IS_ERR(clk)) { + hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); + if (IS_ERR(hw)) { pr_err("%s: failed to register clock\n", node->full_name); return; } - clk_register_clkdev(clk, NULL, name); - of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_hw_register_clkdev(hw, NULL, name); + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", moxart_of_pll_clk_init); @@ -57,7 +58,8 @@ CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", static void __init moxart_of_apb_clk_init(struct device_node *node) { static void __iomem *base; - struct clk *clk, *pll_clk; + struct clk_hw *hw; + struct clk *pll_clk; unsigned int div, val; unsigned int div_idx[] = { 2, 3, 4, 6, 8}; const char *name = node->name; @@ -85,14 +87,14 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) return; } - clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div); - if (IS_ERR(clk)) { + hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div); + if (IS_ERR(hw)) { pr_err("%s: failed to register clock\n", node->full_name); return; } - clk_register_clkdev(clk, NULL, name); - of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_hw_register_clkdev(hw, NULL, name); + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock", moxart_of_apb_clk_init); -- cgit v0.10.2 From 416886ad1eb0f90f1ee6415ede7037865fc58a2d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:20 -0700 Subject: clk: nspire: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Daniel Tang Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c index 64f196a..f861011 100644 --- a/drivers/clk/clk-nspire.c +++ b/drivers/clk/clk-nspire.c @@ -69,7 +69,7 @@ static void __init nspire_ahbdiv_setup(struct device_node *node, { u32 val; void __iomem *io; - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; const char *parent_name; struct nspire_clk_info info; @@ -85,10 +85,10 @@ static void __init nspire_ahbdiv_setup(struct device_node *node, of_property_read_string(node, "clock-output-names", &clk_name); parent_name = of_clk_get_parent_name(node, 0); - clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, - 1, info.base_ahb_ratio); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + hw = clk_hw_register_fixed_factor(NULL, clk_name, parent_name, 0, + 1, info.base_ahb_ratio); + if (!IS_ERR(hw)) + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); } static void __init nspire_ahbdiv_setup_cx(struct device_node *node) @@ -111,7 +111,7 @@ static void __init nspire_clk_setup(struct device_node *node, { u32 val; void __iomem *io; - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; struct nspire_clk_info info; @@ -125,9 +125,10 @@ static void __init nspire_clk_setup(struct device_node *node, of_property_read_string(node, "clock-output-names", &clk_name); - clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, info.base_clock); - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); + hw = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, + info.base_clock); + if (!IS_ERR(hw)) + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); else return; -- cgit v0.10.2 From c742e365a7e03a34363023526fe53c9bc11e294b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:21 -0700 Subject: clk: palmas: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Peter Ujfalusi Cc: Nishanth Menon Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index 8328863..31f590c 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c @@ -41,7 +41,6 @@ struct palmas_clk32k_desc { struct palmas_clock_info { struct device *dev; - struct clk *clk; struct clk_hw hw; struct palmas *palmas; const struct palmas_clk32k_desc *clk_desc; @@ -218,7 +217,7 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo) } if (cinfo->ext_control_pin) { - ret = clk_prepare(cinfo->clk); + ret = clk_prepare(cinfo->hw.clk); if (ret < 0) { dev_err(cinfo->dev, "Clock prep failed, %d\n", ret); return ret; @@ -242,7 +241,6 @@ static int palmas_clks_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; const struct palmas_clks_of_match_data *match_data; struct palmas_clock_info *cinfo; - struct clk *clk; int ret; match_data = of_device_get_match_data(&pdev->dev); @@ -261,22 +259,20 @@ static int palmas_clks_probe(struct platform_device *pdev) cinfo->clk_desc = &match_data->desc; cinfo->hw.init = &match_data->init; - clk = devm_clk_register(&pdev->dev, &cinfo->hw); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + ret = devm_clk_hw_register(&pdev->dev, &cinfo->hw); + if (ret) { dev_err(&pdev->dev, "Fail to register clock %s, %d\n", match_data->desc.clk_name, ret); return ret; } - cinfo->clk = clk; ret = palmas_clks_init_configure(cinfo); if (ret < 0) { dev_err(&pdev->dev, "Clock config failed, %d\n", ret); return ret; } - ret = of_clk_add_provider(node, of_clk_src_simple_get, cinfo->clk); + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &cinfo->hw); if (ret < 0) dev_err(&pdev->dev, "Fail to add clock driver, %d\n", ret); return ret; -- cgit v0.10.2 From 4cf915dfb8ede6e2673b4f1b2d2518ef4fe6620c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:22 -0700 Subject: clk: pwm: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Janusz Uzycki Cc: Philipp Zabel Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index 1630a1f..8cb9d11 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -61,7 +61,6 @@ static int clk_pwm_probe(struct platform_device *pdev) struct pwm_device *pwm; struct pwm_args pargs; const char *clk_name; - struct clk *clk; int ret; clk_pwm = devm_kzalloc(&pdev->dev, sizeof(*clk_pwm), GFP_KERNEL); @@ -107,11 +106,11 @@ static int clk_pwm_probe(struct platform_device *pdev) clk_pwm->pwm = pwm; clk_pwm->hw.init = &init; - clk = devm_clk_register(&pdev->dev, &clk_pwm->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(&pdev->dev, &clk_pwm->hw); + if (ret) + return ret; - return of_clk_add_provider(node, of_clk_src_simple_get, clk); + return of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clk_pwm->hw); } static int clk_pwm_remove(struct platform_device *pdev) -- cgit v0.10.2 From a8b6e85db6a65132ebc85e38b6391669b37b36f8 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:23 -0700 Subject: clk: rk808: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Chris Zhong Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c index 7438303..faa447e 100644 --- a/drivers/clk/clk-rk808.c +++ b/drivers/clk/clk-rk808.c @@ -22,11 +22,8 @@ #include #include -#define RK808_NR_OUTPUT 2 - struct rk808_clkout { struct rk808 *rk808; - struct clk_onecell_data clk_data; struct clk_hw clkout1_hw; struct clk_hw clkout2_hw; }; @@ -85,14 +82,28 @@ static const struct clk_ops rk808_clkout2_ops = { .recalc_rate = rk808_clkout_recalc_rate, }; +static struct clk_hw * +of_clk_rk808_get(struct of_phandle_args *clkspec, void *data) +{ + struct rk808_clkout *rk808_clkout = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= 2) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return idx ? &rk808_clkout->clkout2_hw : &rk808_clkout->clkout1_hw; +} + static int rk808_clkout_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); struct i2c_client *client = rk808->i2c; struct device_node *node = client->dev.of_node; struct clk_init_data init = {}; - struct clk **clk_table; struct rk808_clkout *rk808_clkout; + int ret; rk808_clkout = devm_kzalloc(&client->dev, sizeof(*rk808_clkout), GFP_KERNEL); @@ -101,11 +112,6 @@ static int rk808_clkout_probe(struct platform_device *pdev) rk808_clkout->rk808 = rk808; - clk_table = devm_kcalloc(&client->dev, RK808_NR_OUTPUT, - sizeof(struct clk *), GFP_KERNEL); - if (!clk_table) - return -ENOMEM; - init.parent_names = NULL; init.num_parents = 0; init.name = "rk808-clkout1"; @@ -116,10 +122,9 @@ static int rk808_clkout_probe(struct platform_device *pdev) of_property_read_string_index(node, "clock-output-names", 0, &init.name); - clk_table[0] = devm_clk_register(&client->dev, - &rk808_clkout->clkout1_hw); - if (IS_ERR(clk_table[0])) - return PTR_ERR(clk_table[0]); + ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout1_hw); + if (ret) + return ret; init.name = "rk808-clkout2"; init.ops = &rk808_clkout2_ops; @@ -129,16 +134,11 @@ static int rk808_clkout_probe(struct platform_device *pdev) of_property_read_string_index(node, "clock-output-names", 1, &init.name); - clk_table[1] = devm_clk_register(&client->dev, - &rk808_clkout->clkout2_hw); - if (IS_ERR(clk_table[1])) - return PTR_ERR(clk_table[1]); - - rk808_clkout->clk_data.clks = clk_table; - rk808_clkout->clk_data.clk_num = RK808_NR_OUTPUT; + ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout2_hw); + if (ret) + return ret; - return of_clk_add_provider(node, of_clk_src_onecell_get, - &rk808_clkout->clk_data); + return of_clk_add_hw_provider(node, of_clk_rk808_get, &rk808_clkout); } static int rk808_clkout_remove(struct platform_device *pdev) -- cgit v0.10.2 From 93ae00be20d872bfa3099e6376442362aaa8d567 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:25 -0700 Subject: clk: scpi: Migrate to clk_hw based OF and registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Sudeep Holla Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 6962ee5..2a3e9d8 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -146,13 +146,13 @@ static const struct of_device_id scpi_clk_match[] = { {} }; -static struct clk * +static int scpi_clk_ops_init(struct device *dev, const struct of_device_id *match, struct scpi_clk *sclk, const char *name) { struct clk_init_data init; - struct clk *clk; unsigned long min = 0, max = 0; + int ret; init.name = name; init.flags = 0; @@ -164,18 +164,18 @@ scpi_clk_ops_init(struct device *dev, const struct of_device_id *match, if (init.ops == &scpi_dvfs_ops) { sclk->info = sclk->scpi_ops->dvfs_get_info(sclk->id); if (IS_ERR(sclk->info)) - return NULL; + return PTR_ERR(sclk->info); } else if (init.ops == &scpi_clk_ops) { if (sclk->scpi_ops->clk_get_range(sclk->id, &min, &max) || !max) - return NULL; + return -EINVAL; } else { - return NULL; + return -EINVAL; } - clk = devm_clk_register(dev, &sclk->hw); - if (!IS_ERR(clk) && max) + ret = devm_clk_hw_register(dev, &sclk->hw); + if (!ret && max) clk_hw_set_rate_range(&sclk->hw, min, max); - return clk; + return ret; } struct scpi_clk_data { @@ -183,7 +183,7 @@ struct scpi_clk_data { unsigned int clk_num; }; -static struct clk * +static struct clk_hw * scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data) { struct scpi_clk *sclk; @@ -193,7 +193,7 @@ scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data) for (count = 0; count < clk_data->clk_num; count++) { sclk = clk_data->clk[count]; if (idx == sclk->id) - return sclk->hw.clk; + return &sclk->hw; } return ERR_PTR(-EINVAL); @@ -202,8 +202,7 @@ scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data) static int scpi_clk_add(struct device *dev, struct device_node *np, const struct of_device_id *match) { - struct clk **clks; - int idx, count; + int idx, count, err; struct scpi_clk_data *clk_data; count = of_property_count_strings(np, "clock-output-names"); @@ -222,10 +221,6 @@ static int scpi_clk_add(struct device *dev, struct device_node *np, if (!clk_data->clk) return -ENOMEM; - clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL); - if (!clks) - return -ENOMEM; - for (idx = 0; idx < count; idx++) { struct scpi_clk *sclk; const char *name; @@ -249,15 +244,15 @@ static int scpi_clk_add(struct device *dev, struct device_node *np, sclk->id = val; - clks[idx] = scpi_clk_ops_init(dev, match, sclk, name); - if (IS_ERR_OR_NULL(clks[idx])) + err = scpi_clk_ops_init(dev, match, sclk, name); + if (err) dev_err(dev, "failed to register clock '%s'\n", name); else dev_dbg(dev, "Registered clock '%s'\n", name); clk_data->clk[idx] = sclk; } - return of_clk_add_provider(np, scpi_of_clk_src_get, clk_data); + return of_clk_add_hw_provider(np, scpi_of_clk_src_get, clk_data); } static int scpi_clocks_remove(struct platform_device *pdev) -- cgit v0.10.2 From d06e46c25a8945fe3e6f5385221a3551f0866f79 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:26 -0700 Subject: clk: si514: Migrate to clk_hw based OF and registration APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Sebastian Hesselbarth Cc: Guenter Roeck Cc: Sören Brinkmann Cc: Mike Looijmans Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index ceef25b..09b6718 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -305,7 +305,6 @@ static int si514_probe(struct i2c_client *client, { struct clk_si514 *data; struct clk_init_data init; - struct clk *clk; int err; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); @@ -330,13 +329,13 @@ static int si514_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - clk = devm_clk_register(&client->dev, &data->hw); - if (IS_ERR(clk)) { + err = devm_clk_hw_register(&client->dev, &data->hw); + if (err) { dev_err(&client->dev, "clock registration failed\n"); - return PTR_ERR(clk); + return err; } - err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get, - clk); + err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get, + &data->hw); if (err) { dev_err(&client->dev, "unable to add clk provider\n"); return err; -- cgit v0.10.2 From 4d89c3d54e0b2d0edea0ab5cf62fd464a0473bad Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:27 -0700 Subject: clk: si5351: Migrate to clk_hw based OF and registration APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Sebastian Hesselbarth Cc: Guenter Roeck Cc: Sören Brinkmann Cc: Mike Looijmans Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index b1bc12c..b051db4 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -54,7 +54,6 @@ struct si5351_driver_data { enum si5351_variant variant; struct i2c_client *client; struct regmap *regmap; - struct clk_onecell_data onecell; struct clk *pxtal; const char *pxtal_name; @@ -66,6 +65,7 @@ struct si5351_driver_data { struct si5351_hw_data pll[2]; struct si5351_hw_data *msynth; struct si5351_hw_data *clkout; + size_t num_clkout; }; static const char * const si5351_input_names[] = { @@ -1307,11 +1307,31 @@ put_child: of_node_put(child); return -EINVAL; } + +static struct clk_hw * +si53351_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct si5351_driver_data *drvdata = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= drvdata->num_clkout) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &drvdata->clkout[idx].hw; +} #else static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant) { return 0; } + +static struct clk_hw * +si53351_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + return NULL; +} #endif /* CONFIG_OF */ static int si5351_i2c_probe(struct i2c_client *client, @@ -1321,7 +1341,6 @@ static int si5351_i2c_probe(struct i2c_client *client, struct si5351_platform_data *pdata; struct si5351_driver_data *drvdata; struct clk_init_data init; - struct clk *clk; const char *parent_names[4]; u8 num_parents, num_clocks; int ret, n; @@ -1438,10 +1457,9 @@ static int si5351_i2c_probe(struct i2c_client *client, init.num_parents = 1; } drvdata->xtal.init = &init; - clk = devm_clk_register(&client->dev, &drvdata->xtal); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->xtal); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } @@ -1456,11 +1474,10 @@ static int si5351_i2c_probe(struct i2c_client *client, init.num_parents = 1; } drvdata->clkin.init = &init; - clk = devm_clk_register(&client->dev, &drvdata->clkin); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->clkin); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } } @@ -1480,10 +1497,9 @@ static int si5351_i2c_probe(struct i2c_client *client, init.flags = 0; init.parent_names = parent_names; init.num_parents = num_parents; - clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } @@ -1505,10 +1521,9 @@ static int si5351_i2c_probe(struct i2c_client *client, init.parent_names = parent_names; init.num_parents = num_parents; } - clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } @@ -1524,13 +1539,9 @@ static int si5351_i2c_probe(struct i2c_client *client, sizeof(*drvdata->msynth), GFP_KERNEL); drvdata->clkout = devm_kzalloc(&client->dev, num_clocks * sizeof(*drvdata->clkout), GFP_KERNEL); + drvdata->num_clkout = num_clocks; - drvdata->onecell.clk_num = num_clocks; - drvdata->onecell.clks = devm_kzalloc(&client->dev, - num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL); - - if (WARN_ON(!drvdata->msynth || !drvdata->clkout || - !drvdata->onecell.clks)) { + if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) { ret = -ENOMEM; goto err_clk; } @@ -1547,11 +1558,11 @@ static int si5351_i2c_probe(struct i2c_client *client, init.flags |= CLK_SET_RATE_PARENT; init.parent_names = parent_names; init.num_parents = 2; - clk = devm_clk_register(&client->dev, &drvdata->msynth[n].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, + &drvdata->msynth[n].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } } @@ -1575,19 +1586,19 @@ static int si5351_i2c_probe(struct i2c_client *client, init.flags |= CLK_SET_RATE_PARENT; init.parent_names = parent_names; init.num_parents = num_parents; - clk = devm_clk_register(&client->dev, &drvdata->clkout[n].hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(&client->dev, + &drvdata->clkout[n].hw); + if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - ret = PTR_ERR(clk); goto err_clk; } - drvdata->onecell.clks[n] = clk; /* set initial clkout rate */ if (pdata->clkout[n].rate != 0) { int ret; - ret = clk_set_rate(clk, pdata->clkout[n].rate); + ret = clk_set_rate(drvdata->clkout[n].hw.clk, + pdata->clkout[n].rate); if (ret != 0) { dev_err(&client->dev, "Cannot set rate : %d\n", ret); @@ -1595,8 +1606,8 @@ static int si5351_i2c_probe(struct i2c_client *client, } } - ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, - &drvdata->onecell); + ret = of_clk_add_hw_provider(client->dev.of_node, si53351_of_clk_get, + drvdata); if (ret) { dev_err(&client->dev, "unable to add clk provider\n"); goto err_clk; -- cgit v0.10.2 From a340dae9de5df79d1d09ab7eae6cb8bbeb77b996 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:28 -0700 Subject: clk: si570: Migrate to clk_hw based OF and registration APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Guenter Roeck Cc: Sören Brinkmann Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index d566485..646af1d 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -408,7 +408,6 @@ static int si570_probe(struct i2c_client *client, { struct clk_si570 *data; struct clk_init_data init; - struct clk *clk; u32 initial_fout, factory_fout, stability; int err; enum clk_si570_variant variant = id->driver_data; @@ -462,13 +461,13 @@ static int si570_probe(struct i2c_client *client, if (err) return err; - clk = devm_clk_register(&client->dev, &data->hw); - if (IS_ERR(clk)) { + err = devm_clk_hw_register(&client->dev, &data->hw); + if (err) { dev_err(&client->dev, "clock registration failed\n"); - return PTR_ERR(clk); + return err; } - err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get, - clk); + err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get, + &data->hw); if (err) { dev_err(&client->dev, "unable to add clk provider\n"); return err; @@ -477,7 +476,7 @@ static int si570_probe(struct i2c_client *client, /* Read the requested initial output frequency from device tree */ if (!of_property_read_u32(client->dev.of_node, "clock-frequency", &initial_fout)) { - err = clk_set_rate(clk, initial_fout); + err = clk_set_rate(data->hw.clk, initial_fout); if (err) { of_clk_del_provider(client->dev.of_node); return err; -- cgit v0.10.2 From f5b3715ecf851da45f27e28120b9c5c9ddeccb5f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:30 -0700 Subject: clk: twl6040: Migrate to clk_hw based registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Peter Ujfalusi Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index c98b1ec..7b222a5 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -30,7 +30,6 @@ struct twl6040_pdmclk { struct twl6040 *twl6040; struct device *dev; struct clk_hw pdmclk_hw; - struct clk *clk; int enabled; }; @@ -93,6 +92,7 @@ static int twl6040_pdmclk_probe(struct platform_device *pdev) { struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent); struct twl6040_pdmclk *clkdata; + int ret; clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL); if (!clkdata) @@ -102,14 +102,15 @@ static int twl6040_pdmclk_probe(struct platform_device *pdev) clkdata->twl6040 = twl6040; clkdata->pdmclk_hw.init = &twl6040_pdmclk_init; - clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->pdmclk_hw); - if (IS_ERR(clkdata->clk)) - return PTR_ERR(clkdata->clk); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->pdmclk_hw); + if (ret) + return ret; platform_set_drvdata(pdev, clkdata); - return of_clk_add_provider(pdev->dev.parent->of_node, - of_clk_src_simple_get, clkdata->clk); + return of_clk_add_hw_provider(pdev->dev.parent->of_node, + of_clk_hw_simple_get, + &clkdata->pdmclk_hw); } static struct platform_driver twl6040_pdmclk_driver = { -- cgit v0.10.2 From 759fa9613245b99b21c25b0aecf9919fb0e96c31 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:32 -0700 Subject: clk: vt8500: Migrate to clk_hw based registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Sebastian Hesselbarth Cc: Tony Prisk Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index 37368a3..4161a6f 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -232,7 +232,7 @@ static const struct clk_ops vt8500_gated_divisor_clk_ops = { static __init void vtwm_device_clk_init(struct device_node *node) { u32 en_reg, div_reg; - struct clk *clk; + struct clk_hw *hw; struct clk_device *dev_clk; const char *clk_name = node->name; const char *parent_name; @@ -301,13 +301,14 @@ static __init void vtwm_device_clk_init(struct device_node *node) dev_clk->hw.init = &init; - clk = clk_register(NULL, &dev_clk->hw); - if (WARN_ON(IS_ERR(clk))) { + hw = &dev_clk->hw; + rc = clk_hw_register(NULL, hw); + if (WARN_ON(rc)) { kfree(dev_clk); return; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, clk_name, NULL); + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); + clk_hw_register_clkdev(hw, clk_name, NULL); } CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init); @@ -681,7 +682,7 @@ static const struct clk_ops vtwm_pll_ops = { static __init void vtwm_pll_clk_init(struct device_node *node, int pll_type) { u32 reg; - struct clk *clk; + struct clk_hw *hw; struct clk_pll *pll_clk; const char *clk_name = node->name; const char *parent_name; @@ -714,13 +715,14 @@ static __init void vtwm_pll_clk_init(struct device_node *node, int pll_type) pll_clk->hw.init = &init; - clk = clk_register(NULL, &pll_clk->hw); - if (WARN_ON(IS_ERR(clk))) { + hw = &pll_clk->hw; + rc = clk_hw_register(NULL, &pll_clk->hw); + if (WARN_ON(rc)) { kfree(pll_clk); return; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, clk_name, NULL); + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); + clk_hw_register_clkdev(hw, clk_name, NULL); } -- cgit v0.10.2 From cc671d13b6a1d1f6db2093994ff75220ce621234 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:33 -0700 Subject: clk: wm831x: Migrate to clk_hw based registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Mark Brown Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 88def4b..f4fdac5 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -24,9 +24,6 @@ struct wm831x_clk { struct clk_hw xtal_hw; struct clk_hw fll_hw; struct clk_hw clkout_hw; - struct clk *xtal; - struct clk *fll; - struct clk *clkout; bool xtal_ena; }; @@ -370,19 +367,19 @@ static int wm831x_clk_probe(struct platform_device *pdev) clkdata->xtal_ena = ret & WM831X_XTAL_ENA; clkdata->xtal_hw.init = &wm831x_xtal_init; - clkdata->xtal = devm_clk_register(&pdev->dev, &clkdata->xtal_hw); - if (IS_ERR(clkdata->xtal)) - return PTR_ERR(clkdata->xtal); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->xtal_hw); + if (ret) + return ret; clkdata->fll_hw.init = &wm831x_fll_init; - clkdata->fll = devm_clk_register(&pdev->dev, &clkdata->fll_hw); - if (IS_ERR(clkdata->fll)) - return PTR_ERR(clkdata->fll); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->fll_hw); + if (ret) + return ret; clkdata->clkout_hw.init = &wm831x_clkout_init; - clkdata->clkout = devm_clk_register(&pdev->dev, &clkdata->clkout_hw); - if (IS_ERR(clkdata->clkout)) - return PTR_ERR(clkdata->clkout); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->clkout_hw); + if (ret) + return ret; platform_set_drvdata(pdev, clkdata); -- cgit v0.10.2 From 120c1552839036f0fb2c01fffb8d8ce4049b729a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Aug 2016 15:38:27 -0700 Subject: clk: qcom: Migrate to clk_hw based registration and OF APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers in this driver, allowing us to move closer to a clear split of consumer and provider clk APIs. Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/clk-regmap.c b/drivers/clk/qcom/clk-regmap.c index a58ba39..1c856d3 100644 --- a/drivers/clk/qcom/clk-regmap.c +++ b/drivers/clk/qcom/clk-regmap.c @@ -101,14 +101,13 @@ EXPORT_SYMBOL_GPL(clk_disable_regmap); * clk_regmap struct via this function so that the regmap is initialized * and so that the clock is registered with the common clock framework. */ -struct clk *devm_clk_register_regmap(struct device *dev, - struct clk_regmap *rclk) +int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk) { if (dev && dev_get_regmap(dev, NULL)) rclk->regmap = dev_get_regmap(dev, NULL); else if (dev && dev->parent) rclk->regmap = dev_get_regmap(dev->parent, NULL); - return devm_clk_register(dev, &rclk->hw); + return devm_clk_hw_register(dev, &rclk->hw); } EXPORT_SYMBOL_GPL(devm_clk_register_regmap); diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h index 491a63d..90d95cd 100644 --- a/drivers/clk/qcom/clk-regmap.h +++ b/drivers/clk/qcom/clk-regmap.h @@ -39,7 +39,6 @@ struct clk_regmap { int clk_is_enabled_regmap(struct clk_hw *hw); int clk_enable_regmap(struct clk_hw *hw); void clk_disable_regmap(struct clk_hw *hw); -struct clk * -devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk); +int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk); #endif diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index f7c226a..fffcbaf 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -27,8 +27,8 @@ struct qcom_cc { struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; + struct clk_regmap **rclks; + size_t num_rclks; }; const @@ -102,8 +102,8 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, struct device_node *clocks_node; struct clk_fixed_factor *factor; struct clk_fixed_rate *fixed; - struct clk *clk; struct clk_init_data init_data = { }; + int ret; clocks_node = of_find_node_by_path("/clocks"); if (clocks_node) @@ -121,9 +121,9 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, init_data.name = path; init_data.ops = &clk_fixed_rate_ops; - clk = devm_clk_register(dev, &fixed->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, &fixed->hw); + if (ret) + return ret; } of_node_put(node); @@ -141,9 +141,9 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, init_data.flags = 0; init_data.ops = &clk_fixed_factor_ops; - clk = devm_clk_register(dev, &factor->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, &factor->hw); + if (ret) + return ret; } return 0; @@ -174,42 +174,48 @@ int qcom_cc_register_sleep_clk(struct device *dev) } EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk); +static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec, + void *data) +{ + struct qcom_cc *cc = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= cc->num_rclks) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return cc->rclks[idx] ? &cc->rclks[idx]->hw : ERR_PTR(-ENOENT); +} + int qcom_cc_really_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc, struct regmap *regmap) { int i, ret; struct device *dev = &pdev->dev; - struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; struct qcom_reset_controller *reset; struct qcom_cc *cc; struct gdsc_desc *scd; size_t num_clks = desc->num_clks; struct clk_regmap **rclks = desc->clks; - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); + cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); if (!cc) return -ENOMEM; - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; + cc->rclks = rclks; + cc->num_rclks = num_clks; for (i = 0; i < num_clks; i++) { - if (!rclks[i]) { - clks[i] = ERR_PTR(-ENOENT); + if (!rclks[i]) continue; - } - clk = devm_clk_register_regmap(dev, rclks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; + + ret = devm_clk_register_regmap(dev, rclks[i]); + if (ret) + return ret; } - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); + ret = of_clk_add_hw_provider(dev->of_node, qcom_cc_clk_hw_get, cc); if (ret) return ret; diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c index 0f648fc..581a17f 100644 --- a/drivers/clk/qcom/gcc-mdm9615.c +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -1686,7 +1686,7 @@ static int gcc_mdm9615_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct regmap *regmap; - struct clk *clk; + int ret; int i; regmap = qcom_cc_map(pdev, &gcc_mdm9615_desc); @@ -1694,9 +1694,9 @@ static int gcc_mdm9615_probe(struct platform_device *pdev) return PTR_ERR(regmap); for (i = 0; i < ARRAY_SIZE(gcc_mdm9615_hws); i++) { - clk = devm_clk_register(dev, gcc_mdm9615_hws[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, gcc_mdm9615_hws[i]); + if (ret) + return ret; } return qcom_cc_really_probe(pdev, &gcc_mdm9615_desc, regmap); diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index bbf732b..3afe42c 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -3447,9 +3447,8 @@ MODULE_DEVICE_TABLE(of, gcc_msm8996_match_table); static int gcc_msm8996_probe(struct platform_device *pdev) { - struct clk *clk; struct device *dev = &pdev->dev; - int i; + int i, ret; struct regmap *regmap; regmap = qcom_cc_map(pdev, &gcc_msm8996_desc); @@ -3463,9 +3462,9 @@ static int gcc_msm8996_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21)); for (i = 0; i < ARRAY_SIZE(gcc_msm8996_hws); i++) { - clk = devm_clk_register(dev, gcc_msm8996_hws[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, gcc_msm8996_hws[i]); + if (ret) + return ret; } return qcom_cc_really_probe(pdev, &gcc_msm8996_desc, regmap); diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 1822045..ca97e11 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -3314,9 +3314,8 @@ MODULE_DEVICE_TABLE(of, mmcc_msm8996_match_table); static int mmcc_msm8996_probe(struct platform_device *pdev) { - struct clk *clk; struct device *dev = &pdev->dev; - int i; + int i, ret; struct regmap *regmap; regmap = qcom_cc_map(pdev, &mmcc_msm8996_desc); @@ -3329,9 +3328,9 @@ static int mmcc_msm8996_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x5054, BIT(15), 0); for (i = 0; i < ARRAY_SIZE(mmcc_msm8996_hws); i++) { - clk = devm_clk_register(dev, mmcc_msm8996_hws[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, mmcc_msm8996_hws[i]); + if (ret) + return ret; } return qcom_cc_really_probe(pdev, &mmcc_msm8996_desc, regmap); -- cgit v0.10.2 From 8b2bdc7690bb2ae85b198c065c8f3511180eafef Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Aug 2016 15:37:57 -0700 Subject: clk: h8300: Migrate to clk_hw based registration APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Yoshinori Sato Cc: Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index 4bf44a2..715b882 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -14,7 +14,7 @@ static DEFINE_SPINLOCK(clklock); static void __init h8300_div_clk_setup(struct device_node *node) { unsigned int num_parents; - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; const char *parent_name; void __iomem *divcr = NULL; @@ -38,15 +38,15 @@ static void __init h8300_div_clk_setup(struct device_node *node) parent_name = of_clk_get_parent_name(node, 0); of_property_read_u32(node, "renesas,width", &width); - clk = clk_register_divider(NULL, clk_name, parent_name, + hw = clk_hw_register_divider(NULL, clk_name, parent_name, CLK_SET_RATE_GATE, divcr, offset, width, CLK_DIVIDER_POWER_OF_TWO, &clklock); - if (!IS_ERR(clk)) { - of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (!IS_ERR(hw)) { + of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); return; } pr_err("%s: failed to register %s div clock (%ld)\n", - __func__, clk_name, PTR_ERR(clk)); + __func__, clk_name, PTR_ERR(hw)); error: if (divcr) iounmap(divcr); diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index c9c2fd5..a263124 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -84,11 +84,11 @@ static const struct clk_ops pll_ops = { static void __init h8s2678_pll_clk_setup(struct device_node *node) { unsigned int num_parents; - struct clk *clk; const char *clk_name = node->name; const char *parent_name; struct pll_clock *pll_clock; struct clk_init_data init; + int ret; num_parents = of_clk_get_parent_count(node); if (!num_parents) { @@ -121,14 +121,14 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node) init.num_parents = 1; pll_clock->hw.init = &init; - clk = clk_register(NULL, &pll_clock->hw); - if (IS_ERR(clk)) { - pr_err("%s: failed to register %s div clock (%ld)\n", - __func__, clk_name, PTR_ERR(clk)); + ret = clk_hw_register(NULL, &pll_clock->hw); + if (ret) { + pr_err("%s: failed to register %s div clock (%d)\n", + __func__, clk_name, ret); goto unmap_pllcr; } - of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clock->hw); return; unmap_pllcr: -- cgit v0.10.2 From 6d91f2c0141330b919ae4d13395f38c341469564 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 25 Aug 2016 12:28:07 +0100 Subject: clk: qcom: select GDSC for msm8996 gcc and mmcc This patch selects QCOM_GDSC Kconfig for msm8996 GCC and MMCC clock controllers, as these provide some of the gdscs on the SOC. Also selecting this config will make it align with other drivers which do the same. Signed-off-by: Srinivas Kandagatla Fixes: 52111672f791 ("clk: qcom: gdsc: Add GDSCs in msm8996 GCC") Fixes: 7e824d507909 ("clk: qcom: gdsc: Add mmcc gdscs for msm8996 family") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 1e7c86f..0146d3c 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -134,6 +134,7 @@ config MSM_MMCC_8974 config MSM_GCC_8996 tristate "MSM8996 Global Clock Controller" + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the global clock controller on msm8996 devices. @@ -143,6 +144,7 @@ config MSM_GCC_8996 config MSM_MMCC_8996 tristate "MSM8996 Multimedia Clock Controller" select MSM_GCC_8996 + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the multimedia clock controller on msm8996 devices. -- cgit v0.10.2 From ce61966c05f276294b6be04d1765ad0d827ddefd Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 25 Aug 2016 12:20:46 +0100 Subject: clk: gcc-msm8996: Fix pcie 2 pipe register offset This patch corrects the register offset for pcie2 pipe clock. Offset according to datasheet is 0x6e018 instead of 0x6e108. Signed-off-by: Srinivas Kandagatla Fixes: b1e010c0730a ("clk: qcom: Add MSM8996 Global Clock Control (GCC) driver") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 3afe42c..2c36771 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -2592,9 +2592,9 @@ static struct clk_branch gcc_pcie_2_aux_clk = { }; static struct clk_branch gcc_pcie_2_pipe_clk = { - .halt_reg = 0x6e108, + .halt_reg = 0x6e018, .clkr = { - .enable_reg = 0x6e108, + .enable_reg = 0x6e018, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_2_pipe_clk", -- cgit v0.10.2 From 62d157587efa54487c32b3c2ca76979348e0b90a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 25 Aug 2016 12:20:47 +0100 Subject: clk: gcc-msm8996: add missing pcie phy reset lines This patch adds missing 2 PCIE common reset lines. Signed-off-by: Srinivas Kandagatla Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 2c36771..ebe5d18 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -3404,6 +3404,8 @@ static const struct qcom_reset_map gcc_msm8996_resets[] = { [GCC_PCIE_2_BCR] = { 0x6e000 }, [GCC_PCIE_2_PHY_BCR] = { 0x6e038 }, [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f014 }, + [GCC_PCIE_PHY_COM_NOCSR_BCR] = { 0x6f00c }, [GCC_DCD_BCR] = { 0x70000 }, [GCC_OBT_ODT_BCR] = { 0x73000 }, [GCC_UFS_BCR] = { 0x75000 }, diff --git a/include/dt-bindings/clock/qcom,gcc-msm8996.h b/include/dt-bindings/clock/qcom,gcc-msm8996.h index 6f814db..b7ea1e8 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8996.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8996.h @@ -335,6 +335,9 @@ #define GCC_MSMPU_BCR 98 #define GCC_MSS_Q6_BCR 99 #define GCC_QREFS_VBG_CAL_BCR 100 +#define GCC_PCIE_PHY_COM_BCR 101 +#define GCC_PCIE_PHY_COM_NOCSR_BCR 102 + /* Indexes for GDSCs */ #define AGGRE0_NOC_GDSC 0 -- cgit v0.10.2 From 50581cc4f14f0f704b967cd4664a34d7644be816 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 22 Aug 2016 11:19:32 +0200 Subject: clk: versatile add DT bindings for the ICST CM variants The Integrator/AP and Integrator/CP core modules have special versions of the ICST525 interface hardcoding some bits. Create special compatible strings to identify these variants, also explain a bit what is going on. Cc: devicetree@vger.kernel.org Cc: Russell King Signed-off-by: Linus Walleij Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt b/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt index 8b7177c..2746811 100644 --- a/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt +++ b/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt @@ -5,20 +5,50 @@ Technology (IDT). ARM integrated these oscillators deeply into their reference designs by adding special control registers that manage such oscillators to their system controllers. -The ARM system controller contains logic to serialize and initialize +The various ARM system controllers contain logic to serialize and initialize an ICST clock request after a write to the 32 bit register at an offset into the system controller. Furthermore, to even be able to alter one of these frequencies, the system controller must first be unlocked by writing a special token to another offset in the system controller. +Some ARM hardware contain special versions of the serial interface that only +connects the low 8 bits of the VDW (missing one bit), hardwires RDW to +different values and sometimes also hardwire the output divider. They +therefore have special compatible strings as per this table (the OD value is +the value on the pins, not the resulting output divider): + +Hardware variant: RDW OD VDW + +Integrator/AP 22 1 Bit 8 0, rest variable +integratorap-cm + +Integrator/AP 46 3 Bit 8 0, rest variable +integratorap-sys + +Integrator/AP 22 or 1 17 or (33 or 25 MHz) +integratorap-pci 14 1 14 + +Integrator/CP 22 variable Bit 8 0, rest variable +integratorcp-cm-core + +Integrator/CP 22 variable Bit 8 0, rest variable +integratorcp-cm-mem + The ICST oscillator must be provided inside a system controller node. Required properties: +- compatible: must be one of + "arm,syscon-icst525" + "arm,syscon-icst307" + "arm,syscon-icst525-integratorap-cm" + "arm,syscon-icst525-integratorap-sys" + "arm,syscon-icst525-integratorap-pci" + "arm,syscon-icst525-integratorcp-cm-core" + "arm,syscon-icst525-integratorcp-cm-mem" - lock-offset: the offset address into the system controller where the unlocking register is located - vco-offset: the offset address into the system controller where the ICST control register is located (even 32 bit address) -- compatible: must be one of "arm,syscon-icst525" or "arm,syscon-icst307" - #clock-cells: must be <0> - clocks: parent clock, since the ICST needs a parent clock to derive its frequency from, this attribute is compulsory. -- cgit v0.10.2 From 5e23c593057520db45b089644863989d4b21e31f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 22 Aug 2016 11:19:33 +0200 Subject: clk: versatile/icst: add Integrator core module clocks The Integrator/AP and Integrator/CP have special derivatives of the ICST525 control registers, where some bits have been hardwired but others are possible to adjust, resulting in a control register that makes it possible to set an even, desired megahertz value. The Integrator/AP and Integrator/CP have slightly different layout so we support them using different compatible strings. After adding these clocks, the Integrator-specific cpufreq driver can be switched over to use the generic operating point device tree cpufreq driver. Instead of simply writing a value to the oscillator control register we switch to the more elaborate method of providing a bitmask and use regmap_update_bits() to poke the right bits for the desired frequency, this is needed since these control registers sometimes control more than one clock. Cc: Russell King Signed-off-by: Linus Walleij Signed-off-by: Stephen Boyd diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 5e9b652..8f06473 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -27,6 +27,21 @@ /* Magic unlocking token used on all Versatile boards */ #define VERSATILE_LOCK_VAL 0xA05F +#define VERSATILE_AUX_OSC_BITS 0x7FFFF +#define INTEGRATOR_AP_CM_BITS 0xFF +#define INTEGRATOR_CP_CM_CORE_BITS 0x7FF +#define INTEGRATOR_CP_CM_MEM_BITS 0x7FF000 + +/** + * enum icst_control_type - the type of ICST control register + */ +enum icst_control_type { + ICST_VERSATILE, /* The standard type, all control bits available */ + ICST_INTEGRATOR_AP_CM, /* Only 8 bits of VDW available */ + ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ + ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ +}; + /** * struct clk_icst - ICST VCO clock wrapper * @hw: corresponding clock hardware entry @@ -34,6 +49,7 @@ * @lockreg: VCO lock register address * @params: parameters for this ICST instance * @rate: current rate + * @ctype: the type of control register for the ICST */ struct clk_icst { struct clk_hw hw; @@ -42,6 +58,7 @@ struct clk_icst { u32 lockreg_off; struct icst_params *params; unsigned long rate; + enum icst_control_type ctype; }; #define to_icst(_hw) container_of(_hw, struct clk_icst, hw) @@ -59,6 +76,44 @@ static int vco_get(struct clk_icst *icst, struct icst_vco *vco) ret = regmap_read(icst->map, icst->vcoreg_off, &val); if (ret) return ret; + + /* + * The Integrator/AP core clock can only access the low eight + * bits of the v PLL divider. Bit 8 is tied low and always zero, + * r is hardwired to 22 and output divider s is hardwired to 1 + * (divide by 2) according to the document + * "Integrator CM926EJ-S, CM946E-S, CM966E-S, CM1026EJ-S and + * CM1136JF-S User Guide" ARM DUI 0138E, page 3-13 thru 3-14. + */ + if (icst->ctype == ICST_INTEGRATOR_AP_CM) { + vco->v = val & INTEGRATOR_AP_CM_BITS; + vco->r = 22; + vco->s = 1; + return 0; + } + + /* + * The Integrator/CP core clock can access the low eight bits + * of the v PLL divider. Bit 8 is tied low and always zero, + * r is hardwired to 22 and the output divider s is accessible + * in bits 8 thru 10 according to the document + * "Integrator/CM940T, CM920T, CM740T, and CM720T User Guide" + * ARM DUI 0157A, page 3-20 thru 3-23 and 4-10. + */ + if (icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) { + vco->v = val & 0xFF; + vco->r = 22; + vco->s = (val >> 8) & 7; + return 0; + } + + if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) { + vco->v = (val >> 12) & 0xFF; + vco->r = 22; + vco->s = (val >> 20) & 7; + return 0; + } + vco->v = val & 0x1ff; vco->r = (val >> 9) & 0x7f; vco->s = (val >> 16) & 03; @@ -72,22 +127,52 @@ static int vco_get(struct clk_icst *icst, struct icst_vco *vco) */ static int vco_set(struct clk_icst *icst, struct icst_vco vco) { + u32 mask; u32 val; int ret; - ret = regmap_read(icst->map, icst->vcoreg_off, &val); - if (ret) - return ret; + /* Mask the bits used by the VCO */ + switch (icst->ctype) { + case ICST_INTEGRATOR_AP_CM: + mask = INTEGRATOR_AP_CM_BITS; + val = vco.v & 0xFF; + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.s != 1) + pr_err("ICST error: tried to use VOD != 1\n"); + if (vco.r != 22) + pr_err("ICST error: tried to use RDW != 22\n"); + break; + case ICST_INTEGRATOR_CP_CM_CORE: + mask = INTEGRATOR_CP_CM_CORE_BITS; /* Uses 12 bits */ + val = (vco.v & 0xFF) | vco.s << 8; + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.r != 22) + pr_err("ICST error: tried to use RDW != 22\n"); + break; + case ICST_INTEGRATOR_CP_CM_MEM: + mask = INTEGRATOR_CP_CM_MEM_BITS; /* Uses 12 bits */ + val = ((vco.v & 0xFF) << 12) | (vco.s << 20); + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.r != 22) + pr_err("ICST error: tried to use RDW != 22\n"); + break; + default: + /* Regular auxilary oscillator */ + mask = VERSATILE_AUX_OSC_BITS; + val = vco.v | (vco.r << 9) | (vco.s << 16); + break; + } - /* Mask the 18 bits used by the VCO */ - val &= ~0x7ffff; - val |= vco.v | (vco.r << 9) | (vco.s << 16); + pr_debug("ICST: new val = 0x%08x\n", val); /* This magic unlocks the VCO so it can be controlled */ ret = regmap_write(icst->map, icst->lockreg_off, VERSATILE_LOCK_VAL); if (ret) return ret; - ret = regmap_write(icst->map, icst->vcoreg_off, val); + ret = regmap_update_bits(icst->map, icst->vcoreg_off, mask, val); if (ret) return ret; /* This locks the VCO again */ @@ -121,6 +206,25 @@ static long icst_round_rate(struct clk_hw *hw, unsigned long rate, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (icst->ctype == ICST_INTEGRATOR_AP_CM || + icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) { + if (rate <= 12000000) + return 12000000; + if (rate >= 160000000) + return 160000000; + /* Slam to closest megahertz */ + return DIV_ROUND_CLOSEST(rate, 1000000) * 1000000; + } + + if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) { + if (rate <= 6000000) + return 6000000; + if (rate >= 66000000) + return 66000000; + /* Slam to closest 0.5 megahertz */ + return DIV_ROUND_CLOSEST(rate, 500000) * 500000; + } + vco = icst_hz_to_vco(icst->params, rate); return icst_hz(icst->params, vco); } @@ -148,7 +252,8 @@ static struct clk *icst_clk_setup(struct device *dev, const struct clk_icst_desc *desc, const char *name, const char *parent_name, - struct regmap *map) + struct regmap *map, + enum icst_control_type ctype) { struct clk *clk; struct clk_icst *icst; @@ -178,6 +283,7 @@ static struct clk *icst_clk_setup(struct device *dev, icst->params = pclone; icst->vcoreg_off = desc->vco_offset; icst->lockreg_off = desc->lock_offset; + icst->ctype = ctype; clk = clk_register(dev, &icst->hw); if (IS_ERR(clk)) { @@ -206,7 +312,8 @@ struct clk *icst_clk_register(struct device *dev, pr_err("could not initialize ICST regmap\n"); return ERR_CAST(map); } - return icst_clk_setup(dev, desc, name, parent_name, map); + return icst_clk_setup(dev, desc, name, parent_name, map, + ICST_VERSATILE); } EXPORT_SYMBOL_GPL(icst_clk_register); @@ -239,6 +346,28 @@ static const struct icst_params icst307_params = { .idx2s = icst307_idx2s, }; +/** + * The core modules on the Integrator/AP and Integrator/CP have + * especially crippled ICST525 control. + */ +static const struct icst_params icst525_apcp_cm_params = { + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, + /* Minimum 12 MHz, VDW = 4 */ + .vd_min = 12, + /* + * Maximum 160 MHz, VDW = 152 for all core modules, but + * CM926EJ-S, CM1026EJ-S and CM1136JF-S can actually + * go to 200 MHz (max VDW = 192). + */ + .vd_max = 192, + /* r is hardcoded to 22 and this is the actual divisor, +2 */ + .rd_min = 24, + .rd_max = 24, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, +}; + static void __init of_syscon_icst_setup(struct device_node *np) { struct device_node *parent; @@ -247,6 +376,7 @@ static void __init of_syscon_icst_setup(struct device_node *np) const char *name = np->name; const char *parent_name; struct clk *regclk; + enum icst_control_type ctype; /* We do not release this reference, we are using it perpetually */ parent = of_get_parent(np); @@ -269,11 +399,22 @@ static void __init of_syscon_icst_setup(struct device_node *np) return; } - if (of_device_is_compatible(np, "arm,syscon-icst525")) + if (of_device_is_compatible(np, "arm,syscon-icst525")) { icst_desc.params = &icst525_params; - else if (of_device_is_compatible(np, "arm,syscon-icst307")) + ctype = ICST_VERSATILE; + } else if (of_device_is_compatible(np, "arm,syscon-icst307")) { icst_desc.params = &icst307_params; - else { + ctype = ICST_VERSATILE; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-cm")) { + icst_desc.params = &icst525_apcp_cm_params; + ctype = ICST_INTEGRATOR_AP_CM; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-core")) { + icst_desc.params = &icst525_apcp_cm_params; + ctype = ICST_INTEGRATOR_CP_CM_CORE; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-mem")) { + icst_desc.params = &icst525_apcp_cm_params; + ctype = ICST_INTEGRATOR_CP_CM_MEM; + } else { pr_err("unknown ICST clock %s\n", name); return; } @@ -281,7 +422,7 @@ static void __init of_syscon_icst_setup(struct device_node *np) /* Parent clock name is not the same as node parent */ parent_name = of_clk_get_parent_name(np, 0); - regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map); + regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map, ctype); if (IS_ERR(regclk)) { pr_err("error setting up syscon ICST clock %s\n", name); return; @@ -294,5 +435,10 @@ CLK_OF_DECLARE(arm_syscon_icst525_clk, "arm,syscon-icst525", of_syscon_icst_setup); CLK_OF_DECLARE(arm_syscon_icst307_clk, "arm,syscon-icst307", of_syscon_icst_setup); - +CLK_OF_DECLARE(arm_syscon_integratorap_cm_clk, + "arm,syscon-icst525-integratorap-cm", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorcp_cm_core_clk, + "arm,syscon-icst525-integratorcp-cm-core", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorcp_cm_mem_clk, + "arm,syscon-icst525-integratorcp-cm-mem", of_syscon_icst_setup); #endif -- cgit v0.10.2 From 89af85253c32b67898c0f8bb06fe6e790e62846f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 20 Jul 2016 23:45:35 +0200 Subject: clk: sunxi-ng: mux: Rename mux macro to be consistent Rename the internal mux macro to be consistent with the other internal structure macros. Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index 653ade5..5d98549 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -83,7 +83,7 @@ struct ccu_div { struct ccu_div _struct = { \ .enable = _gate, \ .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ - .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ .common = { \ .reg = _reg, \ .hw.init = CLK_HW_INIT_PARENTS(_name, \ diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h index 3cf12bf..edf9215 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.h +++ b/drivers/clk/sunxi-ng/ccu_mp.h @@ -44,7 +44,7 @@ struct ccu_mp { .enable = _gate, \ .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \ - .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ .common = { \ .reg = _reg, \ .hw.init = CLK_HW_INIT_PARENTS(_name, \ diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index d35ce5e..83737c2 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -21,7 +21,7 @@ struct ccu_mux_internal { } variable_prediv; }; -#define SUNXI_CLK_MUX(_shift, _width) \ +#define _SUNXI_CCU_MUX(_shift, _width) \ { \ .shift = _shift, \ .width = _width, \ @@ -37,7 +37,7 @@ struct ccu_mux { #define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width, _flags) \ struct ccu_mux _struct = { \ - .mux = SUNXI_CLK_MUX(_shift, _width), \ + .mux = _SUNXI_CCU_MUX(_shift, _width), \ .common = { \ .reg = _reg, \ .hw.init = CLK_HW_INIT_PARENTS(_name, \ @@ -51,7 +51,7 @@ struct ccu_mux { _shift, _width, _gate, _flags) \ struct ccu_mux _struct = { \ .enable = _gate, \ - .mux = SUNXI_CLK_MUX(_shift, _width), \ + .mux = _SUNXI_CCU_MUX(_shift, _width), \ .common = { \ .reg = _reg, \ .hw.init = CLK_HW_INIT_PARENTS(_name, \ diff --git a/drivers/clk/sunxi-ng/ccu_nkm.h b/drivers/clk/sunxi-ng/ccu_nkm.h index fcb152f..35493fd 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.h +++ b/drivers/clk/sunxi-ng/ccu_nkm.h @@ -49,7 +49,7 @@ struct ccu_nkm { .k = _SUNXI_CCU_MULT(_kshift, _kwidth), \ .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \ .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ - .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ .common = { \ .reg = _reg, \ .hw.init = CLK_HW_INIT_PARENTS(_name, \ -- cgit v0.10.2 From 2b9c875c56f0bec92b301061fe3c2adb5e098b36 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 25 Aug 2016 14:21:56 +0800 Subject: clk: sunxi-ng: mux: Add support for mux tables Some clock muxes have holes, i.e. invalid or unconnected inputs, between parent mux values. Add support for specifying a mux table to map clock parents to mux values. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 1329b9a..68b32f1 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -107,6 +107,15 @@ u8 ccu_mux_helper_get_parent(struct ccu_common *common, parent = reg >> cm->shift; parent &= (1 << cm->width) - 1; + if (cm->table) { + int num_parents = clk_hw_get_num_parents(&common->hw); + int i; + + for (i = 0; i < num_parents; i++) + if (cm->table[i] == parent) + return i; + } + return parent; } @@ -117,6 +126,9 @@ int ccu_mux_helper_set_parent(struct ccu_common *common, unsigned long flags; u32 reg; + if (cm->table) + index = cm->table[index]; + spin_lock_irqsave(common->lock, flags); reg = readl(common->base + common->reg); diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index 83737c2..b1e0856 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -6,8 +6,9 @@ #include "ccu_common.h" struct ccu_mux_internal { - u8 shift; - u8 width; + u8 shift; + u8 width; + const u8 *table; struct { u8 index; @@ -21,12 +22,16 @@ struct ccu_mux_internal { } variable_prediv; }; -#define _SUNXI_CCU_MUX(_shift, _width) \ - { \ - .shift = _shift, \ - .width = _width, \ +#define _SUNXI_CCU_MUX_TABLE(_shift, _width, _table) \ + { \ + .shift = _shift, \ + .width = _width, \ + .table = _table, \ } +#define _SUNXI_CCU_MUX(_shift, _width) \ + _SUNXI_CCU_MUX_TABLE(_shift, _width, NULL) + struct ccu_mux { u16 reg; u32 enable; -- cgit v0.10.2 From ff5294db4161d7121c0251527d6ea2f1f9c91854 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 25 Aug 2016 14:21:57 +0800 Subject: clk: sunxi-ng: mux: support fixed pre-dividers on multiple parents Some clocks on the A31 have fixed pre-dividers on multiple parents. Add support for them. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 9af35954..4fa9374 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -184,15 +184,15 @@ static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, 0); static const char * const ahb2_parents[] = { "ahb1" , "pll-periph0" }; +static const struct ccu_mux_fixed_prediv ahb2_fixed_predivs[] = { + { .index = 1, .div = 2 }, +}; static struct ccu_mux ahb2_clk = { .mux = { .shift = 0, .width = 1, - - .fixed_prediv = { - .index = 1, - .div = 2, - }, + .fixed_predivs = ahb2_fixed_predivs, + .n_predivs = ARRAY_SIZE(ahb2_fixed_predivs), }, .common = { diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 68b32f1..7b17e0c 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -20,6 +20,7 @@ void ccu_mux_helper_adjust_parent_for_prediv(struct ccu_common *common, { u16 prediv = 1; u32 reg; + int i; if (!((common->features & CCU_FEATURE_FIXED_PREDIV) || (common->features & CCU_FEATURE_VARIABLE_PREDIV))) @@ -32,8 +33,9 @@ void ccu_mux_helper_adjust_parent_for_prediv(struct ccu_common *common, } if (common->features & CCU_FEATURE_FIXED_PREDIV) - if (parent_index == cm->fixed_prediv.index) - prediv = cm->fixed_prediv.div; + for (i = 0; i < cm->n_predivs; i++) + if (parent_index == cm->fixed_predivs[i].index) + prediv = cm->fixed_predivs[i].div; if (common->features & CCU_FEATURE_VARIABLE_PREDIV) if (parent_index == cm->variable_prediv.index) { diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index b1e0856..8eab173 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -5,15 +5,18 @@ #include "ccu_common.h" +struct ccu_mux_fixed_prediv { + u8 index; + u16 div; +}; + struct ccu_mux_internal { u8 shift; u8 width; const u8 *table; - struct { - u8 index; - u16 div; - } fixed_prediv; + const struct ccu_mux_fixed_prediv *fixed_predivs; + u8 n_predivs; struct { u8 index; -- cgit v0.10.2 From 8adfb08605a99d742853ff8cf4da5bc68db2028a Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 25 Aug 2016 14:21:58 +0800 Subject: clk: sunxi-ng: mux: Add clk notifier functions On sunxi we support cpufreq by changing the clock rate of PLL-CPU. It's possible the clock output of the PLL goes out of the CPU's operational limits when the PLL's multipliers / dividers are changed and it hasn't stabilized yet. This would result in the CPU hanging. To circumvent this, we temporarily switch the CPU mux clock to another stable clock before the rate change, and switch it back after the PLL stabilizes. This is done with clk notifiers registered on the PLL. This patch adds common functions for notifiers to reparent mux clocks. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 7b17e0c..a43ad52 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -8,7 +8,9 @@ * the License, or (at your option) any later version. */ +#include #include +#include #include "ccu_gate.h" #include "ccu_mux.h" @@ -199,3 +201,37 @@ const struct clk_ops ccu_mux_ops = { .determine_rate = __clk_mux_determine_rate, .recalc_rate = ccu_mux_recalc_rate, }; + +/* + * This clock notifier is called when the frequency of the of the parent + * PLL clock is to be changed. The idea is to switch the parent to a + * stable clock, such as the main oscillator, while the PLL frequency + * stabilizes. + */ +static int ccu_mux_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct ccu_mux_nb *mux = to_ccu_mux_nb(nb); + int ret = 0; + + if (event == PRE_RATE_CHANGE) { + mux->original_index = ccu_mux_helper_get_parent(mux->common, + mux->cm); + ret = ccu_mux_helper_set_parent(mux->common, mux->cm, + mux->bypass_index); + } else if (event == POST_RATE_CHANGE) { + ret = ccu_mux_helper_set_parent(mux->common, mux->cm, + mux->original_index); + } + + udelay(mux->delay_us); + + return notifier_from_errno(ret); +} + +int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb) +{ + mux_nb->clk_nb.notifier_call = ccu_mux_notifier_cb; + + return clk_notifier_register(clk, &mux_nb->clk_nb); +} diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index 8eab173..f5123a1 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -96,4 +96,18 @@ int ccu_mux_helper_set_parent(struct ccu_common *common, struct ccu_mux_internal *cm, u8 index); +struct ccu_mux_nb { + struct notifier_block clk_nb; + struct ccu_common *common; + struct ccu_mux_internal *cm; + + u32 delay_us; /* How many us to wait after reparenting */ + u8 bypass_index; /* Which parent to temporarily use */ + u8 original_index; /* This is set by the notifier callback */ +}; + +#define to_ccu_mux_nb(_nb) container_of(_nb, struct ccu_mux_nb, clk_nb) + +int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb); + #endif /* _CCU_MUX_H_ */ -- cgit v0.10.2 From c6e6c96d8fa6f21e80e625bdf56c9ef580f43acb Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 25 Aug 2016 14:21:59 +0800 Subject: clk: sunxi-ng: Add A31/A31s clocks Add a new style driver for the clock control unit in Allwinner A31/A31s. A few clocks are still missing: - MIPI PLL's HDMI mode support - EMAC clock Signed-off-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Maxime Ripard diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt index cb91507..eac4587 100644 --- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt +++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt @@ -2,7 +2,8 @@ Allwinner Clock Control Unit Binding ------------------------------------ Required properties : -- compatible: must contain one of the following compatible: +- compatible: must contain one of the following compatibles: + - "allwinner,sun6i-a31-ccu" - "allwinner,sun8i-h3-ccu" - reg: Must contain the registers base address and length diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 2afcbd3..a1dee86 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -51,6 +51,16 @@ config SUNXI_CCU_MP # SoC Drivers +config SUN6I_A31_CCU + bool "Support for the Allwinner A31/A31s CCU" + select SUNXI_CCU_DIV + select SUNXI_CCU_NK + select SUNXI_CCU_NKM + select SUNXI_CCU_NM + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN6I + config SUN8I_H3_CCU bool "Support for the Allwinner H3 CCU" select SUNXI_CCU_DIV diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 633ce64..261438b 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -17,4 +17,5 @@ obj-$(CONFIG_SUNXI_CCU_NM) += ccu_nm.o obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o # SoC support +obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c new file mode 100644 index 0000000..f1d61fa --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -0,0 +1,1235 @@ +/* + * Copyright (c) 2016 Chen-Yu Tsai + * + * Chen-Yu Tsai + * + * Based on ccu-sun8i-h3.c by Maxime Ripard. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_mux.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_phase.h" + +#include "ccu-sun6i-a31.h" + +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_cpu_clk, "pll-cpu", + "osc24M", 0x000, + 8, 5, /* N */ + 4, 2, /* K */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +/* + * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from + * the base (2x, 4x and 8x), and one variable divider (the one true + * pll audio). + * + * We don't have any need for the variable divider for now, so we just + * hardcode it to match with the clock names + */ +#define SUN6I_A31_PLL_AUDIO_REG 0x008 + +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", + "osc24M", 0x010, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", + "osc24M", 0x018, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", + "osc24M", 0x020, + 8, 5, /* N */ + 4, 2, /* K */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph_clk, "pll-periph", + "osc24M", 0x028, + 8, 5, /* N */ + 4, 2, /* K */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 2, /* post-div */ + 0); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", + "osc24M", 0x030, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", + "osc24M", 0x038, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +/* + * The MIPI PLL has 2 modes: "MIPI" and "HDMI". + * + * The MIPI mode is a standard NKM-style clock. The HDMI mode is an + * integer / fractional clock with switchable multipliers and dividers. + * This is not supported here. We hardcode the PLL to MIPI mode. + */ +#define SUN6I_A31_PLL_MIPI_REG 0x040 + +static const char * const pll_mipi_parents[] = { "pll-video0", "pll-video1" }; +static SUNXI_CCU_NKM_WITH_MUX_GATE_LOCK(pll_mipi_clk, "pll-mipi", + pll_mipi_parents, 0x040, + 8, 4, /* N */ + 4, 2, /* K */ + 0, 4, /* M */ + 21, 0, /* mux */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll9_clk, "pll9", + "osc24M", 0x044, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll10_clk, "pll10", + "osc24M", 0x048, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static const char * const cpux_parents[] = { "osc32k", "osc24M", + "pll-cpu", "pll-cpu" }; +static SUNXI_CCU_MUX(cpu_clk, "cpu", cpux_parents, + 0x050, 16, 2, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + +static struct clk_div_table axi_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 4, .div = 4 }, + { .val = 5, .div = 4 }, + { .val = 6, .div = 4 }, + { .val = 7, .div = 4 }, + { /* Sentinel */ }, +}; + +static SUNXI_CCU_DIV_TABLE(axi_clk, "axi", "cpu", + 0x050, 0, 3, axi_div_table, 0); + +static const char * const ahb1_parents[] = { "osc32k", "osc24M", + "axi", "pll-periph" }; + +static struct ccu_div ahb1_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 12, + .width = 2, + + .variable_prediv = { + .index = 3, + .shift = 6, + .width = 2, + }, + }, + + .common = { + .reg = 0x054, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ahb1", + ahb1_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct clk_div_table apb1_div_table[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { /* Sentinel */ }, +}; + +static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1", + 0x054, 8, 2, apb1_div_table, 0); + +static const char * const apb2_parents[] = { "osc32k", "osc24M", + "pll-periph", "pll-periph" }; +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_GATE(ahb1_mipidsi_clk, "ahb1-mipidsi", "ahb1", + 0x060, BIT(1), 0); +static SUNXI_CCU_GATE(ahb1_ss_clk, "ahb1-ss", "ahb1", + 0x060, BIT(5), 0); +static SUNXI_CCU_GATE(ahb1_dma_clk, "ahb1-dma", "ahb1", + 0x060, BIT(6), 0); +static SUNXI_CCU_GATE(ahb1_mmc0_clk, "ahb1-mmc0", "ahb1", + 0x060, BIT(8), 0); +static SUNXI_CCU_GATE(ahb1_mmc1_clk, "ahb1-mmc1", "ahb1", + 0x060, BIT(9), 0); +static SUNXI_CCU_GATE(ahb1_mmc2_clk, "ahb1-mmc2", "ahb1", + 0x060, BIT(10), 0); +static SUNXI_CCU_GATE(ahb1_mmc3_clk, "ahb1-mmc3", "ahb1", + 0x060, BIT(12), 0); +static SUNXI_CCU_GATE(ahb1_nand1_clk, "ahb1-nand1", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(ahb1_nand0_clk, "ahb1-nand0", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(ahb1_sdram_clk, "ahb1-sdram", "ahb1", + 0x060, BIT(14), 0); +static SUNXI_CCU_GATE(ahb1_emac_clk, "ahb1-emac", "ahb1", + 0x060, BIT(17), 0); +static SUNXI_CCU_GATE(ahb1_ts_clk, "ahb1-ts", "ahb1", + 0x060, BIT(18), 0); +static SUNXI_CCU_GATE(ahb1_hstimer_clk, "ahb1-hstimer", "ahb1", + 0x060, BIT(19), 0); +static SUNXI_CCU_GATE(ahb1_spi0_clk, "ahb1-spi0", "ahb1", + 0x060, BIT(20), 0); +static SUNXI_CCU_GATE(ahb1_spi1_clk, "ahb1-spi1", "ahb1", + 0x060, BIT(21), 0); +static SUNXI_CCU_GATE(ahb1_spi2_clk, "ahb1-spi2", "ahb1", + 0x060, BIT(22), 0); +static SUNXI_CCU_GATE(ahb1_spi3_clk, "ahb1-spi3", "ahb1", + 0x060, BIT(23), 0); +static SUNXI_CCU_GATE(ahb1_otg_clk, "ahb1-otg", "ahb1", + 0x060, BIT(24), 0); +static SUNXI_CCU_GATE(ahb1_ehci0_clk, "ahb1-ehci0", "ahb1", + 0x060, BIT(26), 0); +static SUNXI_CCU_GATE(ahb1_ehci1_clk, "ahb1-ehci1", "ahb1", + 0x060, BIT(27), 0); +static SUNXI_CCU_GATE(ahb1_ohci0_clk, "ahb1-ohci0", "ahb1", + 0x060, BIT(29), 0); +static SUNXI_CCU_GATE(ahb1_ohci1_clk, "ahb1-ohci1", "ahb1", + 0x060, BIT(30), 0); +static SUNXI_CCU_GATE(ahb1_ohci2_clk, "ahb1-ohci2", "ahb1", + 0x060, BIT(31), 0); + +static SUNXI_CCU_GATE(ahb1_ve_clk, "ahb1-ve", "ahb1", + 0x064, BIT(0), 0); +static SUNXI_CCU_GATE(ahb1_lcd0_clk, "ahb1-lcd0", "ahb1", + 0x064, BIT(4), 0); +static SUNXI_CCU_GATE(ahb1_lcd1_clk, "ahb1-lcd1", "ahb1", + 0x064, BIT(5), 0); +static SUNXI_CCU_GATE(ahb1_csi_clk, "ahb1-csi", "ahb1", + 0x064, BIT(8), 0); +static SUNXI_CCU_GATE(ahb1_hdmi_clk, "ahb1-hdmi", "ahb1", + 0x064, BIT(11), 0); +static SUNXI_CCU_GATE(ahb1_be0_clk, "ahb1-be0", "ahb1", + 0x064, BIT(12), 0); +static SUNXI_CCU_GATE(ahb1_be1_clk, "ahb1-be1", "ahb1", + 0x064, BIT(13), 0); +static SUNXI_CCU_GATE(ahb1_fe0_clk, "ahb1-fe0", "ahb1", + 0x064, BIT(14), 0); +static SUNXI_CCU_GATE(ahb1_fe1_clk, "ahb1-fe1", "ahb1", + 0x064, BIT(15), 0); +static SUNXI_CCU_GATE(ahb1_mp_clk, "ahb1-mp", "ahb1", + 0x064, BIT(18), 0); +static SUNXI_CCU_GATE(ahb1_gpu_clk, "ahb1-gpu", "ahb1", + 0x064, BIT(20), 0); +static SUNXI_CCU_GATE(ahb1_deu0_clk, "ahb1-deu0", "ahb1", + 0x064, BIT(23), 0); +static SUNXI_CCU_GATE(ahb1_deu1_clk, "ahb1-deu1", "ahb1", + 0x064, BIT(24), 0); +static SUNXI_CCU_GATE(ahb1_drc0_clk, "ahb1-drc0", "ahb1", + 0x064, BIT(25), 0); +static SUNXI_CCU_GATE(ahb1_drc1_clk, "ahb1-drc1", "ahb1", + 0x064, BIT(26), 0); + +static SUNXI_CCU_GATE(apb1_codec_clk, "apb1-codec", "apb1", + 0x068, BIT(0), 0); +static SUNXI_CCU_GATE(apb1_spdif_clk, "apb1-spdif", "apb1", + 0x068, BIT(1), 0); +static SUNXI_CCU_GATE(apb1_digital_mic_clk, "apb1-digital-mic", "apb1", + 0x068, BIT(4), 0); +static SUNXI_CCU_GATE(apb1_pio_clk, "apb1-pio", "apb1", + 0x068, BIT(5), 0); +static SUNXI_CCU_GATE(apb1_daudio0_clk, "apb1-daudio0", "apb1", + 0x068, BIT(12), 0); +static SUNXI_CCU_GATE(apb1_daudio1_clk, "apb1-daudio1", "apb1", + 0x068, BIT(13), 0); + +static SUNXI_CCU_GATE(apb2_i2c0_clk, "apb2-i2c0", "apb2", + 0x06c, BIT(0), 0); +static SUNXI_CCU_GATE(apb2_i2c1_clk, "apb2-i2c1", "apb2", + 0x06c, BIT(1), 0); +static SUNXI_CCU_GATE(apb2_i2c2_clk, "apb2-i2c2", "apb2", + 0x06c, BIT(2), 0); +static SUNXI_CCU_GATE(apb2_i2c3_clk, "apb2-i2c3", "apb2", + 0x06c, BIT(3), 0); +static SUNXI_CCU_GATE(apb2_uart0_clk, "apb2-uart0", "apb2", + 0x06c, BIT(16), 0); +static SUNXI_CCU_GATE(apb2_uart1_clk, "apb2-uart1", "apb2", + 0x06c, BIT(17), 0); +static SUNXI_CCU_GATE(apb2_uart2_clk, "apb2-uart2", "apb2", + 0x06c, BIT(18), 0); +static SUNXI_CCU_GATE(apb2_uart3_clk, "apb2-uart3", "apb2", + 0x06c, BIT(19), 0); +static SUNXI_CCU_GATE(apb2_uart4_clk, "apb2-uart4", "apb2", + 0x06c, BIT(20), 0); +static SUNXI_CCU_GATE(apb2_uart5_clk, "apb2-uart5", "apb2", + 0x06c, BIT(21), 0); + +static const char * const mod0_default_parents[] = { "osc24M", "pll-periph" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", mod0_default_parents, + 0x080, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", mod0_default_parents, + 0x084, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_default_parents, + 0x088, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_default_parents, + 0x08c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1_sample", "mmc1", + 0x08c, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1_output", "mmc1", + 0x08c, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mod0_default_parents, + 0x090, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2_sample", "mmc2", + 0x090, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc2_output_clk, "mmc2_output", "mmc2", + 0x090, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc3_clk, "mmc3", mod0_default_parents, + 0x094, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc3_sample_clk, "mmc3_sample", "mmc3", + 0x094, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc3_output_clk, "mmc3_output", "mmc3", + 0x094, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", mod0_default_parents, 0x098, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(ss_clk, "ss", mod0_default_parents, 0x09c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents, 0x0a0, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); +static SUNXI_CCU_MP_WITH_MUX_GATE(spi2_clk, "spi2", mod0_default_parents, 0x0a8, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi3_clk, "spi3", mod0_default_parents, 0x0ac, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const daudio_parents[] = { "pll-audio-8x", "pll-audio-4x", + "pll-audio-2x", "pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(daudio0_clk, "daudio0", daudio_parents, + 0x0b0, 16, 2, BIT(31), CLK_SET_RATE_PARENT); +static SUNXI_CCU_MUX_WITH_GATE(daudio1_clk, "daudio1", daudio_parents, + 0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio", + 0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", + 0x0cc, BIT(8), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", + 0x0cc, BIT(9), 0); +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", + 0x0cc, BIT(10), 0); +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", + 0x0cc, BIT(16), 0); +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc24M", + 0x0cc, BIT(17), 0); +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M", + 0x0cc, BIT(18), 0); + +/* TODO emac clk not supported yet */ + +static const char * const dram_parents[] = { "pll-ddr", "pll-periph" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mdfs_clk, "mdfs", dram_parents, 0x0f0, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_IS_CRITICAL); + +static SUNXI_CCU_M_WITH_MUX(sdram0_clk, "sdram0", dram_parents, + 0x0f4, 0, 4, 4, 1, CLK_IS_CRITICAL); +static SUNXI_CCU_M_WITH_MUX(sdram1_clk, "sdram1", dram_parents, + 0x0f4, 8, 4, 12, 1, CLK_IS_CRITICAL); + +static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "mdfs", + 0x100, BIT(0), 0); +static SUNXI_CCU_GATE(dram_csi_isp_clk, "dram-csi-isp", "mdfs", + 0x100, BIT(1), 0); +static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "mdfs", + 0x100, BIT(3), 0); +static SUNXI_CCU_GATE(dram_drc0_clk, "dram-drc0", "mdfs", + 0x100, BIT(16), 0); +static SUNXI_CCU_GATE(dram_drc1_clk, "dram-drc1", "mdfs", + 0x100, BIT(17), 0); +static SUNXI_CCU_GATE(dram_deu0_clk, "dram-deu0", "mdfs", + 0x100, BIT(18), 0); +static SUNXI_CCU_GATE(dram_deu1_clk, "dram-deu1", "mdfs", + 0x100, BIT(19), 0); +static SUNXI_CCU_GATE(dram_fe0_clk, "dram-fe0", "mdfs", + 0x100, BIT(24), 0); +static SUNXI_CCU_GATE(dram_fe1_clk, "dram-fe1", "mdfs", + 0x100, BIT(25), 0); +static SUNXI_CCU_GATE(dram_be0_clk, "dram-be0", "mdfs", + 0x100, BIT(26), 0); +static SUNXI_CCU_GATE(dram_be1_clk, "dram-be1", "mdfs", + 0x100, BIT(27), 0); +static SUNXI_CCU_GATE(dram_mp_clk, "dram-mp", "mdfs", + 0x100, BIT(28), 0); + +static const char * const de_parents[] = { "pll-video0", "pll-video1", + "pll-periph-2x", "pll-gpu", + "pll9", "pll10" }; +static SUNXI_CCU_M_WITH_MUX_GATE(be0_clk, "be0", de_parents, + 0x104, 0, 4, 24, 3, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(be1_clk, "be1", de_parents, + 0x108, 0, 4, 24, 3, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(fe0_clk, "fe0", de_parents, + 0x10c, 0, 4, 24, 3, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(fe1_clk, "fe1", de_parents, + 0x110, 0, 4, 24, 3, BIT(31), 0); + +static const char * const mp_parents[] = { "pll-video0", "pll-video1", + "pll9", "pll10" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mp_clk, "mp", mp_parents, + 0x114, 0, 4, 24, 3, BIT(31), 0); + +static const char * const lcd_ch0_parents[] = { "pll-video0", "pll-video1", + "pll-video0-2x", + "pll-video1-2x", "pll-mipi" }; +static SUNXI_CCU_MUX_WITH_GATE(lcd0_ch0_clk, "lcd0-ch0", lcd_ch0_parents, + 0x118, 24, 2, BIT(31), 0); +static SUNXI_CCU_MUX_WITH_GATE(lcd1_ch0_clk, "lcd1-ch0", lcd_ch0_parents, + 0x11c, 24, 2, BIT(31), 0); + +static const char * const lcd_ch1_parents[] = { "pll-video0", "pll-video1", + "pll-video0-2x", + "pll-video1-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(lcd0_ch1_clk, "lcd0-ch1", lcd_ch1_parents, + 0x12c, 0, 4, 24, 3, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(lcd1_ch1_clk, "lcd1-ch1", lcd_ch1_parents, + 0x12c, 0, 4, 24, 3, BIT(31), 0); + +static const char * const csi_sclk_parents[] = { "pll-video0", "pll-video1", + "pll9", "pll10", "pll-mipi", + "pll-ve" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi0_sclk_clk, "csi0-sclk", csi_sclk_parents, + 0x134, 16, 4, 24, 3, BIT(31), 0); + +static const char * const csi_mclk_parents[] = { "pll-video0", "pll-video1", + "osc24M" }; +static const u8 csi_mclk_table[] = { 0, 1, 5 }; +static struct ccu_div csi0_mclk_clk = { + .enable = BIT(15), + .div = _SUNXI_CCU_DIV(0, 4), + .mux = _SUNXI_CCU_MUX_TABLE(8, 3, csi_mclk_table), + .common = { + .reg = 0x134, + .hw.init = CLK_HW_INIT_PARENTS("csi0-mclk", + csi_mclk_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_div csi1_mclk_clk = { + .enable = BIT(15), + .div = _SUNXI_CCU_DIV(0, 4), + .mux = _SUNXI_CCU_MUX_TABLE(8, 3, csi_mclk_table), + .common = { + .reg = 0x138, + .hw.init = CLK_HW_INIT_PARENTS("csi1-mclk", + csi_mclk_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", + 0x13c, 16, 3, BIT(31), 0); + +static SUNXI_CCU_GATE(codec_clk, "codec", "pll-audio", + 0x140, BIT(31), CLK_SET_RATE_PARENT); +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", + 0x144, BIT(31), 0); +static SUNXI_CCU_GATE(digital_mic_clk, "digital-mic", "pll-audio", + 0x148, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", lcd_ch1_parents, + 0x150, 0, 4, 24, 2, BIT(31), 0); + +static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(31), 0); + +static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0); + +static const char * const mbus_parents[] = { "osc24M", "pll-periph", + "pll-ddr" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mbus0_clk, "mbus0", mbus_parents, 0x15c, + 0, 3, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_IS_CRITICAL); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mbus1_clk, "mbus1", mbus_parents, 0x160, + 0, 3, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_IS_CRITICAL); + +static SUNXI_CCU_M_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi", lcd_ch1_parents, + 0x168, 16, 3, 24, 2, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(mipi_dsi_dphy_clk, "mipi-dsi-dphy", + lcd_ch1_parents, 0x168, 0, 3, 8, 2, + BIT(15), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(mipi_csi_dphy_clk, "mipi-csi-dphy", + lcd_ch1_parents, 0x168, 0, 3, 8, 2, + BIT(15), 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(iep_drc0_clk, "iep-drc0", de_parents, + 0x180, 0, 3, 24, 2, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(iep_drc1_clk, "iep-drc1", de_parents, + 0x184, 0, 3, 24, 2, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(iep_deu0_clk, "iep-deu0", de_parents, + 0x188, 0, 3, 24, 2, BIT(31), 0); +static SUNXI_CCU_M_WITH_MUX_GATE(iep_deu1_clk, "iep-deu1", de_parents, + 0x18c, 0, 3, 24, 2, BIT(31), 0); + +static const char * const gpu_parents[] = { "pll-gpu", "pll-periph-2x", + "pll-video0", "pll-video1", + "pll9", "pll10" }; +static const struct ccu_mux_fixed_prediv gpu_predivs[] = { + { .index = 1, .div = 3, }, +}; + +static struct ccu_div gpu_core_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV(0, 3), + .mux = { + .shift = 24, + .width = 3, + .fixed_predivs = gpu_predivs, + .n_predivs = ARRAY_SIZE(gpu_predivs), + }, + .common = { + .reg = 0x1a0, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("gpu-core", + gpu_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_div gpu_memory_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV(0, 3), + .mux = { + .shift = 24, + .width = 3, + .fixed_predivs = gpu_predivs, + .n_predivs = ARRAY_SIZE(gpu_predivs), + }, + .common = { + .reg = 0x1a4, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("gpu-memory", + gpu_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_div gpu_hyd_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV(0, 3), + .mux = { + .shift = 24, + .width = 3, + .fixed_predivs = gpu_predivs, + .n_predivs = ARRAY_SIZE(gpu_predivs), + }, + .common = { + .reg = 0x1a8, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("gpu-hyd", + gpu_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_M_WITH_MUX_GATE(ats_clk, "ats", mod0_default_parents, 0x1b0, + 0, 3, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(trace_clk, "trace", mod0_default_parents, + 0x1b0, + 0, 3, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const clk_out_parents[] = { "osc24M", "osc32k", "osc24M", + "axi", "ahb1" }; +static const u8 clk_out_table[] = { 0, 1, 2, 11, 13 }; + +static const struct ccu_mux_fixed_prediv clk_out_predivs[] = { + { .index = 0, .div = 750, }, + { .index = 3, .div = 4, }, + { .index = 4, .div = 4, }, +}; + +static struct ccu_mp out_a_clk = { + .enable = BIT(31), + .m = _SUNXI_CCU_DIV(8, 5), + .p = _SUNXI_CCU_DIV(20, 2), + .mux = { + .shift = 24, + .width = 4, + .table = clk_out_table, + .fixed_predivs = clk_out_predivs, + .n_predivs = ARRAY_SIZE(clk_out_predivs), + }, + .common = { + .reg = 0x300, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("out-a", + clk_out_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_mp out_b_clk = { + .enable = BIT(31), + .m = _SUNXI_CCU_DIV(8, 5), + .p = _SUNXI_CCU_DIV(20, 2), + .mux = { + .shift = 24, + .width = 4, + .table = clk_out_table, + .fixed_predivs = clk_out_predivs, + .n_predivs = ARRAY_SIZE(clk_out_predivs), + }, + .common = { + .reg = 0x304, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("out-b", + clk_out_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_mp out_c_clk = { + .enable = BIT(31), + .m = _SUNXI_CCU_DIV(8, 5), + .p = _SUNXI_CCU_DIV(20, 2), + .mux = { + .shift = 24, + .width = 4, + .table = clk_out_table, + .fixed_predivs = clk_out_predivs, + .n_predivs = ARRAY_SIZE(clk_out_predivs), + }, + .common = { + .reg = 0x308, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("out-c", + clk_out_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_common *sun6i_a31_ccu_clks[] = { + &pll_cpu_clk.common, + &pll_audio_base_clk.common, + &pll_video0_clk.common, + &pll_ve_clk.common, + &pll_ddr_clk.common, + &pll_periph_clk.common, + &pll_video1_clk.common, + &pll_gpu_clk.common, + &pll_mipi_clk.common, + &pll9_clk.common, + &pll10_clk.common, + &cpu_clk.common, + &axi_clk.common, + &ahb1_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &ahb1_mipidsi_clk.common, + &ahb1_ss_clk.common, + &ahb1_dma_clk.common, + &ahb1_mmc0_clk.common, + &ahb1_mmc1_clk.common, + &ahb1_mmc2_clk.common, + &ahb1_mmc3_clk.common, + &ahb1_nand1_clk.common, + &ahb1_nand0_clk.common, + &ahb1_sdram_clk.common, + &ahb1_emac_clk.common, + &ahb1_ts_clk.common, + &ahb1_hstimer_clk.common, + &ahb1_spi0_clk.common, + &ahb1_spi1_clk.common, + &ahb1_spi2_clk.common, + &ahb1_spi3_clk.common, + &ahb1_otg_clk.common, + &ahb1_ehci0_clk.common, + &ahb1_ehci1_clk.common, + &ahb1_ohci0_clk.common, + &ahb1_ohci1_clk.common, + &ahb1_ohci2_clk.common, + &ahb1_ve_clk.common, + &ahb1_lcd0_clk.common, + &ahb1_lcd1_clk.common, + &ahb1_csi_clk.common, + &ahb1_hdmi_clk.common, + &ahb1_be0_clk.common, + &ahb1_be1_clk.common, + &ahb1_fe0_clk.common, + &ahb1_fe1_clk.common, + &ahb1_mp_clk.common, + &ahb1_gpu_clk.common, + &ahb1_deu0_clk.common, + &ahb1_deu1_clk.common, + &ahb1_drc0_clk.common, + &ahb1_drc1_clk.common, + &apb1_codec_clk.common, + &apb1_spdif_clk.common, + &apb1_digital_mic_clk.common, + &apb1_pio_clk.common, + &apb1_daudio0_clk.common, + &apb1_daudio1_clk.common, + &apb2_i2c0_clk.common, + &apb2_i2c1_clk.common, + &apb2_i2c2_clk.common, + &apb2_i2c3_clk.common, + &apb2_uart0_clk.common, + &apb2_uart1_clk.common, + &apb2_uart2_clk.common, + &apb2_uart3_clk.common, + &apb2_uart4_clk.common, + &apb2_uart5_clk.common, + &nand0_clk.common, + &nand1_clk.common, + &mmc0_clk.common, + &mmc0_sample_clk.common, + &mmc0_output_clk.common, + &mmc1_clk.common, + &mmc1_sample_clk.common, + &mmc1_output_clk.common, + &mmc2_clk.common, + &mmc2_sample_clk.common, + &mmc2_output_clk.common, + &mmc3_clk.common, + &mmc3_sample_clk.common, + &mmc3_output_clk.common, + &ts_clk.common, + &ss_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &spi2_clk.common, + &spi3_clk.common, + &daudio0_clk.common, + &daudio1_clk.common, + &spdif_clk.common, + &usb_phy0_clk.common, + &usb_phy1_clk.common, + &usb_phy2_clk.common, + &usb_ohci0_clk.common, + &usb_ohci1_clk.common, + &usb_ohci2_clk.common, + &mdfs_clk.common, + &sdram0_clk.common, + &sdram1_clk.common, + &dram_ve_clk.common, + &dram_csi_isp_clk.common, + &dram_ts_clk.common, + &dram_drc0_clk.common, + &dram_drc1_clk.common, + &dram_deu0_clk.common, + &dram_deu1_clk.common, + &dram_fe0_clk.common, + &dram_fe1_clk.common, + &dram_be0_clk.common, + &dram_be1_clk.common, + &dram_mp_clk.common, + &be0_clk.common, + &be1_clk.common, + &fe0_clk.common, + &fe1_clk.common, + &mp_clk.common, + &lcd0_ch0_clk.common, + &lcd1_ch0_clk.common, + &lcd0_ch1_clk.common, + &lcd1_ch1_clk.common, + &csi0_sclk_clk.common, + &csi0_mclk_clk.common, + &csi1_mclk_clk.common, + &ve_clk.common, + &codec_clk.common, + &avs_clk.common, + &digital_mic_clk.common, + &hdmi_clk.common, + &hdmi_ddc_clk.common, + &ps_clk.common, + &mbus0_clk.common, + &mbus1_clk.common, + &mipi_dsi_clk.common, + &mipi_dsi_dphy_clk.common, + &mipi_csi_dphy_clk.common, + &iep_drc0_clk.common, + &iep_drc1_clk.common, + &iep_deu0_clk.common, + &iep_deu1_clk.common, + &gpu_core_clk.common, + &gpu_memory_clk.common, + &gpu_hyd_clk.common, + &ats_clk.common, + &trace_clk.common, + &out_a_clk.common, + &out_b_clk.common, + &out_c_clk.common, +}; + +/* We hardcode the divider to 4 for now */ +static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", + "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x", + "pll-periph", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x", + "pll-video0", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x", + "pll-video1", 1, 2, 0); + +static struct clk_hw_onecell_data sun6i_a31_hw_clks = { + .hws = { + [CLK_PLL_CPU] = &pll_cpu_clk.common.hw, + [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, + [CLK_PLL_VIDEO0_2X] = &pll_video0_2x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DDR] = &pll_ddr_clk.common.hw, + [CLK_PLL_PERIPH] = &pll_periph_clk.common.hw, + [CLK_PLL_PERIPH_2X] = &pll_periph_2x_clk.hw, + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, + [CLK_PLL_VIDEO1_2X] = &pll_video1_2x_clk.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_MIPI] = &pll_mipi_clk.common.hw, + [CLK_PLL9] = &pll9_clk.common.hw, + [CLK_PLL10] = &pll10_clk.common.hw, + [CLK_CPU] = &cpu_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_AHB1] = &ahb1_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_AHB1_MIPIDSI] = &ahb1_mipidsi_clk.common.hw, + [CLK_AHB1_SS] = &ahb1_ss_clk.common.hw, + [CLK_AHB1_DMA] = &ahb1_dma_clk.common.hw, + [CLK_AHB1_MMC0] = &ahb1_mmc0_clk.common.hw, + [CLK_AHB1_MMC1] = &ahb1_mmc1_clk.common.hw, + [CLK_AHB1_MMC2] = &ahb1_mmc2_clk.common.hw, + [CLK_AHB1_MMC3] = &ahb1_mmc3_clk.common.hw, + [CLK_AHB1_NAND1] = &ahb1_nand1_clk.common.hw, + [CLK_AHB1_NAND0] = &ahb1_nand0_clk.common.hw, + [CLK_AHB1_SDRAM] = &ahb1_sdram_clk.common.hw, + [CLK_AHB1_EMAC] = &ahb1_emac_clk.common.hw, + [CLK_AHB1_TS] = &ahb1_ts_clk.common.hw, + [CLK_AHB1_HSTIMER] = &ahb1_hstimer_clk.common.hw, + [CLK_AHB1_SPI0] = &ahb1_spi0_clk.common.hw, + [CLK_AHB1_SPI1] = &ahb1_spi1_clk.common.hw, + [CLK_AHB1_SPI2] = &ahb1_spi2_clk.common.hw, + [CLK_AHB1_SPI3] = &ahb1_spi3_clk.common.hw, + [CLK_AHB1_OTG] = &ahb1_otg_clk.common.hw, + [CLK_AHB1_EHCI0] = &ahb1_ehci0_clk.common.hw, + [CLK_AHB1_EHCI1] = &ahb1_ehci1_clk.common.hw, + [CLK_AHB1_OHCI0] = &ahb1_ohci0_clk.common.hw, + [CLK_AHB1_OHCI1] = &ahb1_ohci1_clk.common.hw, + [CLK_AHB1_OHCI2] = &ahb1_ohci2_clk.common.hw, + [CLK_AHB1_VE] = &ahb1_ve_clk.common.hw, + [CLK_AHB1_LCD0] = &ahb1_lcd0_clk.common.hw, + [CLK_AHB1_LCD1] = &ahb1_lcd1_clk.common.hw, + [CLK_AHB1_CSI] = &ahb1_csi_clk.common.hw, + [CLK_AHB1_HDMI] = &ahb1_hdmi_clk.common.hw, + [CLK_AHB1_BE0] = &ahb1_be0_clk.common.hw, + [CLK_AHB1_BE1] = &ahb1_be1_clk.common.hw, + [CLK_AHB1_FE0] = &ahb1_fe0_clk.common.hw, + [CLK_AHB1_FE1] = &ahb1_fe1_clk.common.hw, + [CLK_AHB1_MP] = &ahb1_mp_clk.common.hw, + [CLK_AHB1_GPU] = &ahb1_gpu_clk.common.hw, + [CLK_AHB1_DEU0] = &ahb1_deu0_clk.common.hw, + [CLK_AHB1_DEU1] = &ahb1_deu1_clk.common.hw, + [CLK_AHB1_DRC0] = &ahb1_drc0_clk.common.hw, + [CLK_AHB1_DRC1] = &ahb1_drc1_clk.common.hw, + [CLK_APB1_CODEC] = &apb1_codec_clk.common.hw, + [CLK_APB1_SPDIF] = &apb1_spdif_clk.common.hw, + [CLK_APB1_DIGITAL_MIC] = &apb1_digital_mic_clk.common.hw, + [CLK_APB1_PIO] = &apb1_pio_clk.common.hw, + [CLK_APB1_DAUDIO0] = &apb1_daudio0_clk.common.hw, + [CLK_APB1_DAUDIO1] = &apb1_daudio1_clk.common.hw, + [CLK_APB2_I2C0] = &apb2_i2c0_clk.common.hw, + [CLK_APB2_I2C1] = &apb2_i2c1_clk.common.hw, + [CLK_APB2_I2C2] = &apb2_i2c2_clk.common.hw, + [CLK_APB2_I2C3] = &apb2_i2c3_clk.common.hw, + [CLK_APB2_UART0] = &apb2_uart0_clk.common.hw, + [CLK_APB2_UART1] = &apb2_uart1_clk.common.hw, + [CLK_APB2_UART2] = &apb2_uart2_clk.common.hw, + [CLK_APB2_UART3] = &apb2_uart3_clk.common.hw, + [CLK_APB2_UART4] = &apb2_uart4_clk.common.hw, + [CLK_APB2_UART5] = &apb2_uart5_clk.common.hw, + [CLK_NAND0] = &nand0_clk.common.hw, + [CLK_NAND1] = &nand1_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC0_SAMPLE] = &mmc0_sample_clk.common.hw, + [CLK_MMC0_OUTPUT] = &mmc0_output_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC1_SAMPLE] = &mmc1_sample_clk.common.hw, + [CLK_MMC1_OUTPUT] = &mmc1_output_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_MMC2_SAMPLE] = &mmc2_sample_clk.common.hw, + [CLK_MMC2_OUTPUT] = &mmc2_output_clk.common.hw, + [CLK_MMC3] = &mmc3_clk.common.hw, + [CLK_MMC3_SAMPLE] = &mmc3_sample_clk.common.hw, + [CLK_MMC3_OUTPUT] = &mmc3_output_clk.common.hw, + [CLK_TS] = &ts_clk.common.hw, + [CLK_SS] = &ss_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_SPI2] = &spi2_clk.common.hw, + [CLK_SPI3] = &spi3_clk.common.hw, + [CLK_DAUDIO0] = &daudio0_clk.common.hw, + [CLK_DAUDIO1] = &daudio1_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_PHY2] = &usb_phy2_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, + [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw, + [CLK_MDFS] = &mdfs_clk.common.hw, + [CLK_SDRAM0] = &sdram0_clk.common.hw, + [CLK_SDRAM1] = &sdram1_clk.common.hw, + [CLK_DRAM_VE] = &dram_ve_clk.common.hw, + [CLK_DRAM_CSI_ISP] = &dram_csi_isp_clk.common.hw, + [CLK_DRAM_TS] = &dram_ts_clk.common.hw, + [CLK_DRAM_DRC0] = &dram_drc0_clk.common.hw, + [CLK_DRAM_DRC1] = &dram_drc1_clk.common.hw, + [CLK_DRAM_DEU0] = &dram_deu0_clk.common.hw, + [CLK_DRAM_DEU1] = &dram_deu1_clk.common.hw, + [CLK_DRAM_FE0] = &dram_fe0_clk.common.hw, + [CLK_DRAM_FE1] = &dram_fe1_clk.common.hw, + [CLK_DRAM_BE0] = &dram_be0_clk.common.hw, + [CLK_DRAM_BE1] = &dram_be1_clk.common.hw, + [CLK_DRAM_MP] = &dram_mp_clk.common.hw, + [CLK_BE0] = &be0_clk.common.hw, + [CLK_BE1] = &be1_clk.common.hw, + [CLK_FE0] = &fe0_clk.common.hw, + [CLK_FE1] = &fe1_clk.common.hw, + [CLK_MP] = &mp_clk.common.hw, + [CLK_LCD0_CH0] = &lcd0_ch0_clk.common.hw, + [CLK_LCD1_CH0] = &lcd1_ch0_clk.common.hw, + [CLK_LCD0_CH1] = &lcd0_ch1_clk.common.hw, + [CLK_LCD1_CH1] = &lcd1_ch1_clk.common.hw, + [CLK_CSI0_SCLK] = &csi0_sclk_clk.common.hw, + [CLK_CSI0_MCLK] = &csi0_mclk_clk.common.hw, + [CLK_CSI1_MCLK] = &csi1_mclk_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_CODEC] = &codec_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_DIGITAL_MIC] = &digital_mic_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_HDMI_DDC] = &hdmi_ddc_clk.common.hw, + [CLK_PS] = &ps_clk.common.hw, + [CLK_MBUS0] = &mbus0_clk.common.hw, + [CLK_MBUS1] = &mbus1_clk.common.hw, + [CLK_MIPI_DSI] = &mipi_dsi_clk.common.hw, + [CLK_MIPI_DSI_DPHY] = &mipi_dsi_dphy_clk.common.hw, + [CLK_MIPI_CSI_DPHY] = &mipi_csi_dphy_clk.common.hw, + [CLK_IEP_DRC0] = &iep_drc0_clk.common.hw, + [CLK_IEP_DRC1] = &iep_drc1_clk.common.hw, + [CLK_IEP_DEU0] = &iep_deu0_clk.common.hw, + [CLK_IEP_DEU1] = &iep_deu1_clk.common.hw, + [CLK_GPU_CORE] = &gpu_core_clk.common.hw, + [CLK_GPU_MEMORY] = &gpu_memory_clk.common.hw, + [CLK_GPU_HYD] = &gpu_hyd_clk.common.hw, + [CLK_ATS] = &ats_clk.common.hw, + [CLK_TRACE] = &trace_clk.common.hw, + [CLK_OUT_A] = &out_a_clk.common.hw, + [CLK_OUT_B] = &out_b_clk.common.hw, + [CLK_OUT_C] = &out_c_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun6i_a31_ccu_resets[] = { + [RST_USB_PHY0] = { 0x0cc, BIT(0) }, + [RST_USB_PHY1] = { 0x0cc, BIT(1) }, + [RST_USB_PHY2] = { 0x0cc, BIT(2) }, + + [RST_AHB1_MIPI_DSI] = { 0x2c0, BIT(1) }, + [RST_AHB1_SS] = { 0x2c0, BIT(5) }, + [RST_AHB1_DMA] = { 0x2c0, BIT(6) }, + [RST_AHB1_MMC0] = { 0x2c0, BIT(8) }, + [RST_AHB1_MMC1] = { 0x2c0, BIT(9) }, + [RST_AHB1_MMC2] = { 0x2c0, BIT(10) }, + [RST_AHB1_MMC3] = { 0x2c0, BIT(11) }, + [RST_AHB1_NAND1] = { 0x2c0, BIT(12) }, + [RST_AHB1_NAND0] = { 0x2c0, BIT(13) }, + [RST_AHB1_SDRAM] = { 0x2c0, BIT(14) }, + [RST_AHB1_EMAC] = { 0x2c0, BIT(17) }, + [RST_AHB1_TS] = { 0x2c0, BIT(18) }, + [RST_AHB1_HSTIMER] = { 0x2c0, BIT(19) }, + [RST_AHB1_SPI0] = { 0x2c0, BIT(20) }, + [RST_AHB1_SPI1] = { 0x2c0, BIT(21) }, + [RST_AHB1_SPI2] = { 0x2c0, BIT(22) }, + [RST_AHB1_SPI3] = { 0x2c0, BIT(23) }, + [RST_AHB1_OTG] = { 0x2c0, BIT(24) }, + [RST_AHB1_EHCI0] = { 0x2c0, BIT(26) }, + [RST_AHB1_EHCI1] = { 0x2c0, BIT(27) }, + [RST_AHB1_OHCI0] = { 0x2c0, BIT(29) }, + [RST_AHB1_OHCI1] = { 0x2c0, BIT(30) }, + [RST_AHB1_OHCI2] = { 0x2c0, BIT(31) }, + + [RST_AHB1_VE] = { 0x2c4, BIT(0) }, + [RST_AHB1_LCD0] = { 0x2c4, BIT(4) }, + [RST_AHB1_LCD1] = { 0x2c4, BIT(5) }, + [RST_AHB1_CSI] = { 0x2c4, BIT(8) }, + [RST_AHB1_HDMI] = { 0x2c4, BIT(11) }, + [RST_AHB1_BE0] = { 0x2c4, BIT(12) }, + [RST_AHB1_BE1] = { 0x2c4, BIT(13) }, + [RST_AHB1_FE0] = { 0x2c4, BIT(14) }, + [RST_AHB1_FE1] = { 0x2c4, BIT(15) }, + [RST_AHB1_MP] = { 0x2c4, BIT(18) }, + [RST_AHB1_GPU] = { 0x2c4, BIT(20) }, + [RST_AHB1_DEU0] = { 0x2c4, BIT(23) }, + [RST_AHB1_DEU1] = { 0x2c4, BIT(24) }, + [RST_AHB1_DRC0] = { 0x2c4, BIT(25) }, + [RST_AHB1_DRC1] = { 0x2c4, BIT(26) }, + [RST_AHB1_LVDS] = { 0x2c8, BIT(0) }, + + [RST_APB1_CODEC] = { 0x2d0, BIT(0) }, + [RST_APB1_SPDIF] = { 0x2d0, BIT(1) }, + [RST_APB1_DIGITAL_MIC] = { 0x2d0, BIT(4) }, + [RST_APB1_DAUDIO0] = { 0x2d0, BIT(12) }, + [RST_APB1_DAUDIO1] = { 0x2d0, BIT(13) }, + + [RST_APB2_I2C0] = { 0x2d8, BIT(0) }, + [RST_APB2_I2C1] = { 0x2d8, BIT(1) }, + [RST_APB2_I2C2] = { 0x2d8, BIT(2) }, + [RST_APB2_I2C3] = { 0x2d8, BIT(3) }, + [RST_APB2_UART0] = { 0x2d8, BIT(16) }, + [RST_APB2_UART1] = { 0x2d8, BIT(17) }, + [RST_APB2_UART2] = { 0x2d8, BIT(18) }, + [RST_APB2_UART3] = { 0x2d8, BIT(19) }, + [RST_APB2_UART4] = { 0x2d8, BIT(20) }, + [RST_APB2_UART5] = { 0x2d8, BIT(21) }, +}; + +static const struct sunxi_ccu_desc sun6i_a31_ccu_desc = { + .ccu_clks = sun6i_a31_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun6i_a31_ccu_clks), + + .hw_clks = &sun6i_a31_hw_clks, + + .resets = sun6i_a31_ccu_resets, + .num_resets = ARRAY_SIZE(sun6i_a31_ccu_resets), +}; + +static struct ccu_mux_nb sun6i_a31_cpu_nb = { + .common = &cpu_clk.common, + .cm = &cpu_clk.mux, + .delay_us = 1, /* > 8 clock cycles at 24 MHz */ + .bypass_index = 1, /* index of 24 MHz oscillator */ +}; + +static void __init sun6i_a31_ccu_setup(struct device_node *node) +{ + void __iomem *reg; + u32 val; + + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(reg)) { + pr_err("%s: Could not map the clock registers\n", + of_node_full_name(node)); + return; + } + + /* Force the PLL-Audio-1x divider to 4 */ + val = readl(reg + SUN6I_A31_PLL_AUDIO_REG); + val &= ~GENMASK(19, 16); + writel(val | (3 << 16), reg + SUN6I_A31_PLL_AUDIO_REG); + + /* Force PLL-MIPI to MIPI mode */ + val = readl(reg + SUN6I_A31_PLL_MIPI_REG); + val &= BIT(16); + writel(val, reg + SUN6I_A31_PLL_MIPI_REG); + + sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc); + + ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk, + &sun6i_a31_cpu_nb); +} +CLK_OF_DECLARE(sun6i_a31_ccu, "allwinner,sun6i-a31-ccu", + sun6i_a31_ccu_setup); diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.h b/drivers/clk/sunxi-ng/ccu-sun6i-a31.h new file mode 100644 index 0000000..4e43401 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.h @@ -0,0 +1,72 @@ +/* + * Copyright 2016 Chen-Yu Tsai + * + * Chen-Yu Tsai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CCU_SUN6I_A31_H_ +#define _CCU_SUN6I_A31_H_ + +#include +#include + +#define CLK_PLL_CPU 0 +#define CLK_PLL_AUDIO_BASE 1 +#define CLK_PLL_AUDIO 2 +#define CLK_PLL_AUDIO_2X 3 +#define CLK_PLL_AUDIO_4X 4 +#define CLK_PLL_AUDIO_8X 5 +#define CLK_PLL_VIDEO0 6 +#define CLK_PLL_VIDEO0_2X 7 +#define CLK_PLL_VE 8 +#define CLK_PLL_DDR 9 + +/* The PLL_PERIPH clock is exported */ + +#define CLK_PLL_PERIPH_2X 11 +#define CLK_PLL_VIDEO1 12 +#define CLK_PLL_VIDEO1_2X 13 +#define CLK_PLL_GPU 14 +#define CLK_PLL_MIPI 15 +#define CLK_PLL9 16 +#define CLK_PLL10 17 + +/* The CPUX clock is exported */ + +#define CLK_AXI 19 +#define CLK_AHB1 20 +#define CLK_APB1 21 +#define CLK_APB2 22 + +/* All the bus gates are exported */ + +/* The first bunch of module clocks are exported */ + +/* EMAC clock is not implemented */ + +#define CLK_MDFS 107 +#define CLK_SDRAM0 108 +#define CLK_SDRAM1 109 + +/* All the DRAM gates are exported */ + +/* Some more module clocks are exported */ + +#define CLK_MBUS0 141 +#define CLK_MBUS1 142 + +/* Some more module clocks and external clock outputs are exported */ + +#define CLK_NUMBER (CLK_OUT_C + 1) + +#endif /* _CCU_SUN6I_A31_H_ */ diff --git a/include/dt-bindings/clock/sun6i-a31-ccu.h b/include/dt-bindings/clock/sun6i-a31-ccu.h new file mode 100644 index 0000000..4482530 --- /dev/null +++ b/include/dt-bindings/clock/sun6i-a31-ccu.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2016 Chen-Yu Tsai + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DT_BINDINGS_CLK_SUN6I_A31_H_ +#define _DT_BINDINGS_CLK_SUN6I_A31_H_ + +#define CLK_PLL_PERIPH 10 + +#define CLK_CPU 18 + +#define CLK_AHB1_MIPIDSI 23 +#define CLK_AHB1_SS 24 +#define CLK_AHB1_DMA 25 +#define CLK_AHB1_MMC0 26 +#define CLK_AHB1_MMC1 27 +#define CLK_AHB1_MMC2 28 +#define CLK_AHB1_MMC3 29 +#define CLK_AHB1_NAND1 30 +#define CLK_AHB1_NAND0 31 +#define CLK_AHB1_SDRAM 32 +#define CLK_AHB1_EMAC 33 +#define CLK_AHB1_TS 34 +#define CLK_AHB1_HSTIMER 35 +#define CLK_AHB1_SPI0 36 +#define CLK_AHB1_SPI1 37 +#define CLK_AHB1_SPI2 38 +#define CLK_AHB1_SPI3 39 +#define CLK_AHB1_OTG 40 +#define CLK_AHB1_EHCI0 41 +#define CLK_AHB1_EHCI1 42 +#define CLK_AHB1_OHCI0 43 +#define CLK_AHB1_OHCI1 44 +#define CLK_AHB1_OHCI2 45 +#define CLK_AHB1_VE 46 +#define CLK_AHB1_LCD0 47 +#define CLK_AHB1_LCD1 48 +#define CLK_AHB1_CSI 49 +#define CLK_AHB1_HDMI 50 +#define CLK_AHB1_BE0 51 +#define CLK_AHB1_BE1 52 +#define CLK_AHB1_FE0 53 +#define CLK_AHB1_FE1 54 +#define CLK_AHB1_MP 55 +#define CLK_AHB1_GPU 56 +#define CLK_AHB1_DEU0 57 +#define CLK_AHB1_DEU1 58 +#define CLK_AHB1_DRC0 59 +#define CLK_AHB1_DRC1 60 + +#define CLK_APB1_CODEC 61 +#define CLK_APB1_SPDIF 62 +#define CLK_APB1_DIGITAL_MIC 63 +#define CLK_APB1_PIO 64 +#define CLK_APB1_DAUDIO0 65 +#define CLK_APB1_DAUDIO1 66 + +#define CLK_APB2_I2C0 67 +#define CLK_APB2_I2C1 68 +#define CLK_APB2_I2C2 69 +#define CLK_APB2_I2C3 70 +#define CLK_APB2_UART0 71 +#define CLK_APB2_UART1 72 +#define CLK_APB2_UART2 73 +#define CLK_APB2_UART3 74 +#define CLK_APB2_UART4 75 +#define CLK_APB2_UART5 76 + +#define CLK_NAND0 77 +#define CLK_NAND1 78 +#define CLK_MMC0 79 +#define CLK_MMC0_SAMPLE 80 +#define CLK_MMC0_OUTPUT 81 +#define CLK_MMC1 82 +#define CLK_MMC1_SAMPLE 83 +#define CLK_MMC1_OUTPUT 84 +#define CLK_MMC2 85 +#define CLK_MMC2_SAMPLE 86 +#define CLK_MMC2_OUTPUT 87 +#define CLK_MMC3 88 +#define CLK_MMC3_SAMPLE 89 +#define CLK_MMC3_OUTPUT 90 +#define CLK_TS 91 +#define CLK_SS 92 +#define CLK_SPI0 93 +#define CLK_SPI1 94 +#define CLK_SPI2 95 +#define CLK_SPI3 96 +#define CLK_DAUDIO0 97 +#define CLK_DAUDIO1 98 +#define CLK_SPDIF 99 +#define CLK_USB_PHY0 100 +#define CLK_USB_PHY1 101 +#define CLK_USB_PHY2 102 +#define CLK_USB_OHCI0 103 +#define CLK_USB_OHCI1 104 +#define CLK_USB_OHCI2 105 + +#define CLK_DRAM_VE 110 +#define CLK_DRAM_CSI_ISP 111 +#define CLK_DRAM_TS 112 +#define CLK_DRAM_DRC0 113 +#define CLK_DRAM_DRC1 114 +#define CLK_DRAM_DEU0 115 +#define CLK_DRAM_DEU1 116 +#define CLK_DRAM_FE0 117 +#define CLK_DRAM_FE1 118 +#define CLK_DRAM_BE0 119 +#define CLK_DRAM_BE1 120 +#define CLK_DRAM_MP 121 + +#define CLK_BE0 122 +#define CLK_BE1 123 +#define CLK_FE0 124 +#define CLK_FE1 125 +#define CLK_MP 126 +#define CLK_LCD0_CH0 127 +#define CLK_LCD1_CH0 128 +#define CLK_LCD0_CH1 129 +#define CLK_LCD1_CH1 130 +#define CLK_CSI0_SCLK 131 +#define CLK_CSI0_MCLK 132 +#define CLK_CSI1_MCLK 133 +#define CLK_VE 134 +#define CLK_CODEC 135 +#define CLK_AVS 136 +#define CLK_DIGITAL_MIC 137 +#define CLK_HDMI 138 +#define CLK_HDMI_DDC 139 +#define CLK_PS 140 + +#define CLK_MIPI_DSI 143 +#define CLK_MIPI_DSI_DPHY 144 +#define CLK_MIPI_CSI_DPHY 145 +#define CLK_IEP_DRC0 146 +#define CLK_IEP_DRC1 147 +#define CLK_IEP_DEU0 148 +#define CLK_IEP_DEU1 149 +#define CLK_GPU_CORE 150 +#define CLK_GPU_MEMORY 151 +#define CLK_GPU_HYD 152 +#define CLK_ATS 153 +#define CLK_TRACE 154 + +#define CLK_OUT_A 155 +#define CLK_OUT_B 156 +#define CLK_OUT_C 157 + +#endif /* _DT_BINDINGS_CLK_SUN6I_A31_H_ */ diff --git a/include/dt-bindings/reset/sun6i-a31-ccu.h b/include/dt-bindings/reset/sun6i-a31-ccu.h new file mode 100644 index 0000000..fbff365 --- /dev/null +++ b/include/dt-bindings/reset/sun6i-a31-ccu.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 Chen-Yu Tsai + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DT_BINDINGS_RST_SUN6I_A31_H_ +#define _DT_BINDINGS_RST_SUN6I_A31_H_ + +#define RST_USB_PHY0 0 +#define RST_USB_PHY1 1 +#define RST_USB_PHY2 2 + +#define RST_AHB1_MIPI_DSI 3 +#define RST_AHB1_SS 4 +#define RST_AHB1_DMA 5 +#define RST_AHB1_MMC0 6 +#define RST_AHB1_MMC1 7 +#define RST_AHB1_MMC2 8 +#define RST_AHB1_MMC3 9 +#define RST_AHB1_NAND1 10 +#define RST_AHB1_NAND0 11 +#define RST_AHB1_SDRAM 12 +#define RST_AHB1_EMAC 13 +#define RST_AHB1_TS 14 +#define RST_AHB1_HSTIMER 15 +#define RST_AHB1_SPI0 16 +#define RST_AHB1_SPI1 17 +#define RST_AHB1_SPI2 18 +#define RST_AHB1_SPI3 19 +#define RST_AHB1_OTG 20 +#define RST_AHB1_EHCI0 21 +#define RST_AHB1_EHCI1 22 +#define RST_AHB1_OHCI0 23 +#define RST_AHB1_OHCI1 24 +#define RST_AHB1_OHCI2 25 +#define RST_AHB1_VE 26 +#define RST_AHB1_LCD0 27 +#define RST_AHB1_LCD1 28 +#define RST_AHB1_CSI 29 +#define RST_AHB1_HDMI 30 +#define RST_AHB1_BE0 31 +#define RST_AHB1_BE1 32 +#define RST_AHB1_FE0 33 +#define RST_AHB1_FE1 34 +#define RST_AHB1_MP 35 +#define RST_AHB1_GPU 36 +#define RST_AHB1_DEU0 37 +#define RST_AHB1_DEU1 38 +#define RST_AHB1_DRC0 39 +#define RST_AHB1_DRC1 40 +#define RST_AHB1_LVDS 41 + +#define RST_APB1_CODEC 42 +#define RST_APB1_SPDIF 43 +#define RST_APB1_DIGITAL_MIC 44 +#define RST_APB1_DAUDIO0 45 +#define RST_APB1_DAUDIO1 46 +#define RST_APB2_I2C0 47 +#define RST_APB2_I2C1 48 +#define RST_APB2_I2C2 49 +#define RST_APB2_I2C3 50 +#define RST_APB2_UART0 51 +#define RST_APB2_UART1 52 +#define RST_APB2_UART2 53 +#define RST_APB2_UART3 54 +#define RST_APB2_UART4 55 +#define RST_APB2_UART5 56 + +#endif /* _DT_BINDINGS_RST_SUN6I_A31_H_ */ -- cgit v0.10.2 From d42c047245ae09ebc2f506c5d1730ce3113278ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 26 Aug 2016 14:58:07 +0200 Subject: clk: return unsigned int in dummy non-OF of_clk_get_parent_count() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the commit 929e7f3bc7b82 ("clk: Make of_clk_get_parent_count() return unsigned ints") of_clk_get_parent_count has been modified to return unsigned int. There is also a dummy implementation of the same function for configs without CONFIG_OF. For the consistency it should be updated as well. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Stephen Boyd diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index f403b8a..37b8fdc 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -854,7 +854,7 @@ of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data) { return ERR_PTR(-ENOENT); } -static inline int of_clk_get_parent_count(struct device_node *np) +static inline unsigned int of_clk_get_parent_count(struct device_node *np) { return 0; } -- cgit v0.10.2 From 74002fcde01d8acb4ce68878e9998fad51fe7925 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 25 Aug 2016 13:35:36 -0700 Subject: clk: Simplify __of_clk_get_hw_from_provider() __of_clk_get_hw_from_provider() is confusing because it will return EPROBE_DEFER if there isn't a ->get() or ->get_hw() function pointer in a provider. That's just a bug though, and we used to NULL pointer exception when ->get() was missing anyway, so let's make this more obvious that they're not optional. The assumption is that most providers will implement ->get_hw() so we only fallback to the ->get() function if necessary. This clarifies the intent and removes any possibility of probe defer happening if clk providers are buggy. Reported-by: Masahiro Yamada Reviewed-by: Sylwester Nawrocki Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 71cc567..d3d2614 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3174,19 +3174,14 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider, struct of_phandle_args *clkspec) { struct clk *clk; - struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); - if (provider->get_hw) { - hw = provider->get_hw(clkspec, provider->data); - } else if (provider->get) { - clk = provider->get(clkspec, provider->data); - if (!IS_ERR(clk)) - hw = __clk_get_hw(clk); - else - hw = ERR_CAST(clk); - } + if (provider->get_hw) + return provider->get_hw(clkspec, provider->data); - return hw; + clk = provider->get(clkspec, provider->data); + if (IS_ERR(clk)) + return ERR_CAST(clk); + return __clk_get_hw(clk); } struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, -- cgit v0.10.2 From fa62e10d2613b9e9edbe944b890644b30e9d4ed7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 27 Aug 2016 14:01:19 +0200 Subject: clk: versatile/icst: support for AP baseboard clocks This adds support for the two ICST525-based clocks on the Integrator/AP baseboard, as documented in the board manual "Integrator/AP ASIC Development Motherboard", ARM DUI0098 B, pages 3-15 thru 3-18. Cc: Russell King Signed-off-by: Linus Walleij [sboyd@codeaurora.org: fixed uninitialized val warning] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 8f06473..4faa944 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -29,15 +29,20 @@ #define VERSATILE_AUX_OSC_BITS 0x7FFFF #define INTEGRATOR_AP_CM_BITS 0xFF +#define INTEGRATOR_AP_SYS_BITS 0xFF #define INTEGRATOR_CP_CM_CORE_BITS 0x7FF #define INTEGRATOR_CP_CM_MEM_BITS 0x7FF000 +#define INTEGRATOR_AP_PCI_25_33_MHZ BIT(8) + /** * enum icst_control_type - the type of ICST control register */ enum icst_control_type { ICST_VERSATILE, /* The standard type, all control bits available */ ICST_INTEGRATOR_AP_CM, /* Only 8 bits of VDW available */ + ICST_INTEGRATOR_AP_SYS, /* Only 8 bits of VDW available */ + ICST_INTEGRATOR_AP_PCI, /* Odd bit pattern storage */ ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ }; @@ -93,6 +98,38 @@ static int vco_get(struct clk_icst *icst, struct icst_vco *vco) } /* + * The Integrator/AP system clock on the base board can only + * access the low eight bits of the v PLL divider. Bit 8 is tied low + * and always zero, r is hardwired to 46, and the output divider is + * hardwired to 3 (divide by 4) according to the document + * "Integrator AP ASIC Development Motherboard" ARM DUI 0098B, + * page 3-16. + */ + if (icst->ctype == ICST_INTEGRATOR_AP_SYS) { + vco->v = val & INTEGRATOR_AP_SYS_BITS; + vco->r = 46; + vco->s = 3; + return 0; + } + + /* + * The Integrator/AP PCI clock is using an odd pattern to create + * the child clock, basically a single bit called DIVX/Y is used + * to select between two different hardwired values: setting the + * bit to 0 yields v = 17, r = 22 and OD = 1, whereas setting the + * bit to 1 yields v = 14, r = 14 and OD = 1 giving the frequencies + * 33 or 25 MHz respectively. + */ + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { + bool divxy = !!(val & INTEGRATOR_AP_PCI_25_33_MHZ); + + vco->v = divxy ? 17 : 14; + vco->r = divxy ? 22 : 14; + vco->s = 1; + return 0; + } + + /* * The Integrator/CP core clock can access the low eight bits * of the v PLL divider. Bit 8 is tied low and always zero, * r is hardwired to 22 and the output divider s is accessible @@ -143,6 +180,16 @@ static int vco_set(struct clk_icst *icst, struct icst_vco vco) if (vco.r != 22) pr_err("ICST error: tried to use RDW != 22\n"); break; + case ICST_INTEGRATOR_AP_SYS: + mask = INTEGRATOR_AP_SYS_BITS; + val = vco.v & 0xFF; + if (vco.v & 0x100) + pr_err("ICST error: tried to set bit 8 of VDW\n"); + if (vco.s != 3) + pr_err("ICST error: tried to use VOD != 1\n"); + if (vco.r != 46) + pr_err("ICST error: tried to use RDW != 22\n"); + break; case ICST_INTEGRATOR_CP_CM_CORE: mask = INTEGRATOR_CP_CM_CORE_BITS; /* Uses 12 bits */ val = (vco.v & 0xFF) | vco.s << 8; @@ -225,6 +272,27 @@ static long icst_round_rate(struct clk_hw *hw, unsigned long rate, return DIV_ROUND_CLOSEST(rate, 500000) * 500000; } + if (icst->ctype == ICST_INTEGRATOR_AP_SYS) { + /* Divides between 3 and 50 MHz in steps of 0.25 MHz */ + if (rate <= 3000000) + return 3000000; + if (rate >= 50000000) + return 5000000; + /* Slam to closest 0.25 MHz */ + return DIV_ROUND_CLOSEST(rate, 250000) * 250000; + } + + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { + /* + * If we're below or less than halfway from 25 to 33 MHz + * select 25 MHz + */ + if (rate <= 25000000 || rate < 29000000) + return 25000000; + /* Else just return the default frequency */ + return 33000000; + } + vco = icst_hz_to_vco(icst->params, rate); return icst_hz(icst->params, vco); } @@ -235,6 +303,36 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { + /* This clock is especially primitive */ + unsigned int val; + int ret; + + if (rate == 25000000) { + val = 0; + } else if (rate == 33000000) { + val = INTEGRATOR_AP_PCI_25_33_MHZ; + } else { + pr_err("ICST: cannot set PCI frequency %lu\n", + rate); + return -EINVAL; + } + ret = regmap_write(icst->map, icst->lockreg_off, + VERSATILE_LOCK_VAL); + if (ret) + return ret; + ret = regmap_update_bits(icst->map, icst->vcoreg_off, + INTEGRATOR_AP_PCI_25_33_MHZ, + val); + if (ret) + return ret; + /* This locks the VCO again */ + ret = regmap_write(icst->map, icst->lockreg_off, 0); + if (ret) + return ret; + return 0; + } + if (parent_rate) icst->params->ref = parent_rate; vco = icst_hz_to_vco(icst->params, rate); @@ -368,6 +466,34 @@ static const struct icst_params icst525_apcp_cm_params = { .idx2s = icst525_idx2s, }; +static const struct icst_params icst525_ap_sys_params = { + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, + /* Minimum 3 MHz, VDW = 4 */ + .vd_min = 3, + /* Maximum 50 MHz, VDW = 192 */ + .vd_max = 50, + /* r is hardcoded to 46 and this is the actual divisor, +2 */ + .rd_min = 48, + .rd_max = 48, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, +}; + +static const struct icst_params icst525_ap_pci_params = { + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, + /* Minimum 25 MHz */ + .vd_min = 25, + /* Maximum 33 MHz */ + .vd_max = 33, + /* r is hardcoded to 14 or 22 and this is the actual divisors +2 */ + .rd_min = 16, + .rd_max = 24, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, +}; + static void __init of_syscon_icst_setup(struct device_node *np) { struct device_node *parent; @@ -408,6 +534,12 @@ static void __init of_syscon_icst_setup(struct device_node *np) } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-cm")) { icst_desc.params = &icst525_apcp_cm_params; ctype = ICST_INTEGRATOR_AP_CM; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-sys")) { + icst_desc.params = &icst525_ap_sys_params; + ctype = ICST_INTEGRATOR_AP_SYS; + } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-pci")) { + icst_desc.params = &icst525_ap_pci_params; + ctype = ICST_INTEGRATOR_AP_PCI; } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-core")) { icst_desc.params = &icst525_apcp_cm_params; ctype = ICST_INTEGRATOR_CP_CM_CORE; @@ -437,6 +569,10 @@ CLK_OF_DECLARE(arm_syscon_icst307_clk, "arm,syscon-icst307", of_syscon_icst_setup); CLK_OF_DECLARE(arm_syscon_integratorap_cm_clk, "arm,syscon-icst525-integratorap-cm", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorap_sys_clk, + "arm,syscon-icst525-integratorap-sys", of_syscon_icst_setup); +CLK_OF_DECLARE(arm_syscon_integratorap_pci_clk, + "arm,syscon-icst525-integratorap-pci", of_syscon_icst_setup); CLK_OF_DECLARE(arm_syscon_integratorcp_cm_core_clk, "arm,syscon-icst525-integratorcp-cm-core", of_syscon_icst_setup); CLK_OF_DECLARE(arm_syscon_integratorcp_cm_mem_clk, -- cgit v0.10.2 From 3174b0c9a62bb3738b4a2a506b8a075d4430e353 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 24 Aug 2016 08:32:51 +0200 Subject: clk: core: Force setting the phase delay when no change This patch reverts commit 023bd7166be0 ("clk: skip unnecessary set_phase if nothing to do"), fixing two problems: * in some SoCs, the hardware phase delay depends on the rate ratio of the clock and its parent. So, changing this ratio may imply to set new hardware values, even if the logical delay is the same. * when the delay was the same as previously, an error was returned. Signed-off-by: Jean-Francois Moine Fixes: 023bd7166be0 ("clk: skip unnecessary set_phase if nothing to do") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d3d2614..0fb39fe 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1908,10 +1908,6 @@ int clk_set_phase(struct clk *clk, int degrees) clk_prepare_lock(); - /* bail early if nothing to do */ - if (degrees == clk->core->phase) - goto out; - trace_clk_set_phase(clk->core, degrees); if (clk->core->ops->set_phase) @@ -1922,7 +1918,6 @@ int clk_set_phase(struct clk *clk, int degrees) if (!ret) clk->core->phase = degrees; -out: clk_prepare_unlock(); return ret; -- cgit v0.10.2 From 54fe0791fa0dbe075f6465860bdd38a4b4e6e59c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 30 Aug 2016 14:34:01 -0300 Subject: clk: imx7d: Add PLL_AUDIO_TEST_DIV/POST_DIV clocks Currently we see the following error when using the SAI audio driver on mx7: Division by zero in kernel. CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-rc3-next-20160823 Hardware name: Freescale i.MX7 Dual (Device Tree) Backtrace: [] (dump_backtrace) from [] (show_stack+0x18) r6:60000013 r5:ffffffff r4:00000000 r3:00000000 [] (show_stack) from [] (dump_stack+0xb0/0xe) [] (dump_stack) from [] (__div0+0x18/0x20) r8:00000000 r7:ffffffff r6:ffffffff r5:00000000 r4:00000000 r3:0 [] (__div0) from [] (Ldiv0_64+0x8/0x18) [] (divider_get_val) from [] (clk_divider_se) This error happens due to the lack of definition of the IMX7D_PLL_AUDIO_TEST_DIV/IMX7D_PLL_AUDIO_POST_DIV clocks. Add support for them. Tested on a imx7s-warp board. Signed-off-by: Fabio Estevam Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 6bafcaa..e7c7353 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -26,43 +26,59 @@ static u32 share_count_sai1; static u32 share_count_sai2; static u32 share_count_sai3; +static struct clk_div_table test_div_table[] = { + { .val = 3, .div = 1, }, + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { } +}; + +static struct clk_div_table post_div_table[] = { + { .val = 3, .div = 4, }, + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 1, }, + { } +}; + static struct clk *clks[IMX7D_CLK_END]; static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk", "pll_enet_500m_clk", "pll_dram_main_clk", - "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_main_clk", + "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_post_div", "pll_usb_main_clk", }; static const char *arm_m4_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_enet_250m_clk", "pll_sys_pfd2_270m_clk", - "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *arm_m0_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_125m_clk", "pll_sys_pfd2_135m_clk", - "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd5_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_sys_pfd7_clk", }; + "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd7_clk", }; static const char *disp_axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd6_clk", - "pll_sys_pfd7_clk", "pll_audio_main_clk", "pll_video_main_clk", }; + "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_main_clk", }; static const char *enet_axi_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", - "pll_sys_main_240m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd4_clk", }; static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_main_240m_clk", "pll_sys_pfd2_135m_clk", "pll_sys_pfd6_clk", "pll_enet_250m_clk", - "pll_audio_main_clk", }; + "pll_audio_post_div", }; static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", - "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_main_clk", + "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div", "pll_video_main_clk", }; static const char *dram_phym_sel[] = { "pll_dram_main_clk", @@ -73,13 +89,13 @@ static const char *dram_sel[] = { "pll_dram_main_clk", static const char *dram_phym_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", - "pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_main_clk", + "pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_main_clk", }; static const char *dram_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", "pll_enet_250m_clk", "pll_sys_pfd0_392m_clk", - "pll_audio_main_clk", "pll_sys_pfd2_270m_clk", }; + "pll_audio_post_div", "pll_sys_pfd2_270m_clk", }; static const char *usb_hsic_sel[] = { "osc", "pll_sys_main_clk", "pll_usb_main_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk", @@ -105,53 +121,53 @@ static const char *lcdif_pixel_sel[] = { "osc", "pll_sys_pfd5_clk", static const char *mipi_dsi_sel[] = { "osc", "pll_sys_pfd5_clk", "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk", - "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_main_clk", }; + "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", }; static const char *mipi_csi_sel[] = { "osc", "pll_sys_pfd4_clk", "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk", - "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_main_clk", }; + "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", }; static const char *mipi_dphy_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_dram_533m_clk", "pll_sys_pfd5_clk", "ref_1m_clk", "ext_clk_2", "pll_video_main_clk", "ext_clk_3", }; static const char *sai1_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", }; static const char *sai2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", }; static const char *sai3_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_3", }; static const char *spdif_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_3_clk", }; static const char *enet1_ref_sel[] = { "osc", "pll_enet_125m_clk", "pll_enet_50m_clk", "pll_enet_25m_clk", - "pll_sys_main_120m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk", "ext_clk_4", }; static const char *enet1_time_sel[] = { "osc", "pll_enet_100m_clk", - "pll_audio_main_clk", "ext_clk_1", "ext_clk_2", "ext_clk_3", + "pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3", "ext_clk_4", "pll_video_main_clk", }; static const char *enet2_ref_sel[] = { "osc", "pll_enet_125m_clk", "pll_enet_50m_clk", "pll_enet_25m_clk", - "pll_sys_main_120m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk", "ext_clk_4", }; static const char *enet2_time_sel[] = { "osc", "pll_enet_100m_clk", - "pll_audio_main_clk", "ext_clk_1", "ext_clk_2", "ext_clk_3", + "pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3", "ext_clk_4", "pll_video_main_clk", }; static const char *enet_phy_ref_sel[] = { "osc", "pll_enet_25m_clk", "pll_enet_50m_clk", "pll_enet_125m_clk", - "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd3_clk", }; static const char *eim_sel[] = { "osc", "pll_sys_pfd2_135m_clk", @@ -192,22 +208,22 @@ static const char *can2_sel[] = { "osc", "pll_sys_main_120m_clk", static const char *i2c1_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c2_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c3_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c4_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *uart1_sel[] = { "osc", "pll_sys_main_240m_clk", @@ -266,32 +282,32 @@ static const char *ecspi4_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_usb_main_clk", }; static const char *pwm1_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", }; static const char *pwm2_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", }; static const char *pwm3_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", }; static const char *pwm4_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", }; static const char *flextimer1_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", }; static const char *flextimer2_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk", + "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", }; static const char *sim1_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_usb_main_clk", "pll_audio_main_clk", "pll_enet_125m_clk", + "pll_usb_main_clk", "pll_audio_post_div", "pll_enet_125m_clk", "pll_sys_pfd7_clk", }; static const char *sim2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", @@ -301,19 +317,19 @@ static const char *sim2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", static const char *gpt1_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_1", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_1", }; static const char *gpt2_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_2", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_2", }; static const char *gpt3_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_3", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_3", }; static const char *gpt4_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", - "ref_1m_clk", "pll_audio_main_clk", "ext_clk_4", }; + "ref_1m_clk", "pll_audio_post_div", "ext_clk_4", }; static const char *trace_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", @@ -327,12 +343,12 @@ static const char *wdog_sel[] = { "osc", "pll_sys_pfd2_135m_clk", static const char *csi_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_enet_125m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *audio_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_enet_125m_clk", "pll_audio_main_clk", "pll_video_main_clk", + "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; static const char *wrclk_sel[] = { "osc", "pll_enet_40m_clk", @@ -346,13 +362,13 @@ static const char *clko1_sel[] = { "osc", "pll_sys_main_clk", static const char *clko2_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_166m_clk", "pll_sys_pfd4_clk", - "pll_audio_main_clk", "pll_video_main_clk", "ckil", }; + "pll_audio_post_div", "pll_video_main_clk", "ckil", }; static const char *lvds1_sel[] = { "pll_arm_main_clk", "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_332m_clk", "pll_sys_pfd2_270m_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk", "pll_sys_pfd5_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", - "pll_audio_main_clk", "pll_video_main_clk", "pll_enet_500m_clk", + "pll_audio_post_div", "pll_video_main_clk", "pll_enet_500m_clk", "pll_enet_250m_clk", "pll_enet_125m_clk", "pll_enet_100m_clk", "pll_enet_50m_clk", "pll_enet_40m_clk", "pll_enet_25m_clk", "pll_dram_main_clk", }; @@ -434,6 +450,11 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13); clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13); + clks[IMX7D_PLL_AUDIO_TEST_DIV] = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock); + clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 22, 2, 0, post_div_table, &imx_ccm_lock); + clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0); clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1); clks[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2); -- cgit v0.10.2 From 7fbdfcd68783679f35fa99df948258cb3e828cd1 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 22 Aug 2016 11:36:18 +0800 Subject: clk: rockchip: add SCLK_DDRC id for rk3399 ddrc Add the needed id for the ddr clock. Signed-off-by: Lin Huang Signed-off-by: Heiko Stuebner diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h index 50a44cf..ce5f3e9 100644 --- a/include/dt-bindings/clock/rk3399-cru.h +++ b/include/dt-bindings/clock/rk3399-cru.h @@ -131,6 +131,7 @@ #define SCLK_DPHY_RX0_CFG 165 #define SCLK_RMII_SRC 166 #define SCLK_PCIEPHY_REF100M 167 +#define SCLK_DDRC 168 #define DCLK_VOP0 180 #define DCLK_VOP1 181 -- cgit v0.10.2 From 97dd82682f1a6174698fbea149a04b4cabc58c4f Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 22 Aug 2016 11:36:17 +0800 Subject: soc: rockchip: add header for ddr rate SIP interface Add a header for the SIP interface defined to access the dcf controller handling ddr rate changes on rk3399 (and most likely later socs). This interface is shared between the clock driver as well as the devfreq driver. The SIP interface counterpart was merged from pull-request #684 [0] into the upstream arm-trusted-firmware codebase. [0] https://github.com/ARM-software/arm-trusted-firmware/pull/684 Signed-off-by: Lin Huang Signed-off-by: Heiko Stuebner diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip_sip.h new file mode 100644 index 0000000..7e28092 --- /dev/null +++ b/include/soc/rockchip/rockchip_sip.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#ifndef __SOC_ROCKCHIP_SIP_H +#define __SOC_ROCKCHIP_SIP_H + +#define ROCKCHIP_SIP_DRAM_FREQ 0x82000008 +#define ROCKCHIP_SIP_CONFIG_DRAM_INIT 0x00 +#define ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE 0x01 +#define ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE 0x02 +#define ROCKCHIP_SIP_CONFIG_DRAM_SET_AT_SR 0x03 +#define ROCKCHIP_SIP_CONFIG_DRAM_GET_BW 0x04 +#define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE 0x05 +#define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ 0x06 +#define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM 0x07 + +#endif -- cgit v0.10.2 From a4f182bf81f18f91f1aef6289fcdfa6a2ac51b99 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 22 Aug 2016 11:36:17 +0800 Subject: clk: rockchip: add new clock-type for the ddrclk Changing the rate of the DDR clock needs special care, as the DDR is of course in use and will react badly if the rate changes under it. Over time different approaches to handle that were used. Past SoCs like the rk3288 and before would store some code in SRAM while the rk3368 used a SCPI variant and let a coprocessor handle that. New rockchip platforms like the rk3399 have a dcf controller to do ddr frequency scaling, and support for this controller will be implemented in the arm-trusted-firmware. This new clock-type should over time handle all these methods for handling DDR rate changes, but right now it will concentrate on the SIP interface used to talk to ARM trusted firmware. The SIP interface counterpart was merged from pull-request #684 [0] into the upstream arm-trusted-firmware codebase. [0] https://github.com/ARM-software/arm-trusted-firmware/pull/684 Signed-off-by: Lin Huang Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa..b5f2c8e 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y += clk-pll.o obj-y += clk-cpu.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o +obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-y += clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 0000000..8feba93 --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include "clk.h" + +struct rockchip_ddrclk { + struct clk_hw hw; + void __iomem *reg_base; + int mux_offset; + int mux_shift; + int mux_width; + int div_shift; + int div_width; + int ddr_flag; + spinlock_t *lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) + +static int rockchip_ddrclk_sip_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + unsigned long flags; + struct arm_smccc_res res; + + spin_lock_irqsave(ddrclk->lock, flags); + arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, drate, 0, + ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE, + 0, 0, 0, 0, &res); + spin_unlock_irqrestore(ddrclk->lock, flags); + + return res.a0; +} + +static unsigned long +rockchip_ddrclk_sip_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct arm_smccc_res res; + + arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0, + ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE, + 0, 0, 0, 0, &res); + + return res.a0; +} + +static long rockchip_ddrclk_sip_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + struct arm_smccc_res res; + + arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, rate, 0, + ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE, + 0, 0, 0, 0, &res); + + return res.a0; +} + +static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + int num_parents = clk_hw_get_num_parents(hw); + u32 val; + + val = clk_readl(ddrclk->reg_base + + ddrclk->mux_offset) >> ddrclk->mux_shift; + val &= GENMASK(ddrclk->mux_width - 1, 0); + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static const struct clk_ops rockchip_ddrclk_sip_ops = { + .recalc_rate = rockchip_ddrclk_sip_recalc_rate, + .set_rate = rockchip_ddrclk_sip_set_rate, + .round_rate = rockchip_ddrclk_sip_round_rate, + .get_parent = rockchip_ddrclk_get_parent, +}; + +struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, + u8 num_parents, int mux_offset, + int mux_shift, int mux_width, + int div_shift, int div_width, + int ddr_flag, void __iomem *reg_base, + spinlock_t *lock) +{ + struct rockchip_ddrclk *ddrclk; + struct clk_init_data init; + struct clk *clk; + + ddrclk = kzalloc(sizeof(*ddrclk), GFP_KERNEL); + if (!ddrclk) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.parent_names = parent_names; + init.num_parents = num_parents; + + init.flags = flags; + init.flags |= CLK_SET_RATE_NO_REPARENT; + + switch (ddr_flag) { + case ROCKCHIP_DDRCLK_SIP: + init.ops = &rockchip_ddrclk_sip_ops; + break; + default: + pr_err("%s: unsupported ddrclk type %d\n", __func__, ddr_flag); + kfree(ddrclk); + return ERR_PTR(-EINVAL); + } + + ddrclk->reg_base = reg_base; + ddrclk->lock = lock; + ddrclk->hw.init = &init; + ddrclk->mux_offset = mux_offset; + ddrclk->mux_shift = mux_shift; + ddrclk->mux_width = mux_width; + ddrclk->div_shift = div_shift; + ddrclk->div_width = div_width; + ddrclk->ddr_flag = ddr_flag; + + clk = clk_register(NULL, &ddrclk->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register ddrclk %s\n", __func__, name); + kfree(ddrclk); + return NULL; + } + + return clk; +} diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 1f1c74f..b886be3 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -484,6 +484,15 @@ void __init rockchip_clk_register_branches( list->gate_offset, list->gate_shift, list->gate_flags, flags, &ctx->lock); break; + case branch_ddrclk: + clk = rockchip_clk_register_ddrclk( + list->name, list->flags, + list->parent_names, list->num_parents, + list->muxdiv_offset, list->mux_shift, + list->mux_width, list->div_shift, + list->div_width, list->div_flags, + ctx->reg_base, &ctx->lock); + break; } /* none of the cases above matched */ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 3747de5..1653edd 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -281,6 +281,20 @@ struct clk *rockchip_clk_register_mmc(const char *name, const char *const *parent_names, u8 num_parents, void __iomem *reg, int shift); +/* + * DDRCLK flags, including method of setting the rate + * ROCKCHIP_DDRCLK_SIP: use SIP call to bl31 to change ddrclk rate. + */ +#define ROCKCHIP_DDRCLK_SIP BIT(0) + +struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, + u8 num_parents, int mux_offset, + int mux_shift, int mux_width, + int div_shift, int div_width, + int ddr_flags, void __iomem *reg_base, + spinlock_t *lock); + #define ROCKCHIP_INVERTER_HIWORD_MASK BIT(0) struct clk *rockchip_clk_register_inverter(const char *name, @@ -299,6 +313,7 @@ enum rockchip_clk_branch_type { branch_mmc, branch_inverter, branch_factor, + branch_ddrclk, }; struct rockchip_clk_branch { @@ -488,6 +503,24 @@ struct rockchip_clk_branch { .child = ch, \ } +#define COMPOSITE_DDRCLK(_id, cname, pnames, f, mo, ms, mw, \ + ds, dw, df) \ + { \ + .id = _id, \ + .branch_type = branch_ddrclk, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = -1, \ + } + #define MUX(_id, cname, pnames, f, o, s, w, mf) \ { \ .id = _id, \ -- cgit v0.10.2 From 23353817f85934528d056541894c70346c3822b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20M=C3=BCller?= Date: Sat, 27 Aug 2016 19:40:49 +0200 Subject: clk: meson: Rename meson8b-clkc.c to reflect gxbb naming convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexander Müller Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1472319654-59048-2-git-send-email-serveralex@gmail.com diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index d4cd4a3..3495834 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -3,5 +3,5 @@ # obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o -obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b-clkc.o +obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o diff --git a/drivers/clk/meson/meson8b-clkc.c b/drivers/clk/meson/meson8b-clkc.c deleted file mode 100644 index 4c9413c..0000000 --- a/drivers/clk/meson/meson8b-clkc.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * AmLogic S805 / Meson8b Clock Controller Driver - * - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione - * - * Copyright (c) 2016 BayLibre, Inc. - * Michael Turquette - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "clkc.h" - -/* - * Clock controller register offsets - * - * Register offsets from the HardKernel[0] data sheet are listed in comment - * blocks below. Those offsets must be multiplied by 4 before adding them to - * the base address to get the right value - * - * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf - */ -#define MESON8B_REG_SYS_CPU_CNTL1 0x015c /* 0x57 offset in data sheet */ -#define MESON8B_REG_HHI_MPEG 0x0174 /* 0x5d offset in data sheet */ -#define MESON8B_REG_MALI 0x01b0 /* 0x6c offset in data sheet */ -#define MESON8B_REG_PLL_FIXED 0x0280 -#define MESON8B_REG_PLL_SYS 0x0300 -#define MESON8B_REG_PLL_VID 0x0320 - -static DEFINE_SPINLOCK(clk_lock); - -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(408000000, 68, 1, 2), - PLL_RATE(432000000, 72, 1, 2), - PLL_RATE(456000000, 76, 1, 2), - PLL_RATE(480000000, 80, 1, 2), - PLL_RATE(504000000, 84, 1, 2), - PLL_RATE(528000000, 88, 1, 2), - PLL_RATE(552000000, 92, 1, 2), - PLL_RATE(576000000, 96, 1, 2), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(840000000, 70, 1, 1), - PLL_RATE(864000000, 72, 1, 1), - PLL_RATE(888000000, 74, 1, 1), - PLL_RATE(912000000, 76, 1, 1), - PLL_RATE(936000000, 78, 1, 1), - PLL_RATE(960000000, 80, 1, 1), - PLL_RATE(984000000, 82, 1, 1), - PLL_RATE(1008000000, 84, 1, 1), - PLL_RATE(1032000000, 86, 1, 1), - PLL_RATE(1056000000, 88, 1, 1), - PLL_RATE(1080000000, 90, 1, 1), - PLL_RATE(1104000000, 92, 1, 1), - PLL_RATE(1128000000, 94, 1, 1), - PLL_RATE(1152000000, 96, 1, 1), - PLL_RATE(1176000000, 98, 1, 1), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), - { /* sentinel */ }, -}; - -static const struct clk_div_table cpu_div_table[] = { - { .val = 1, .div = 1 }, - { .val = 2, .div = 2 }, - { .val = 3, .div = 3 }, - { .val = 2, .div = 4 }, - { .val = 3, .div = 6 }, - { .val = 4, .div = 8 }, - { .val = 5, .div = 10 }, - { .val = 6, .div = 12 }, - { .val = 7, .div = 14 }, - { .val = 8, .div = 16 }, - { /* sentinel */ }, -}; - -static struct clk_fixed_rate meson8b_xtal = { - .fixed_rate = 24000000, - .hw.init = &(struct clk_init_data){ - .name = "xtal", - .num_parents = 0, - .ops = &clk_fixed_rate_ops, - }, -}; - -static struct meson_clk_pll meson8b_fixed_pll = { - .m = { - .reg_off = MESON8B_REG_PLL_FIXED, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = MESON8B_REG_PLL_FIXED, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = MESON8B_REG_PLL_FIXED, - .shift = 16, - .width = 2, - }, - .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", - .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct meson_clk_pll meson8b_vid_pll = { - .m = { - .reg_off = MESON8B_REG_PLL_VID, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = MESON8B_REG_PLL_VID, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = MESON8B_REG_PLL_VID, - .shift = 16, - .width = 2, - }, - .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ - .name = "vid_pll", - .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct meson_clk_pll meson8b_sys_pll = { - .m = { - .reg_off = MESON8B_REG_PLL_SYS, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = MESON8B_REG_PLL_SYS, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = MESON8B_REG_PLL_SYS, - .shift = 16, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ - .name = "sys_pll", - .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct clk_fixed_factor meson8b_fclk_div2 = { - .mult = 1, - .div = 2, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", - .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor meson8b_fclk_div3 = { - .mult = 1, - .div = 3, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", - .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor meson8b_fclk_div4 = { - .mult = 1, - .div = 4, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", - .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor meson8b_fclk_div5 = { - .mult = 1, - .div = 5, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", - .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor meson8b_fclk_div7 = { - .mult = 1, - .div = 7, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", - .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "fixed_pll" }, - .num_parents = 1, - }, -}; - -/* - * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL - * post-dividers and should be modeled with their respective PLLs via the - * forthcoming coordinated clock rates feature - */ -static struct meson_clk_cpu meson8b_cpu_clk = { - .reg_off = MESON8B_REG_SYS_CPU_CNTL1, - .div_table = cpu_div_table, - .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, - .hw.init = &(struct clk_init_data){ - .name = "cpu_clk", - .ops = &meson_clk_cpu_ops, - .parent_names = (const char *[]){ "sys_pll" }, - .num_parents = 1, - }, -}; - -static u32 mux_table_clk81[] = { 6, 5, 7 }; - -struct clk_mux meson8b_mpeg_clk_sel = { - .reg = (void *)MESON8B_REG_HHI_MPEG, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, - /* - * FIXME bits 14:12 selects from 8 possible parents: - * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, - * fclk_div4, fclk_div3, fclk_div5 - */ - .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", - "fclk_div5" }, - .num_parents = 3, - .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), - }, -}; - -struct clk_divider meson8b_mpeg_clk_div = { - .reg = (void *)MESON8B_REG_HHI_MPEG, - .shift = 0, - .width = 7, - .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_div", - .ops = &clk_divider_ops, - .parent_names = (const char *[]){ "mpeg_clk_sel" }, - .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), - }, -}; - -struct clk_gate meson8b_clk81 = { - .reg = (void *)MESON8B_REG_HHI_MPEG, - .bit_idx = 7, - .lock = &clk_lock, - .hw.init = &(struct clk_init_data){ - .name = "clk81", - .ops = &clk_gate_ops, - .parent_names = (const char *[]){ "mpeg_clk_div" }, - .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), - }, -}; - -static struct clk_hw_onecell_data meson8b_hw_onecell_data = { - .hws = { - [CLKID_XTAL] = &meson8b_xtal.hw, - [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, - [CLKID_PLL_VID] = &meson8b_vid_pll.hw, - [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, - [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, - [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, - [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, - [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, - [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, - [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, - [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, - [CLKID_CLK81] = &meson8b_clk81.hw, - }, - .num = CLK_NR_CLKS, -}; - -static struct meson_clk_pll *const meson8b_clk_plls[] = { - &meson8b_fixed_pll, - &meson8b_vid_pll, - &meson8b_sys_pll, -}; - -static int meson8b_clkc_probe(struct platform_device *pdev) -{ - void __iomem *clk_base; - int ret, clkid, i; - struct clk_hw *parent_hw; - struct clk *parent_clk; - struct device *dev = &pdev->dev; - - /* Generic clocks and PLLs */ - clk_base = of_iomap(dev->of_node, 1); - if (!clk_base) { - pr_err("%s: Unable to map clk base\n", __func__); - return -ENXIO; - } - - /* Populate base address for PLLs */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) - meson8b_clk_plls[i]->base = clk_base; - - /* Populate the base address for CPU clk */ - meson8b_cpu_clk.base = clk_base; - - /* Populate the base address for the MPEG clks */ - meson8b_mpeg_clk_sel.reg = clk_base + (u32)meson8b_mpeg_clk_sel.reg; - meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg; - meson8b_clk81.reg = clk_base + (u32)meson8b_clk81.reg; - - /* - * register all clks - * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 - */ - for (clkid = CLKID_XTAL; clkid < CLK_NR_CLKS; clkid++) { - /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[clkid]) - continue; - - /* FIXME convert to devm_clk_register */ - ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); - if (ret) - goto iounmap; - } - - /* - * Register CPU clk notifier - * - * FIXME this is wrong for a lot of reasons. First, the muxes should be - * struct clk_hw objects. Second, we shouldn't program the muxes in - * notifier handlers. The tricky programming sequence will be handled - * by the forthcoming coordinated clock rates mechanism once that - * feature is released. - * - * Furthermore, looking up the parent this way is terrible. At some - * point we will stop allocating a default struct clk when registering - * a new clk_hw, and this hack will no longer work. Releasing the ccr - * feature before that time solves the problem :-) - */ - parent_hw = clk_hw_get_parent(&meson8b_cpu_clk.hw); - parent_clk = parent_hw->clk; - ret = clk_notifier_register(parent_clk, &meson8b_cpu_clk.clk_nb); - if (ret) { - pr_err("%s: failed to register clock notifier for cpu_clk\n", - __func__); - goto iounmap; - } - - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - &meson8b_hw_onecell_data); - -iounmap: - iounmap(clk_base); - return ret; -} - -static const struct of_device_id meson8b_clkc_match_table[] = { - { .compatible = "amlogic,meson8b-clkc" }, - { } -}; - -static struct platform_driver meson8b_driver = { - .probe = meson8b_clkc_probe, - .driver = { - .name = "meson8b-clkc", - .of_match_table = meson8b_clkc_match_table, - }, -}; - -static int __init meson8b_clkc_init(void) -{ - return platform_driver_register(&meson8b_driver); -} -device_initcall(meson8b_clkc_init); diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c new file mode 100644 index 0000000..4c9413c --- /dev/null +++ b/drivers/clk/meson/meson8b.c @@ -0,0 +1,447 @@ +/* + * AmLogic S805 / Meson8b Clock Controller Driver + * + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * Copyright (c) 2016 BayLibre, Inc. + * Michael Turquette + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "clkc.h" + +/* + * Clock controller register offsets + * + * Register offsets from the HardKernel[0] data sheet are listed in comment + * blocks below. Those offsets must be multiplied by 4 before adding them to + * the base address to get the right value + * + * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf + */ +#define MESON8B_REG_SYS_CPU_CNTL1 0x015c /* 0x57 offset in data sheet */ +#define MESON8B_REG_HHI_MPEG 0x0174 /* 0x5d offset in data sheet */ +#define MESON8B_REG_MALI 0x01b0 /* 0x6c offset in data sheet */ +#define MESON8B_REG_PLL_FIXED 0x0280 +#define MESON8B_REG_PLL_SYS 0x0300 +#define MESON8B_REG_PLL_VID 0x0320 + +static DEFINE_SPINLOCK(clk_lock); + +static const struct pll_rate_table sys_pll_rate_table[] = { + PLL_RATE(312000000, 52, 1, 2), + PLL_RATE(336000000, 56, 1, 2), + PLL_RATE(360000000, 60, 1, 2), + PLL_RATE(384000000, 64, 1, 2), + PLL_RATE(408000000, 68, 1, 2), + PLL_RATE(432000000, 72, 1, 2), + PLL_RATE(456000000, 76, 1, 2), + PLL_RATE(480000000, 80, 1, 2), + PLL_RATE(504000000, 84, 1, 2), + PLL_RATE(528000000, 88, 1, 2), + PLL_RATE(552000000, 92, 1, 2), + PLL_RATE(576000000, 96, 1, 2), + PLL_RATE(600000000, 50, 1, 1), + PLL_RATE(624000000, 52, 1, 1), + PLL_RATE(648000000, 54, 1, 1), + PLL_RATE(672000000, 56, 1, 1), + PLL_RATE(696000000, 58, 1, 1), + PLL_RATE(720000000, 60, 1, 1), + PLL_RATE(744000000, 62, 1, 1), + PLL_RATE(768000000, 64, 1, 1), + PLL_RATE(792000000, 66, 1, 1), + PLL_RATE(816000000, 68, 1, 1), + PLL_RATE(840000000, 70, 1, 1), + PLL_RATE(864000000, 72, 1, 1), + PLL_RATE(888000000, 74, 1, 1), + PLL_RATE(912000000, 76, 1, 1), + PLL_RATE(936000000, 78, 1, 1), + PLL_RATE(960000000, 80, 1, 1), + PLL_RATE(984000000, 82, 1, 1), + PLL_RATE(1008000000, 84, 1, 1), + PLL_RATE(1032000000, 86, 1, 1), + PLL_RATE(1056000000, 88, 1, 1), + PLL_RATE(1080000000, 90, 1, 1), + PLL_RATE(1104000000, 92, 1, 1), + PLL_RATE(1128000000, 94, 1, 1), + PLL_RATE(1152000000, 96, 1, 1), + PLL_RATE(1176000000, 98, 1, 1), + PLL_RATE(1200000000, 50, 1, 0), + PLL_RATE(1224000000, 51, 1, 0), + PLL_RATE(1248000000, 52, 1, 0), + PLL_RATE(1272000000, 53, 1, 0), + PLL_RATE(1296000000, 54, 1, 0), + PLL_RATE(1320000000, 55, 1, 0), + PLL_RATE(1344000000, 56, 1, 0), + PLL_RATE(1368000000, 57, 1, 0), + PLL_RATE(1392000000, 58, 1, 0), + PLL_RATE(1416000000, 59, 1, 0), + PLL_RATE(1440000000, 60, 1, 0), + PLL_RATE(1464000000, 61, 1, 0), + PLL_RATE(1488000000, 62, 1, 0), + PLL_RATE(1512000000, 63, 1, 0), + PLL_RATE(1536000000, 64, 1, 0), + { /* sentinel */ }, +}; + +static const struct clk_div_table cpu_div_table[] = { + { .val = 1, .div = 1 }, + { .val = 2, .div = 2 }, + { .val = 3, .div = 3 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 6 }, + { .val = 4, .div = 8 }, + { .val = 5, .div = 10 }, + { .val = 6, .div = 12 }, + { .val = 7, .div = 14 }, + { .val = 8, .div = 16 }, + { /* sentinel */ }, +}; + +static struct clk_fixed_rate meson8b_xtal = { + .fixed_rate = 24000000, + .hw.init = &(struct clk_init_data){ + .name = "xtal", + .num_parents = 0, + .ops = &clk_fixed_rate_ops, + }, +}; + +static struct meson_clk_pll meson8b_fixed_pll = { + .m = { + .reg_off = MESON8B_REG_PLL_FIXED, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = MESON8B_REG_PLL_FIXED, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = MESON8B_REG_PLL_FIXED, + .shift = 16, + .width = 2, + }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct meson_clk_pll meson8b_vid_pll = { + .m = { + .reg_off = MESON8B_REG_PLL_VID, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = MESON8B_REG_PLL_VID, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = MESON8B_REG_PLL_VID, + .shift = 16, + .width = 2, + }, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct meson_clk_pll meson8b_sys_pll = { + .m = { + .reg_off = MESON8B_REG_PLL_SYS, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = MESON8B_REG_PLL_SYS, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = MESON8B_REG_PLL_SYS, + .shift = 16, + .width = 2, + }, + .rate_table = sys_pll_rate_table, + .rate_count = ARRAY_SIZE(sys_pll_rate_table), + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div5 = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div7 = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +/* + * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL + * post-dividers and should be modeled with their respective PLLs via the + * forthcoming coordinated clock rates feature + */ +static struct meson_clk_cpu meson8b_cpu_clk = { + .reg_off = MESON8B_REG_SYS_CPU_CNTL1, + .div_table = cpu_div_table, + .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &meson_clk_cpu_ops, + .parent_names = (const char *[]){ "sys_pll" }, + .num_parents = 1, + }, +}; + +static u32 mux_table_clk81[] = { 6, 5, 7 }; + +struct clk_mux meson8b_mpeg_clk_sel = { + .reg = (void *)MESON8B_REG_HHI_MPEG, + .mask = 0x7, + .shift = 12, + .flags = CLK_MUX_READ_ONLY, + .table = mux_table_clk81, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_sel", + .ops = &clk_mux_ro_ops, + /* + * FIXME bits 14:12 selects from 8 possible parents: + * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, + * fclk_div4, fclk_div3, fclk_div5 + */ + .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", + "fclk_div5" }, + .num_parents = 3, + .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_divider meson8b_mpeg_clk_div = { + .reg = (void *)MESON8B_REG_HHI_MPEG, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_gate meson8b_clk81 = { + .reg = (void *)MESON8B_REG_HHI_MPEG, + .bit_idx = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "mpeg_clk_div" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_hw_onecell_data meson8b_hw_onecell_data = { + .hws = { + [CLKID_XTAL] = &meson8b_xtal.hw, + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, + }, + .num = CLK_NR_CLKS, +}; + +static struct meson_clk_pll *const meson8b_clk_plls[] = { + &meson8b_fixed_pll, + &meson8b_vid_pll, + &meson8b_sys_pll, +}; + +static int meson8b_clkc_probe(struct platform_device *pdev) +{ + void __iomem *clk_base; + int ret, clkid, i; + struct clk_hw *parent_hw; + struct clk *parent_clk; + struct device *dev = &pdev->dev; + + /* Generic clocks and PLLs */ + clk_base = of_iomap(dev->of_node, 1); + if (!clk_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + + /* Populate base address for PLLs */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) + meson8b_clk_plls[i]->base = clk_base; + + /* Populate the base address for CPU clk */ + meson8b_cpu_clk.base = clk_base; + + /* Populate the base address for the MPEG clks */ + meson8b_mpeg_clk_sel.reg = clk_base + (u32)meson8b_mpeg_clk_sel.reg; + meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg; + meson8b_clk81.reg = clk_base + (u32)meson8b_clk81.reg; + + /* + * register all clks + * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 + */ + for (clkid = CLKID_XTAL; clkid < CLK_NR_CLKS; clkid++) { + /* array might be sparse */ + if (!meson8b_hw_onecell_data.hws[clkid]) + continue; + + /* FIXME convert to devm_clk_register */ + ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); + if (ret) + goto iounmap; + } + + /* + * Register CPU clk notifier + * + * FIXME this is wrong for a lot of reasons. First, the muxes should be + * struct clk_hw objects. Second, we shouldn't program the muxes in + * notifier handlers. The tricky programming sequence will be handled + * by the forthcoming coordinated clock rates mechanism once that + * feature is released. + * + * Furthermore, looking up the parent this way is terrible. At some + * point we will stop allocating a default struct clk when registering + * a new clk_hw, and this hack will no longer work. Releasing the ccr + * feature before that time solves the problem :-) + */ + parent_hw = clk_hw_get_parent(&meson8b_cpu_clk.hw); + parent_clk = parent_hw->clk; + ret = clk_notifier_register(parent_clk, &meson8b_cpu_clk.clk_nb); + if (ret) { + pr_err("%s: failed to register clock notifier for cpu_clk\n", + __func__); + goto iounmap; + } + + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + &meson8b_hw_onecell_data); + +iounmap: + iounmap(clk_base); + return ret; +} + +static const struct of_device_id meson8b_clkc_match_table[] = { + { .compatible = "amlogic,meson8b-clkc" }, + { } +}; + +static struct platform_driver meson8b_driver = { + .probe = meson8b_clkc_probe, + .driver = { + .name = "meson8b-clkc", + .of_match_table = meson8b_clkc_match_table, + }, +}; + +static int __init meson8b_clkc_init(void) +{ + return platform_driver_register(&meson8b_driver); +} +device_initcall(meson8b_clkc_init); -- cgit v0.10.2 From d0c175da68d7e8f6b52b9fcaffae1d73d51a8655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20M=C3=BCller?= Date: Sat, 27 Aug 2016 19:40:50 +0200 Subject: meson: clk: Move register definitions to meson8b.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the register definitions into a separate header file to reflect the gxbb implementation. Signed-off-by: Alexander Müller Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1472319654-59048-3-git-send-email-serveralex@gmail.com diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 4c9413c..d52ae53 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -28,22 +28,7 @@ #include #include "clkc.h" - -/* - * Clock controller register offsets - * - * Register offsets from the HardKernel[0] data sheet are listed in comment - * blocks below. Those offsets must be multiplied by 4 before adding them to - * the base address to get the right value - * - * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf - */ -#define MESON8B_REG_SYS_CPU_CNTL1 0x015c /* 0x57 offset in data sheet */ -#define MESON8B_REG_HHI_MPEG 0x0174 /* 0x5d offset in data sheet */ -#define MESON8B_REG_MALI 0x01b0 /* 0x6c offset in data sheet */ -#define MESON8B_REG_PLL_FIXED 0x0280 -#define MESON8B_REG_PLL_SYS 0x0300 -#define MESON8B_REG_PLL_VID 0x0320 +#include "meson8b.h" static DEFINE_SPINLOCK(clk_lock); diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h new file mode 100644 index 0000000..5b9cb9f --- /dev/null +++ b/drivers/clk/meson/meson8b.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * Copyright (c) 2016 BayLibre, Inc. + * Michael Turquette + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __MESON8B_H +#define __MESON8B_H + +/* + * Clock controller register offsets + * + * Register offsets from the HardKernel[0] data sheet are listed in comment + * blocks below. Those offsets must be multiplied by 4 before adding them to + * the base address to get the right value + * + * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf + */ +#define MESON8B_REG_SYS_CPU_CNTL1 0x015c /* 0x57 offset in data sheet */ +#define MESON8B_REG_HHI_MPEG 0x0174 /* 0x5d offset in data sheet */ +#define MESON8B_REG_MALI 0x01b0 /* 0x6c offset in data sheet */ +#define MESON8B_REG_PLL_FIXED 0x0280 +#define MESON8B_REG_PLL_SYS 0x0300 +#define MESON8B_REG_PLL_VID 0x0320 + +#endif /* __MESON8B_H */ -- cgit v0.10.2 From e0818a3960418bfef1bbc120bfe8346ff9f3c5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20M=C3=BCller?= Date: Sat, 27 Aug 2016 19:40:51 +0200 Subject: meson: clk: Rename register names according to Amlogic datasheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexander Müller Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1472319654-59048-4-git-send-email-serveralex@gmail.com diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index d52ae53..24395dc 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -113,17 +113,17 @@ static struct clk_fixed_rate meson8b_xtal = { static struct meson_clk_pll meson8b_fixed_pll = { .m = { - .reg_off = MESON8B_REG_PLL_FIXED, + .reg_off = HHI_MPLL_CNTL, .shift = 0, .width = 9, }, .n = { - .reg_off = MESON8B_REG_PLL_FIXED, + .reg_off = HHI_MPLL_CNTL, .shift = 9, .width = 5, }, .od = { - .reg_off = MESON8B_REG_PLL_FIXED, + .reg_off = HHI_MPLL_CNTL, .shift = 16, .width = 2, }, @@ -139,17 +139,17 @@ static struct meson_clk_pll meson8b_fixed_pll = { static struct meson_clk_pll meson8b_vid_pll = { .m = { - .reg_off = MESON8B_REG_PLL_VID, + .reg_off = HHI_VID_PLL_CNTL, .shift = 0, .width = 9, }, .n = { - .reg_off = MESON8B_REG_PLL_VID, + .reg_off = HHI_VID_PLL_CNTL, .shift = 9, .width = 5, }, .od = { - .reg_off = MESON8B_REG_PLL_VID, + .reg_off = HHI_VID_PLL_CNTL, .shift = 16, .width = 2, }, @@ -165,17 +165,17 @@ static struct meson_clk_pll meson8b_vid_pll = { static struct meson_clk_pll meson8b_sys_pll = { .m = { - .reg_off = MESON8B_REG_PLL_SYS, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, .width = 9, }, .n = { - .reg_off = MESON8B_REG_PLL_SYS, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 9, .width = 5, }, .od = { - .reg_off = MESON8B_REG_PLL_SYS, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 16, .width = 2, }, @@ -252,7 +252,7 @@ static struct clk_fixed_factor meson8b_fclk_div7 = { * forthcoming coordinated clock rates feature */ static struct meson_clk_cpu meson8b_cpu_clk = { - .reg_off = MESON8B_REG_SYS_CPU_CNTL1, + .reg_off = HHI_SYS_CPU_CLK_CNTL1, .div_table = cpu_div_table, .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, .hw.init = &(struct clk_init_data){ @@ -266,7 +266,7 @@ static struct meson_clk_cpu meson8b_cpu_clk = { static u32 mux_table_clk81[] = { 6, 5, 7 }; struct clk_mux meson8b_mpeg_clk_sel = { - .reg = (void *)MESON8B_REG_HHI_MPEG, + .reg = (void *)HHI_MPEG_CLK_CNTL, .mask = 0x7, .shift = 12, .flags = CLK_MUX_READ_ONLY, @@ -288,7 +288,7 @@ struct clk_mux meson8b_mpeg_clk_sel = { }; struct clk_divider meson8b_mpeg_clk_div = { - .reg = (void *)MESON8B_REG_HHI_MPEG, + .reg = (void *)HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, .lock = &clk_lock, @@ -302,7 +302,7 @@ struct clk_divider meson8b_mpeg_clk_div = { }; struct clk_gate meson8b_clk81 = { - .reg = (void *)MESON8B_REG_HHI_MPEG, + .reg = (void *)HHI_MPEG_CLK_CNTL, .bit_idx = 7, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 5b9cb9f..b2f29f7 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -30,11 +30,10 @@ * * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf */ -#define MESON8B_REG_SYS_CPU_CNTL1 0x015c /* 0x57 offset in data sheet */ -#define MESON8B_REG_HHI_MPEG 0x0174 /* 0x5d offset in data sheet */ -#define MESON8B_REG_MALI 0x01b0 /* 0x6c offset in data sheet */ -#define MESON8B_REG_PLL_FIXED 0x0280 -#define MESON8B_REG_PLL_SYS 0x0300 -#define MESON8B_REG_PLL_VID 0x0320 +#define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ +#define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ +#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ +#define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ +#define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ #endif /* __MESON8B_H */ -- cgit v0.10.2 From 0f32e64b22ab696c50b18afcb428906fbf0308ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20M=C3=BCller?= Date: Sat, 27 Aug 2016 19:40:52 +0200 Subject: clk: meson: Copy meson8b CLKID defines to private header file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only expose future CLKID constants if necessary. This patch removes CLK_NR_CLKS from the DT bindings but leaves all previously defined CLKIDs there to keep backward compatibility. Signed-off-by: Alexander Müller Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1472319654-59048-5-git-send-email-serveralex@gmail.com diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 24395dc..f815d40 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index b2f29f7..86efe6a 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -36,4 +36,111 @@ #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ #define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ +/* + * CLKID index values + * + * These indices are entirely contrived and do not map onto the hardware. + * Migrate them out of this header and into the DT header file when they need + * to be exposed to client nodes in DT: include/dt-bindings/clock/meson8b-clkc.h + */ + +/* CLKID_UNUSED */ +/* CLKID_XTAL */ +/* CLKID_PLL_FIXED */ +/* CLKID_PLL_VID */ +/* CLKID_PLL_SYS */ +/* CLKID_FCLK_DIV2 */ +/* CLKID_FCLK_DIV3 */ +/* CLKID_FCLK_DIV4 */ +/* CLKID_FCLK_DIV5 */ +/* CLKID_FCLK_DIV7 */ +/* CLKID_CLK81 */ +/* CLKID_MALI */ +/* CLKID_CPUCLK */ +/* CLKID_ZERO */ +/* CLKID_MPEG_SEL */ +/* CLKID_MPEG_DIV */ +#define CLKID_DDR 16 +#define CLKID_DOS 17 +#define CLKID_ISA 18 +#define CLKID_PL301 19 +#define CLKID_PERIPHS 20 +#define CLKID_SPICC 21 +#define CLKID_I2C 22 +#define CLKID_SAR_ADC 23 +#define CLKID_SMART_CARD 24 +#define CLKID_RNG0 25 +#define CLKID_UART0 26 +#define CLKID_SDHC 27 +#define CLKID_STREAM 28 +#define CLKID_ASYNC_FIFO 29 +#define CLKID_SDIO 30 +#define CLKID_ABUF 31 +#define CLKID_HIU_IFACE 32 +#define CLKID_ASSIST_MISC 33 +#define CLKID_SPI 34 +#define CLKID_I2S_SPDIF 35 +#define CLKID_ETH 36 +#define CLKID_DEMUX 37 +#define CLKID_AIU_GLUE 38 +#define CLKID_IEC958 39 +#define CLKID_I2S_OUT 40 +#define CLKID_AMCLK 41 +#define CLKID_AIFIFO2 42 +#define CLKID_MIXER 43 +#define CLKID_MIXER_IFACE 44 +#define CLKID_ADC 45 +#define CLKID_BLKMV 46 +#define CLKID_AIU 47 +#define CLKID_UART1 48 +#define CLKID_G2D 49 +#define CLKID_USB0 50 +#define CLKID_USB1 51 +#define CLKID_RESET 52 +#define CLKID_NAND 53 +#define CLKID_DOS_PARSER 54 +#define CLKID_USB 55 +#define CLKID_VDIN1 56 +#define CLKID_AHB_ARB0 57 +#define CLKID_EFUSE 58 +#define CLKID_BOOT_ROM 59 +#define CLKID_AHB_DATA_BUS 60 +#define CLKID_AHB_CTRL_BUS 61 +#define CLKID_HDMI_INTR_SYNC 62 +#define CLKID_HDMI_PCLK 63 +#define CLKID_USB1_DDR_BRIDGE 64 +#define CLKID_USB0_DDR_BRIDGE 65 +#define CLKID_MMC_PCLK 66 +#define CLKID_DVIN 67 +#define CLKID_UART2 68 +#define CLKID_SANA 69 +#define CLKID_VPU_INTR 70 +#define CLKID_SEC_AHB_AHB3_BRIDGE 71 +#define CLKID_CLK81_A9 72 +#define CLKID_VCLK2_VENCI0 73 +#define CLKID_VCLK2_VENCI1 74 +#define CLKID_VCLK2_VENCP0 75 +#define CLKID_VCLK2_VENCP1 76 +#define CLKID_GCLK_VENCI_INT 77 +#define CLKID_GCLK_VENCP_INT 78 +#define CLKID_DAC_CLK 79 +#define CLKID_AOCLK_GATE 80 +#define CLKID_IEC958_GATE 81 +#define CLKID_ENC480P 82 +#define CLKID_RNG1 83 +#define CLKID_GCLK_VENCL_INT 84 +#define CLKID_VCLK2_VENCLMCC 85 +#define CLKID_VCLK2_VENCL 86 +#define CLKID_VCLK2_OTHER 87 +#define CLKID_EDP 88 +#define CLKID_AO_MEDIA_CPU 89 +#define CLKID_AO_AHB_SRAM 90 +#define CLKID_AO_AHB_BUS 91 +#define CLKID_AO_IFACE 92 + +#define CLK_NR_CLKS 93 + +/* include the CLKIDs that have been made part of the stable DT binding */ +#include + #endif /* __MESON8B_H */ diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h index 595a58d..a55ff8c 100644 --- a/include/dt-bindings/clock/meson8b-clkc.h +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -22,6 +22,4 @@ #define CLKID_MPEG_SEL 14 #define CLKID_MPEG_DIV 15 -#define CLK_NR_CLKS (CLKID_MPEG_DIV + 1) - #endif /* __MESON8B_CLKC_H */ -- cgit v0.10.2 From 7ba64d82b35890afa40e7cd6837e657b6185b389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20M=C3=BCller?= Date: Sat, 27 Aug 2016 19:40:53 +0200 Subject: gxbb: clk: Adjust MESON_GATE macro to be shared with meson8b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macro used gxbb_ prefix for clock definitions. In order to share the macro between gxbb and meson8b, the prefix must be moved to gxbb.c. Signed-off-by: Alexander Müller Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1472319654-59048-6-git-send-email-serveralex@gmail.com diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 53326c3..9bb70e7 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -98,7 +98,7 @@ struct meson_clk_mpll { }; #define MESON_GATE(_name, _reg, _bit) \ -struct clk_gate gxbb_##_name = { \ +struct clk_gate _name = { \ .reg = (void __iomem *) _reg, \ .bit_idx = (_bit), \ .lock = &clk_lock, \ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 8e36d22..b3bd813 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -565,93 +565,93 @@ static struct clk_gate gxbb_clk81 = { }; /* Everything Else (EE) domain gates */ -static MESON_GATE(ddr, HHI_GCLK_MPEG0, 0); -static MESON_GATE(dos, HHI_GCLK_MPEG0, 1); -static MESON_GATE(isa, HHI_GCLK_MPEG0, 5); -static MESON_GATE(pl301, HHI_GCLK_MPEG0, 6); -static MESON_GATE(periphs, HHI_GCLK_MPEG0, 7); -static MESON_GATE(spicc, HHI_GCLK_MPEG0, 8); -static MESON_GATE(i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(sar_adc, HHI_GCLK_MPEG0, 10); -static MESON_GATE(smart_card, HHI_GCLK_MPEG0, 11); -static MESON_GATE(rng0, HHI_GCLK_MPEG0, 12); -static MESON_GATE(uart0, HHI_GCLK_MPEG0, 13); -static MESON_GATE(sdhc, HHI_GCLK_MPEG0, 14); -static MESON_GATE(stream, HHI_GCLK_MPEG0, 15); -static MESON_GATE(async_fifo, HHI_GCLK_MPEG0, 16); -static MESON_GATE(sdio, HHI_GCLK_MPEG0, 17); -static MESON_GATE(abuf, HHI_GCLK_MPEG0, 18); -static MESON_GATE(hiu_iface, HHI_GCLK_MPEG0, 19); -static MESON_GATE(assist_misc, HHI_GCLK_MPEG0, 23); -static MESON_GATE(emmc_a, HHI_GCLK_MPEG0, 24); -static MESON_GATE(emmc_b, HHI_GCLK_MPEG0, 25); -static MESON_GATE(emmc_c, HHI_GCLK_MPEG0, 26); -static MESON_GATE(spi, HHI_GCLK_MPEG0, 30); - -static MESON_GATE(i2s_spdif, HHI_GCLK_MPEG1, 2); -static MESON_GATE(eth, HHI_GCLK_MPEG1, 3); -static MESON_GATE(demux, HHI_GCLK_MPEG1, 4); -static MESON_GATE(aiu_glue, HHI_GCLK_MPEG1, 6); -static MESON_GATE(iec958, HHI_GCLK_MPEG1, 7); -static MESON_GATE(i2s_out, HHI_GCLK_MPEG1, 8); -static MESON_GATE(amclk, HHI_GCLK_MPEG1, 9); -static MESON_GATE(aififo2, HHI_GCLK_MPEG1, 10); -static MESON_GATE(mixer, HHI_GCLK_MPEG1, 11); -static MESON_GATE(mixer_iface, HHI_GCLK_MPEG1, 12); -static MESON_GATE(adc, HHI_GCLK_MPEG1, 13); -static MESON_GATE(blkmv, HHI_GCLK_MPEG1, 14); -static MESON_GATE(aiu, HHI_GCLK_MPEG1, 15); -static MESON_GATE(uart1, HHI_GCLK_MPEG1, 16); -static MESON_GATE(g2d, HHI_GCLK_MPEG1, 20); -static MESON_GATE(usb0, HHI_GCLK_MPEG1, 21); -static MESON_GATE(usb1, HHI_GCLK_MPEG1, 22); -static MESON_GATE(reset, HHI_GCLK_MPEG1, 23); -static MESON_GATE(nand, HHI_GCLK_MPEG1, 24); -static MESON_GATE(dos_parser, HHI_GCLK_MPEG1, 25); -static MESON_GATE(usb, HHI_GCLK_MPEG1, 26); -static MESON_GATE(vdin1, HHI_GCLK_MPEG1, 28); -static MESON_GATE(ahb_arb0, HHI_GCLK_MPEG1, 29); -static MESON_GATE(efuse, HHI_GCLK_MPEG1, 30); -static MESON_GATE(boot_rom, HHI_GCLK_MPEG1, 31); - -static MESON_GATE(ahb_data_bus, HHI_GCLK_MPEG2, 1); -static MESON_GATE(ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static MESON_GATE(hdmi_intr_sync, HHI_GCLK_MPEG2, 3); -static MESON_GATE(hdmi_pclk, HHI_GCLK_MPEG2, 4); -static MESON_GATE(usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); -static MESON_GATE(usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); -static MESON_GATE(mmc_pclk, HHI_GCLK_MPEG2, 11); -static MESON_GATE(dvin, HHI_GCLK_MPEG2, 12); -static MESON_GATE(uart2, HHI_GCLK_MPEG2, 15); -static MESON_GATE(sana, HHI_GCLK_MPEG2, 22); -static MESON_GATE(vpu_intr, HHI_GCLK_MPEG2, 25); -static MESON_GATE(sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static MESON_GATE(clk81_a53, HHI_GCLK_MPEG2, 29); - -static MESON_GATE(vclk2_venci0, HHI_GCLK_OTHER, 1); -static MESON_GATE(vclk2_venci1, HHI_GCLK_OTHER, 2); -static MESON_GATE(vclk2_vencp0, HHI_GCLK_OTHER, 3); -static MESON_GATE(vclk2_vencp1, HHI_GCLK_OTHER, 4); -static MESON_GATE(gclk_venci_int0, HHI_GCLK_OTHER, 8); -static MESON_GATE(gclk_vencp_int, HHI_GCLK_OTHER, 9); -static MESON_GATE(dac_clk, HHI_GCLK_OTHER, 10); -static MESON_GATE(aoclk_gate, HHI_GCLK_OTHER, 14); -static MESON_GATE(iec958_gate, HHI_GCLK_OTHER, 16); -static MESON_GATE(enc480p, HHI_GCLK_OTHER, 20); -static MESON_GATE(rng1, HHI_GCLK_OTHER, 21); -static MESON_GATE(gclk_venci_int1, HHI_GCLK_OTHER, 22); -static MESON_GATE(vclk2_venclmcc, HHI_GCLK_OTHER, 24); -static MESON_GATE(vclk2_vencl, HHI_GCLK_OTHER, 25); -static MESON_GATE(vclk_other, HHI_GCLK_OTHER, 26); -static MESON_GATE(edp, HHI_GCLK_OTHER, 31); +static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); +static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); +static MESON_GATE(gxbb_isa, HHI_GCLK_MPEG0, 5); +static MESON_GATE(gxbb_pl301, HHI_GCLK_MPEG0, 6); +static MESON_GATE(gxbb_periphs, HHI_GCLK_MPEG0, 7); +static MESON_GATE(gxbb_spicc, HHI_GCLK_MPEG0, 8); +static MESON_GATE(gxbb_i2c, HHI_GCLK_MPEG0, 9); +static MESON_GATE(gxbb_sar_adc, HHI_GCLK_MPEG0, 10); +static MESON_GATE(gxbb_smart_card, HHI_GCLK_MPEG0, 11); +static MESON_GATE(gxbb_rng0, HHI_GCLK_MPEG0, 12); +static MESON_GATE(gxbb_uart0, HHI_GCLK_MPEG0, 13); +static MESON_GATE(gxbb_sdhc, HHI_GCLK_MPEG0, 14); +static MESON_GATE(gxbb_stream, HHI_GCLK_MPEG0, 15); +static MESON_GATE(gxbb_async_fifo, HHI_GCLK_MPEG0, 16); +static MESON_GATE(gxbb_sdio, HHI_GCLK_MPEG0, 17); +static MESON_GATE(gxbb_abuf, HHI_GCLK_MPEG0, 18); +static MESON_GATE(gxbb_hiu_iface, HHI_GCLK_MPEG0, 19); +static MESON_GATE(gxbb_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE(gxbb_emmc_a, HHI_GCLK_MPEG0, 24); +static MESON_GATE(gxbb_emmc_b, HHI_GCLK_MPEG0, 25); +static MESON_GATE(gxbb_emmc_c, HHI_GCLK_MPEG0, 26); +static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30); + +static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2); +static MESON_GATE(gxbb_eth, HHI_GCLK_MPEG1, 3); +static MESON_GATE(gxbb_demux, HHI_GCLK_MPEG1, 4); +static MESON_GATE(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6); +static MESON_GATE(gxbb_iec958, HHI_GCLK_MPEG1, 7); +static MESON_GATE(gxbb_i2s_out, HHI_GCLK_MPEG1, 8); +static MESON_GATE(gxbb_amclk, HHI_GCLK_MPEG1, 9); +static MESON_GATE(gxbb_aififo2, HHI_GCLK_MPEG1, 10); +static MESON_GATE(gxbb_mixer, HHI_GCLK_MPEG1, 11); +static MESON_GATE(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12); +static MESON_GATE(gxbb_adc, HHI_GCLK_MPEG1, 13); +static MESON_GATE(gxbb_blkmv, HHI_GCLK_MPEG1, 14); +static MESON_GATE(gxbb_aiu, HHI_GCLK_MPEG1, 15); +static MESON_GATE(gxbb_uart1, HHI_GCLK_MPEG1, 16); +static MESON_GATE(gxbb_g2d, HHI_GCLK_MPEG1, 20); +static MESON_GATE(gxbb_usb0, HHI_GCLK_MPEG1, 21); +static MESON_GATE(gxbb_usb1, HHI_GCLK_MPEG1, 22); +static MESON_GATE(gxbb_reset, HHI_GCLK_MPEG1, 23); +static MESON_GATE(gxbb_nand, HHI_GCLK_MPEG1, 24); +static MESON_GATE(gxbb_dos_parser, HHI_GCLK_MPEG1, 25); +static MESON_GATE(gxbb_usb, HHI_GCLK_MPEG1, 26); +static MESON_GATE(gxbb_vdin1, HHI_GCLK_MPEG1, 28); +static MESON_GATE(gxbb_ahb_arb0, HHI_GCLK_MPEG1, 29); +static MESON_GATE(gxbb_efuse, HHI_GCLK_MPEG1, 30); +static MESON_GATE(gxbb_boot_rom, HHI_GCLK_MPEG1, 31); + +static MESON_GATE(gxbb_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON_GATE(gxbb_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON_GATE(gxbb_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); +static MESON_GATE(gxbb_hdmi_pclk, HHI_GCLK_MPEG2, 4); +static MESON_GATE(gxbb_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); +static MESON_GATE(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); +static MESON_GATE(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON_GATE(gxbb_dvin, HHI_GCLK_MPEG2, 12); +static MESON_GATE(gxbb_uart2, HHI_GCLK_MPEG2, 15); +static MESON_GATE(gxbb_sana, HHI_GCLK_MPEG2, 22); +static MESON_GATE(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static MESON_GATE(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29); + +static MESON_GATE(gxbb_vclk2_venci0, HHI_GCLK_OTHER, 1); +static MESON_GATE(gxbb_vclk2_venci1, HHI_GCLK_OTHER, 2); +static MESON_GATE(gxbb_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static MESON_GATE(gxbb_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static MESON_GATE(gxbb_gclk_venci_int0, HHI_GCLK_OTHER, 8); +static MESON_GATE(gxbb_gclk_vencp_int, HHI_GCLK_OTHER, 9); +static MESON_GATE(gxbb_dac_clk, HHI_GCLK_OTHER, 10); +static MESON_GATE(gxbb_aoclk_gate, HHI_GCLK_OTHER, 14); +static MESON_GATE(gxbb_iec958_gate, HHI_GCLK_OTHER, 16); +static MESON_GATE(gxbb_enc480p, HHI_GCLK_OTHER, 20); +static MESON_GATE(gxbb_rng1, HHI_GCLK_OTHER, 21); +static MESON_GATE(gxbb_gclk_venci_int1, HHI_GCLK_OTHER, 22); +static MESON_GATE(gxbb_vclk2_venclmcc, HHI_GCLK_OTHER, 24); +static MESON_GATE(gxbb_vclk2_vencl, HHI_GCLK_OTHER, 25); +static MESON_GATE(gxbb_vclk_other, HHI_GCLK_OTHER, 26); +static MESON_GATE(gxbb_edp, HHI_GCLK_OTHER, 31); /* Always On (AO) domain gates */ -static MESON_GATE(ao_media_cpu, HHI_GCLK_AO, 0); -static MESON_GATE(ao_ahb_sram, HHI_GCLK_AO, 1); -static MESON_GATE(ao_ahb_bus, HHI_GCLK_AO, 2); -static MESON_GATE(ao_iface, HHI_GCLK_AO, 3); -static MESON_GATE(ao_i2c, HHI_GCLK_AO, 4); +static MESON_GATE(gxbb_ao_media_cpu, HHI_GCLK_AO, 0); +static MESON_GATE(gxbb_ao_ahb_sram, HHI_GCLK_AO, 1); +static MESON_GATE(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2); +static MESON_GATE(gxbb_ao_iface, HHI_GCLK_AO, 3); +static MESON_GATE(gxbb_ao_i2c, HHI_GCLK_AO, 4); /* Array of all clocks provided by this provider */ -- cgit v0.10.2 From e31a1900c1ff73d669408fc3243afb5c55863139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20M=C3=BCller?= Date: Sat, 27 Aug 2016 19:40:54 +0200 Subject: meson: clk: Add support for clock gates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the meson8b clock gates. Most of them are disabled by Amlogic U-Boot, but need to be enabled for ethernet, USB and many other components. Signed-off-by: Alexander Müller Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1472319654-59048-7-git-send-email-serveralex@gmail.com diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index f815d40..e1d4aa1 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -313,6 +313,92 @@ struct clk_gate meson8b_clk81 = { }, }; +/* Everything Else (EE) domain gates */ + +static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); +static MESON_GATE(meson8b_dos, HHI_GCLK_MPEG0, 1); +static MESON_GATE(meson8b_isa, HHI_GCLK_MPEG0, 5); +static MESON_GATE(meson8b_pl301, HHI_GCLK_MPEG0, 6); +static MESON_GATE(meson8b_periphs, HHI_GCLK_MPEG0, 7); +static MESON_GATE(meson8b_spicc, HHI_GCLK_MPEG0, 8); +static MESON_GATE(meson8b_i2c, HHI_GCLK_MPEG0, 9); +static MESON_GATE(meson8b_sar_adc, HHI_GCLK_MPEG0, 10); +static MESON_GATE(meson8b_smart_card, HHI_GCLK_MPEG0, 11); +static MESON_GATE(meson8b_rng0, HHI_GCLK_MPEG0, 12); +static MESON_GATE(meson8b_uart0, HHI_GCLK_MPEG0, 13); +static MESON_GATE(meson8b_sdhc, HHI_GCLK_MPEG0, 14); +static MESON_GATE(meson8b_stream, HHI_GCLK_MPEG0, 15); +static MESON_GATE(meson8b_async_fifo, HHI_GCLK_MPEG0, 16); +static MESON_GATE(meson8b_sdio, HHI_GCLK_MPEG0, 17); +static MESON_GATE(meson8b_abuf, HHI_GCLK_MPEG0, 18); +static MESON_GATE(meson8b_hiu_iface, HHI_GCLK_MPEG0, 19); +static MESON_GATE(meson8b_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE(meson8b_spi, HHI_GCLK_MPEG0, 30); + +static MESON_GATE(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2); +static MESON_GATE(meson8b_eth, HHI_GCLK_MPEG1, 3); +static MESON_GATE(meson8b_demux, HHI_GCLK_MPEG1, 4); +static MESON_GATE(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6); +static MESON_GATE(meson8b_iec958, HHI_GCLK_MPEG1, 7); +static MESON_GATE(meson8b_i2s_out, HHI_GCLK_MPEG1, 8); +static MESON_GATE(meson8b_amclk, HHI_GCLK_MPEG1, 9); +static MESON_GATE(meson8b_aififo2, HHI_GCLK_MPEG1, 10); +static MESON_GATE(meson8b_mixer, HHI_GCLK_MPEG1, 11); +static MESON_GATE(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12); +static MESON_GATE(meson8b_adc, HHI_GCLK_MPEG1, 13); +static MESON_GATE(meson8b_blkmv, HHI_GCLK_MPEG1, 14); +static MESON_GATE(meson8b_aiu, HHI_GCLK_MPEG1, 15); +static MESON_GATE(meson8b_uart1, HHI_GCLK_MPEG1, 16); +static MESON_GATE(meson8b_g2d, HHI_GCLK_MPEG1, 20); +static MESON_GATE(meson8b_usb0, HHI_GCLK_MPEG1, 21); +static MESON_GATE(meson8b_usb1, HHI_GCLK_MPEG1, 22); +static MESON_GATE(meson8b_reset, HHI_GCLK_MPEG1, 23); +static MESON_GATE(meson8b_nand, HHI_GCLK_MPEG1, 24); +static MESON_GATE(meson8b_dos_parser, HHI_GCLK_MPEG1, 25); +static MESON_GATE(meson8b_usb, HHI_GCLK_MPEG1, 26); +static MESON_GATE(meson8b_vdin1, HHI_GCLK_MPEG1, 28); +static MESON_GATE(meson8b_ahb_arb0, HHI_GCLK_MPEG1, 29); +static MESON_GATE(meson8b_efuse, HHI_GCLK_MPEG1, 30); +static MESON_GATE(meson8b_boot_rom, HHI_GCLK_MPEG1, 31); + +static MESON_GATE(meson8b_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON_GATE(meson8b_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON_GATE(meson8b_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); +static MESON_GATE(meson8b_hdmi_pclk, HHI_GCLK_MPEG2, 4); +static MESON_GATE(meson8b_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); +static MESON_GATE(meson8b_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); +static MESON_GATE(meson8b_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON_GATE(meson8b_dvin, HHI_GCLK_MPEG2, 12); +static MESON_GATE(meson8b_uart2, HHI_GCLK_MPEG2, 15); +static MESON_GATE(meson8b_sana, HHI_GCLK_MPEG2, 22); +static MESON_GATE(meson8b_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(meson8b_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static MESON_GATE(meson8b_clk81_a9, HHI_GCLK_MPEG2, 29); + +static MESON_GATE(meson8b_vclk2_venci0, HHI_GCLK_OTHER, 1); +static MESON_GATE(meson8b_vclk2_venci1, HHI_GCLK_OTHER, 2); +static MESON_GATE(meson8b_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static MESON_GATE(meson8b_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static MESON_GATE(meson8b_gclk_venci_int, HHI_GCLK_OTHER, 8); +static MESON_GATE(meson8b_gclk_vencp_int, HHI_GCLK_OTHER, 9); +static MESON_GATE(meson8b_dac_clk, HHI_GCLK_OTHER, 10); +static MESON_GATE(meson8b_aoclk_gate, HHI_GCLK_OTHER, 14); +static MESON_GATE(meson8b_iec958_gate, HHI_GCLK_OTHER, 16); +static MESON_GATE(meson8b_enc480p, HHI_GCLK_OTHER, 20); +static MESON_GATE(meson8b_rng1, HHI_GCLK_OTHER, 21); +static MESON_GATE(meson8b_gclk_vencl_int, HHI_GCLK_OTHER, 22); +static MESON_GATE(meson8b_vclk2_venclmcc, HHI_GCLK_OTHER, 24); +static MESON_GATE(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25); +static MESON_GATE(meson8b_vclk2_other, HHI_GCLK_OTHER, 26); +static MESON_GATE(meson8b_edp, HHI_GCLK_OTHER, 31); + +/* Always On (AO) domain gates */ + +static MESON_GATE(meson8b_ao_media_cpu, HHI_GCLK_AO, 0); +static MESON_GATE(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1); +static MESON_GATE(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2); +static MESON_GATE(meson8b_ao_iface, HHI_GCLK_AO, 3); + static struct clk_hw_onecell_data meson8b_hw_onecell_data = { .hws = { [CLKID_XTAL] = &meson8b_xtal.hw, @@ -328,6 +414,83 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, }, .num = CLK_NR_CLKS, }; @@ -338,6 +501,87 @@ static struct meson_clk_pll *const meson8b_clk_plls[] = { &meson8b_sys_pll, }; +static struct clk_gate *meson8b_clk_gates[] = { + &meson8b_clk81, + &meson8b_ddr, + &meson8b_dos, + &meson8b_isa, + &meson8b_pl301, + &meson8b_periphs, + &meson8b_spicc, + &meson8b_i2c, + &meson8b_sar_adc, + &meson8b_smart_card, + &meson8b_rng0, + &meson8b_uart0, + &meson8b_sdhc, + &meson8b_stream, + &meson8b_async_fifo, + &meson8b_sdio, + &meson8b_abuf, + &meson8b_hiu_iface, + &meson8b_assist_misc, + &meson8b_spi, + &meson8b_i2s_spdif, + &meson8b_eth, + &meson8b_demux, + &meson8b_aiu_glue, + &meson8b_iec958, + &meson8b_i2s_out, + &meson8b_amclk, + &meson8b_aififo2, + &meson8b_mixer, + &meson8b_mixer_iface, + &meson8b_adc, + &meson8b_blkmv, + &meson8b_aiu, + &meson8b_uart1, + &meson8b_g2d, + &meson8b_usb0, + &meson8b_usb1, + &meson8b_reset, + &meson8b_nand, + &meson8b_dos_parser, + &meson8b_usb, + &meson8b_vdin1, + &meson8b_ahb_arb0, + &meson8b_efuse, + &meson8b_boot_rom, + &meson8b_ahb_data_bus, + &meson8b_ahb_ctrl_bus, + &meson8b_hdmi_intr_sync, + &meson8b_hdmi_pclk, + &meson8b_usb1_ddr_bridge, + &meson8b_usb0_ddr_bridge, + &meson8b_mmc_pclk, + &meson8b_dvin, + &meson8b_uart2, + &meson8b_sana, + &meson8b_vpu_intr, + &meson8b_sec_ahb_ahb3_bridge, + &meson8b_clk81_a9, + &meson8b_vclk2_venci0, + &meson8b_vclk2_venci1, + &meson8b_vclk2_vencp0, + &meson8b_vclk2_vencp1, + &meson8b_gclk_venci_int, + &meson8b_gclk_vencp_int, + &meson8b_dac_clk, + &meson8b_aoclk_gate, + &meson8b_iec958_gate, + &meson8b_enc480p, + &meson8b_rng1, + &meson8b_gclk_vencl_int, + &meson8b_vclk2_venclmcc, + &meson8b_vclk2_vencl, + &meson8b_vclk2_other, + &meson8b_edp, + &meson8b_ao_media_cpu, + &meson8b_ao_ahb_sram, + &meson8b_ao_ahb_bus, + &meson8b_ao_iface, +}; + static int meson8b_clkc_probe(struct platform_device *pdev) { void __iomem *clk_base; @@ -365,6 +609,11 @@ static int meson8b_clkc_probe(struct platform_device *pdev) meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg; meson8b_clk81.reg = clk_base + (u32)meson8b_clk81.reg; + /* Populate base address for gates */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++) + meson8b_clk_gates[i]->reg = clk_base + + (u32)meson8b_clk_gates[i]->reg; + /* * register all clks * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 86efe6a..010e958 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -30,6 +30,11 @@ * * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf */ +#define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */ +#define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in data sheet */ +#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ +#define HHI_GCLK_OTHER 0x150 /* 0x54 offset in data sheet */ +#define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ #define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ #define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ -- cgit v0.10.2 From 19a2a85d7157373b3540e9a0baff97d7cdca0dd5 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 22 Aug 2016 14:49:37 +0200 Subject: clk: meson-gxbb: Export PWM related clocks for DT Add the PWM related clocks in order to be referenced as PWM source clocks. Signed-off-by: Neil Armstrong Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1471870177-10609-1-git-send-email-narmstrong@baylibre.com diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index 217df51..ae461b1 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -170,11 +170,11 @@ */ #define CLKID_SYS_PLL 0 /* CLKID_CPUCLK */ -#define CLKID_HDMI_PLL 2 +/* CLKID_HDMI_PLL */ #define CLKID_FIXED_PLL 3 /* CLKID_FCLK_DIV2 */ -#define CLKID_FCLK_DIV3 5 -#define CLKID_FCLK_DIV4 6 +/* CLKID_FCLK_DIV3 */ +/* CLKID_FCLK_DIV4 */ #define CLKID_FCLK_DIV5 7 #define CLKID_FCLK_DIV7 8 #define CLKID_GP0_PLL 9 diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h index 7d41864..ce4ad63 100644 --- a/include/dt-bindings/clock/gxbb-clkc.h +++ b/include/dt-bindings/clock/gxbb-clkc.h @@ -6,7 +6,10 @@ #define __GXBB_CLKC_H #define CLKID_CPUCLK 1 +#define CLKID_HDMI_PLL 2 #define CLKID_FCLK_DIV2 4 +#define CLKID_FCLK_DIV3 5 +#define CLKID_FCLK_DIV4 6 #define CLKID_CLK81 12 #define CLKID_ETH 36 #define CLKID_SD_EMMC_A 94 -- cgit v0.10.2 From e33075db73ca24f6107594a054680a90c4a8d64f Mon Sep 17 00:00:00 2001 From: Yakir Yang Date: Thu, 1 Sep 2016 20:26:24 -0700 Subject: clk: rockchip: add dclk_vop_frac ids for rk3399 vop Export the dclk_vop_frac out, so we can set the dclk_vop as the child of dclk_vop_frac, and then we can start to take use of the fractional dividers. Signed-off-by: Yakir Yang Signed-off-by: Chris Zhong Signed-off-by: Heiko Stuebner diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h index ce5f3e9..220a60f 100644 --- a/include/dt-bindings/clock/rk3399-cru.h +++ b/include/dt-bindings/clock/rk3399-cru.h @@ -138,6 +138,8 @@ #define DCLK_VOP0_DIV 182 #define DCLK_VOP1_DIV 183 #define DCLK_M0_PERILP 184 +#define DCLK_VOP0_FRAC 185 +#define DCLK_VOP1_FRAC 186 #define FCLK_CM0S 190 -- cgit v0.10.2 From 464b9eeb9709877ad5557d2ade6b56ae146167c7 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 22 Aug 2016 11:36:19 +0800 Subject: clk: rockchip: add rk3399 ddr clock support add ddrc clock setting, so we can do ddr frequency scaling on rk3399 platform in future. Signed-off-by: Lin Huang Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 6f3d0a6..c284c01 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -120,6 +120,10 @@ PNAME(mux_armclkb_p) = { "clk_core_b_lpll_src", "clk_core_b_bpll_src", "clk_core_b_dpll_src", "clk_core_b_gpll_src" }; +PNAME(mux_ddrclk_p) = { "clk_ddrc_lpll_src", + "clk_ddrc_bpll_src", + "clk_ddrc_dpll_src", + "clk_ddrc_gpll_src" }; PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", @@ -1379,6 +1383,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, RK3368_CLKSEL_CON(58), 0, 5, DFLAGS, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* ddrc */ + GATE(0, "clk_ddrc_lpll_src", "lpll", 0, RK3399_CLKGATE_CON(3), + 0, GFLAGS), + GATE(0, "clk_ddrc_bpll_src", "bpll", 0, RK3399_CLKGATE_CON(3), + 1, GFLAGS), + GATE(0, "clk_ddrc_dpll_src", "dpll", 0, RK3399_CLKGATE_CON(3), + 2, GFLAGS), + GATE(0, "clk_ddrc_gpll_src", "gpll", 0, RK3399_CLKGATE_CON(3), + 3, GFLAGS), + COMPOSITE_DDRCLK(SCLK_DDRC, "sclk_ddrc", mux_ddrclk_p, 0, + RK3399_CLKSEL_CON(6), 4, 2, 0, 0, ROCKCHIP_DDRCLK_SIP), }; static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { @@ -1493,6 +1509,9 @@ static const char *const rk3399_cru_critical_clocks[] __initconst = { "gpll_aclk_perilp0_src", "gpll_aclk_perihp_src", "aclk_vio_noc", + + /* ddrc */ + "sclk_ddrc" }; static const char *const rk3399_pmucru_critical_clocks[] __initconst = { -- cgit v0.10.2 From fd75b345bb3d97ee4b2aad1d313e8ffe627ce7e7 Mon Sep 17 00:00:00 2001 From: Shunqian Zheng Date: Thu, 1 Sep 2016 07:06:22 +0800 Subject: clk: rockchip: add 2016M to big cpu clk rate table on rk3399 We would prefer the 2016M as 2.0G than 1992M which seems odd, adding it to big cpu clk rate table then we can set 2016M in dts. Signed-off-by: Shunqian Zheng Reviewed-by: Xing Zheng Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index c284c01..ea32b7e 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -379,6 +379,7 @@ static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = { RK3399_CPUCLKB_RATE(2184000000, 1, 11, 11), RK3399_CPUCLKB_RATE(2088000000, 1, 10, 10), RK3399_CPUCLKB_RATE(2040000000, 1, 10, 10), + RK3399_CPUCLKB_RATE(2016000000, 1, 9, 9), RK3399_CPUCLKB_RATE(1992000000, 1, 9, 9), RK3399_CPUCLKB_RATE(1896000000, 1, 9, 9), RK3399_CPUCLKB_RATE(1800000000, 1, 8, 8), -- cgit v0.10.2 From 29edeccb4445123a0457a308d3ff67ddd0e34f97 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 1 Sep 2016 20:26:23 -0700 Subject: clk: rockchip: drop CLK_SET_RATE_PARENT from rk3399 fractional dividers Currently the fractional divider clock time can't handle the CLK_SET_RATE_PARENT flag. This is because, unlike normal dividers, there is no clk_divider_bestdiv() function to try speeding up the parent to see if it helps things. Eventually someone could try to figure out how to make fractional dividers able to use CLK_SET_RATE_PARENT, but until they do let's not confuse the common clock framework (and anyone using it) by setting the flag. Signed-off-by: Douglas Anderson Signed-off-by: Chris Zhong Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index ea32b7e..59417c5 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -585,7 +585,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 13, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", 0, RK3399_CLKSEL_CON(99), 0, RK3399_CLKGATE_CON(8), 14, GFLAGS, &rk3399_spdif_fracmux), @@ -599,7 +599,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(28), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 3, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", 0, RK3399_CLKSEL_CON(96), 0, RK3399_CLKGATE_CON(8), 4, GFLAGS, &rk3399_i2s0_fracmux), @@ -609,7 +609,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(29), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 6, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", 0, RK3399_CLKSEL_CON(97), 0, RK3399_CLKGATE_CON(8), 7, GFLAGS, &rk3399_i2s1_fracmux), @@ -619,7 +619,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(30), 7, 1, MFLAGS, 0, 7, DFLAGS, RK3399_CLKGATE_CON(8), 9, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", 0, RK3399_CLKSEL_CON(98), 0, RK3399_CLKGATE_CON(8), 10, GFLAGS, &rk3399_i2s2_fracmux), @@ -638,7 +638,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart0_div", "clk_uart0_src", 0, RK3399_CLKSEL_CON(33), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 0, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", 0, RK3399_CLKSEL_CON(100), 0, RK3399_CLKGATE_CON(9), 1, GFLAGS, &rk3399_uart0_fracmux), @@ -648,7 +648,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart1_div", "clk_uart_src", 0, RK3399_CLKSEL_CON(34), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 2, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", 0, RK3399_CLKSEL_CON(101), 0, RK3399_CLKGATE_CON(9), 3, GFLAGS, &rk3399_uart1_fracmux), @@ -656,7 +656,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0, RK3399_CLKSEL_CON(35), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 4, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", 0, RK3399_CLKSEL_CON(102), 0, RK3399_CLKGATE_CON(9), 5, GFLAGS, &rk3399_uart2_fracmux), @@ -664,7 +664,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0, RK3399_CLKSEL_CON(36), 0, 7, DFLAGS, RK3399_CLKGATE_CON(9), 6, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", 0, RK3399_CLKSEL_CON(103), 0, RK3399_CLKGATE_CON(9), 7, GFLAGS, &rk3399_uart3_fracmux), @@ -1168,7 +1168,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 12, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop0_frac", "dclk_vop0_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop0_frac", "dclk_vop0_div", 0, RK3399_CLKSEL_CON(106), 0, &rk3399_dclk_vop0_fracmux), @@ -1198,7 +1198,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 13, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop1_frac", "dclk_vop1_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop1_frac", "dclk_vop1_div", 0, RK3399_CLKSEL_CON(107), 0, &rk3399_dclk_vop1_fracmux), @@ -1312,7 +1312,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { /* testout */ MUX(0, "clk_test_pre", mux_pll_src_cpll_gpll_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(58), 7, 1, MFLAGS), - COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", CLK_SET_RATE_PARENT, + COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", 0, RK3399_CLKSEL_CON(105), 0, RK3399_CLKGATE_CON(13), 9, GFLAGS), @@ -1417,7 +1417,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { RK3399_PMU_CLKSEL_CON(1), 13, 1, MFLAGS, 8, 5, DFLAGS, RK3399_PMU_CLKGATE_CON(0), 8, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", 0, RK3399_PMU_CLKSEL_CON(7), 0, &rk3399_pmuclk_wifi_fracmux), @@ -1445,7 +1445,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { RK3399_PMU_CLKSEL_CON(5), 10, 1, MFLAGS, 0, 7, DFLAGS, RK3399_PMU_CLKGATE_CON(0), 5, GFLAGS), - COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", CLK_SET_RATE_PARENT, + COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", 0, RK3399_PMU_CLKSEL_CON(6), 0, RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS, &rk3399_uart4_pmu_fracmux), -- cgit v0.10.2 From 7b0f9e357ac838f640b10fb3db1ac35d9a5fa8de Mon Sep 17 00:00:00 2001 From: Yakir Yang Date: Thu, 1 Sep 2016 20:26:25 -0700 Subject: clk: rockchip: use the dclk_vop_frac clock ids on rk3399 Export the dclk_vop_frac out, so we can set the dclk_vop as the child of dclk_vop_frac, and then we can start to take use of the fractional dividers. Signed-off-by: Yakir Yang Signed-off-by: Chris Zhong Signed-off-by: Heiko Stuebner diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 59417c5..2c7cba7 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -1168,7 +1168,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 12, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop0_frac", "dclk_vop0_div", 0, + COMPOSITE_FRACMUX_NOGATE(DCLK_VOP0_FRAC, "dclk_vop0_frac", "dclk_vop0_div", 0, RK3399_CLKSEL_CON(106), 0, &rk3399_dclk_vop0_fracmux), @@ -1198,7 +1198,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS, RK3399_CLKGATE_CON(10), 13, GFLAGS), - COMPOSITE_FRACMUX_NOGATE(0, "dclk_vop1_frac", "dclk_vop1_div", 0, + COMPOSITE_FRACMUX_NOGATE(DCLK_VOP1_FRAC, "dclk_vop1_frac", "dclk_vop1_div", 0, RK3399_CLKSEL_CON(107), 0, &rk3399_dclk_vop1_fracmux), -- cgit v0.10.2 From b452dfe92f651601d04d7b122d5b96e74d7ae030 Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Thu, 1 Sep 2016 22:32:25 -0400 Subject: clk: renesas: rz: Select EXTAL vs USB clock Check the MD_CLK pin to determine the current clock mode in order to set the pll clock parent correctly. Signed-off-by: Chris Brandt Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/clk-rz.c b/drivers/clk/renesas/clk-rz.c index f6312c6..5adb934 100644 --- a/drivers/clk/renesas/clk-rz.c +++ b/drivers/clk/renesas/clk-rz.c @@ -25,10 +25,31 @@ struct rz_cpg { #define CPG_FRQCR 0x10 #define CPG_FRQCR2 0x14 +#define PPR0 0xFCFE3200 +#define PIBC0 0xFCFE7000 + +#define MD_CLK(x) ((x >> 2) & 1) /* P0_2 */ + /* ----------------------------------------------------------------------------- * Initialization */ +static u16 __init rz_cpg_read_mode_pins(void) +{ + void __iomem *ppr0, *pibc0; + u16 modes; + + ppr0 = ioremap_nocache(PPR0, 2); + pibc0 = ioremap_nocache(PIBC0, 2); + BUG_ON(!ppr0 || !pibc0); + iowrite16(4, pibc0); /* enable input buffer */ + modes = ioread16(ppr0); + iounmap(ppr0); + iounmap(pibc0); + + return modes; +} + static struct clk * __init rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name) { @@ -37,8 +58,7 @@ rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *na static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 }; if (strcmp(name, "pll") == 0) { - /* FIXME: cpg_mode should be read from GPIO. But no GPIO support yet */ - unsigned cpg_mode = 0; /* hardcoded to EXTAL for now */ + unsigned int cpg_mode = MD_CLK(rz_cpg_read_mode_pins()); const char *parent_name = of_clk_get_parent_name(np, cpg_mode); mult = cpg_mode ? (32 / 4) : 30; -- cgit v0.10.2 From 5086b0d6ce619350050b270ea009025e587eceb4 Mon Sep 17 00:00:00 2001 From: Khiem Nguyen Date: Sat, 3 Sep 2016 06:06:49 +0000 Subject: clk: renesas: r8a7796: Add THS/TSC clock Signed-off-by: Khiem Nguyen Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 891b353..271fc3b 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -116,6 +116,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("sdif0", 314, R8A7796_CLK_SD0), DEF_MOD("rwdt0", 402, R8A7796_CLK_R), DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1), + DEF_MOD("thermal", 522, R8A7796_CLK_CP), DEF_MOD("gpio7", 905, R8A7796_CLK_S3D4), DEF_MOD("gpio6", 906, R8A7796_CLK_S3D4), DEF_MOD("gpio5", 907, R8A7796_CLK_S3D4), -- cgit v0.10.2 From fedc81e79760b9f5c066bb5ad21befbc491b85bf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Aug 2016 11:49:30 +0200 Subject: MAINTAINERS: Add section for Renesas clock drivers Add a section for Renesas clock drivers, as found on Renesas ARM SoCs, and list myself as the maintainer. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Stephen Boyd diff --git a/MAINTAINERS b/MAINTAINERS index 5436d3a..69e3ce4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9892,6 +9892,12 @@ F: drivers/rpmsg/ F: Documentation/rpmsg.txt F: include/linux/rpmsg.h +RENESAS CLOCK DRIVERS +M: Geert Uytterhoeven +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: drivers/clk/renesas/ + RENESAS ETHERNET DRIVERS R: Sergei Shtylyov L: netdev@vger.kernel.org -- cgit v0.10.2 From e69fdcca836f0b81a2260b69429c8622a80ea891 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Jun 2016 12:05:33 -0700 Subject: clk: bcm2835: Mark the VPU clock as critical The VPU clock is also the clock for our AXI bus, so we really can't disable it. This might have happened during boot if, for example, uart1 (aux_uart clock) probed and was then disabled before the other consumers of the VPU clock had probed. Signed-off-by: Eric Anholt Acked-by: Martin Sperl Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 7a79708..d9db03c 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -443,6 +443,8 @@ struct bcm2835_clock_data { /* Number of fractional bits in the divider */ u32 frac_bits; + u32 flags; + bool is_vpu_clock; bool is_mash_clock; }; @@ -1230,7 +1232,7 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, init.parent_names = parents; init.num_parents = data->num_mux_parents; init.name = data->name; - init.flags = CLK_IGNORE_UNUSED; + init.flags = data->flags | CLK_IGNORE_UNUSED; if (data->is_vpu_clock) { init.ops = &bcm2835_vpu_clock_clk_ops; @@ -1649,6 +1651,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_VPUDIV, .int_bits = 12, .frac_bits = 8, + .flags = CLK_IS_CRITICAL, .is_vpu_clock = true), /* clocks with per parent mux */ -- cgit v0.10.2 From eddcbe8398fc7103fccd22aa6df6917caf0123bf Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Jun 2016 12:05:34 -0700 Subject: clk: bcm2835: Mark GPIO clocks enabled at boot as critical These divide off of PLLD_PER and are used for the ethernet and wifi PHYs source PLLs. Neither of them is currently represented by a phy device that would grab the clock for us. This keeps other drivers from killing the networking PHYs when they disable their own clocks and trigger PLLD_PER's refcount going to 0. Signed-off-by: Eric Anholt Acked-by: Martin Sperl Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index d9db03c..400615b 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1239,6 +1239,12 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, } else { init.ops = &bcm2835_clock_clk_ops; init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + /* If the clock wasn't actually enabled at boot, it's not + * critical. + */ + if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE)) + init.flags &= ~CLK_IS_CRITICAL; } clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL); @@ -1708,13 +1714,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .div_reg = CM_GP1DIV, .int_bits = 12, .frac_bits = 12, + .flags = CLK_IS_CRITICAL, .is_mash_clock = true), [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( .name = "gp2", .ctl_reg = CM_GP2CTL, .div_reg = CM_GP2DIV, .int_bits = 12, - .frac_bits = 12), + .frac_bits = 12, + .flags = CLK_IS_CRITICAL), /* HDMI state machine */ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK( -- cgit v0.10.2 From 9e400c5cc5c105e35216ac59a346f20cdd7613be Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Jun 2016 12:05:35 -0700 Subject: clk: bcm2835: Mark the CM SDRAM clock's parent as critical While the SDRAM is being driven by its dedicated PLL most of the time, there is a little loop running in the firmware that periodically turns on the CM SDRAM clock (using its pre-initialized parent) and switches SDRAM to using the CM clock to do PVT recalibration. This avoids system hangs if we choose SDRAM's parent for some other clock, then disable that clock. Signed-off-by: Eric Anholt Acked-by: Martin Sperl Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 400615b..c6420b3 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -1801,6 +1802,25 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_PERIICTL), }; +/* + * Permanently take a reference on the parent of the SDRAM clock. + * + * While the SDRAM is being driven by its dedicated PLL most of the + * time, there is a little loop running in the firmware that + * periodically switches the SDRAM to using our CM clock to do PVT + * recalibration, with the assumption that the previously configured + * SDRAM parent is still enabled and running. + */ +static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) +{ + struct clk *parent = clk_get_parent(sdc); + + if (IS_ERR(parent)) + return PTR_ERR(parent); + + return clk_prepare_enable(parent); +} + static int bcm2835_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1810,6 +1830,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) const struct bcm2835_clk_desc *desc; const size_t asize = ARRAY_SIZE(clk_desc_array); size_t i; + int ret; cprman = devm_kzalloc(dev, sizeof(*cprman) + asize * sizeof(*clks), @@ -1840,6 +1861,10 @@ static int bcm2835_clk_probe(struct platform_device *pdev) clks[i] = desc->clk_register(cprman, desc->data); } + ret = bcm2835_mark_sdc_parent_critical(clks[BCM2835_CLOCK_SDRAM]); + if (ret) + return ret; + return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, &cprman->onecell); } -- cgit v0.10.2 From 67615c588a059b731df9d019edc3c561d8006ec9 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Jun 2016 12:05:36 -0700 Subject: clk: bcm2835: Skip PLLC clocks when deciding on a new clock parent If the firmware had set up a clock to source from PLLC, go along with it. But if we're looking for a new parent, we don't want to switch it to PLLC because the firmware will force PLLC (and thus the AXI bus clock) to different frequencies during over-temp/under-voltage, without notification to Linux. On my system, this moves the Linux-enabled HDMI state machine and DSI1 escape clock over to plld_per from pllc_per. EMMC still ends up on pllc_per, because the firmware had set it up to use that. Signed-off-by: Eric Anholt Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Acked-by: Martin Sperl Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index c6420b3..e8a9646a 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1009,16 +1009,28 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, return 0; } +static bool +bcm2835_clk_is_pllc(struct clk_hw *hw) +{ + if (!hw) + return false; + + return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; +} + static int bcm2835_clock_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct clk_hw *parent, *best_parent = NULL; + bool current_parent_is_pllc; unsigned long rate, best_rate = 0; unsigned long prate, best_prate = 0; size_t i; u32 div; + current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw)); + /* * Select parent clock that results in the closest but lower rate */ @@ -1026,6 +1038,17 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, parent = clk_hw_get_parent_by_index(hw, i); if (!parent) continue; + + /* + * Don't choose a PLLC-derived clock as our parent + * unless it had been manually set that way. PLLC's + * frequency gets adjusted by the firmware due to + * over-temp or under-voltage conditions, without + * prior notification to our clock consumer. + */ + if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) + continue; + prate = clk_hw_get_rate(parent); div = bcm2835_clock_choose_div(hw, req->rate, prate, true); rate = bcm2835_clock_rate_from_divisor(clock, prate, div); -- cgit v0.10.2 From 3b6b717218968b500753f5b6b9eeeebcc4763446 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 25 Aug 2016 15:57:16 +0900 Subject: clk: samsung: Add clock IDs for the CMU_CDREX (DRAM Express Controller) This patch adds missing clock IDs for CMU_CDREX (DRAM Express Controller) which generates clocks for DRAM and NoC (Network on Chip) busses. Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h index 17ab839..6fd21c2 100644 --- a/include/dt-bindings/clock/exynos5420.h +++ b/include/dt-bindings/clock/exynos5420.h @@ -214,6 +214,9 @@ #define CLK_MOUT_SW_ACLK400 651 #define CLK_MOUT_USER_ACLK300_GSCL 652 #define CLK_MOUT_SW_ACLK300_GSCL 653 +#define CLK_MOUT_MCLK_CDREX 654 +#define CLK_MOUT_BPLL 655 +#define CLK_MOUT_MX_MSPLL_CCORE 656 /* divider clocks */ #define CLK_DOUT_PIXEL 768 @@ -239,8 +242,14 @@ #define CLK_DOUT_ACLK300_DISP1 788 #define CLK_DOUT_ACLK300_GSCL 789 #define CLK_DOUT_ACLK400_DISP1 790 +#define CLK_DOUT_PCLK_CDREX 791 +#define CLK_DOUT_SCLK_CDREX 792 +#define CLK_DOUT_ACLK_CDREX1 793 +#define CLK_DOUT_CCLK_DREX0 794 +#define CLK_DOUT_CLK2X_PHY0 795 +#define CLK_DOUT_PCLK_CORE_MEM 796 /* must be greater than maximal clock id */ -#define CLK_NR_CLKS 791 +#define CLK_NR_CLKS 797 #endif /* _DT_BINDINGS_CLOCK_EXYNOS_5420_H */ -- cgit v0.10.2 From 58d6506f327e3d192998ba03632f546da221b8d8 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 22 Aug 2016 11:15:39 +0200 Subject: clk: samsung: exynos5410: Add clock IDs for PDMA and EPLL clocks The PDMA{0,1} and EPLL clock IDs are added separately in this patch so the patch can be merged to the arm-soc tree as dependency. Signed-off-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Reviewed-by: Chanwoo Choi diff --git a/include/dt-bindings/clock/exynos5410.h b/include/dt-bindings/clock/exynos5410.h index 85b467b..6cb4e90 100644 --- a/include/dt-bindings/clock/exynos5410.h +++ b/include/dt-bindings/clock/exynos5410.h @@ -19,6 +19,7 @@ #define CLK_FOUT_MPLL 4 #define CLK_FOUT_BPLL 5 #define CLK_FOUT_KPLL 6 +#define CLK_FOUT_EPLL 7 /* gate for special clocks (sclk) */ #define CLK_SCLK_UART0 128 @@ -55,6 +56,8 @@ #define CLK_MMC0 351 #define CLK_MMC1 352 #define CLK_MMC2 353 +#define CLK_PDMA0 362 +#define CLK_PDMA1 363 #define CLK_USBH20 365 #define CLK_USBD300 366 #define CLK_USBD301 367 -- cgit v0.10.2 From 490583f0b6604a50073c3ba73fce596dc30d3282 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 18 Aug 2016 21:47:19 +0900 Subject: MAINTAINERS: Add myself as Samsung SoC clock drivers co-maintainer Add myself to the SAMSUNG SOC CLOCK DRIVERS entry, I'm going to review and test related patches as supporter. I can access all the datasheet of Exynos SoC series and can do tests on Exynos based boards. I have implemented the exynos4415/5433 clock drivers and co-authored the exynos3250 clock driver. While at it, add missing paths of the exynos clock driver files. Cc: Tomasz Figa Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki diff --git a/MAINTAINERS b/MAINTAINERS index 20bb1d0..442d6f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10233,9 +10233,12 @@ F: drivers/nfc/s3fwrn5 SAMSUNG SOC CLOCK DRIVERS M: Sylwester Nawrocki M: Tomasz Figa +M: Chanwoo Choi S: Supported L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) F: drivers/clk/samsung/ +F: include/dt-bindings/clock/exynos*.h +F: Documentation/devicetree/bindings/clock/exynos*.txt SAMSUNG SXGBE DRIVERS M: Byungho An -- cgit v0.10.2 From 7a23fa0c6a9f5abf132d015cabc9d48a6eba3957 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 22 Aug 2016 11:49:44 +0900 Subject: clk: samsung: exynos5260: Move struct samsung_cmu_info to init section This patch moves the samsung_cmu_info struct instances to initconst section, this decreases the kernel image size by 784 bytes, which makes zImage smaller by 480 bytes. The patch increases .init.rodata section size by 780 bytes but decreases .init.text section size by 1564 bytes. Size of the drivers/clk/samsung/clk-exynos5260.o object file is 29100 bytes without the patch and 28316 after applying the patch. The section size differences are as below: 15c15 < 3 .init.text 000006b8 00000000 00000000 00000034 2**2 --- > 3 .init.text 0000009c 00000000 00000000 00000034 2**2 25c25 < 8 .init.rodata 00003f6c 00000000 00000000 00002f20 2**2 --- > 8 .init.rodata 00004278 00000000 00000000 00002904 2**2 Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki 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", -- cgit v0.10.2 From ba9d05d9728e229eaebc68c42215ed391f473263 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 22 Aug 2016 11:49:45 +0900 Subject: clk: samsung: exynos5410: Use samsung_cmu_register_one() to simplify code This patch uses the samsung_cmu_register_one() to simplify code and move the pll/mux/div/gate data to initconst section. Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index 54ec486..5488a44 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -230,29 +230,22 @@ 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); - - 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)); - - samsung_clk_of_add_provider(np, ctx); + samsung_cmu_register_one(np, &cmu); pr_debug("Exynos5410: clock setup completed.\n"); } -- cgit v0.10.2 From e867e8fa825dd4fae2514883d77f5954d8d90991 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 25 Aug 2016 15:57:17 +0900 Subject: clk: samsung: exynos5420: Add clocks for CMU_CDREX domain This patch adds the mux/divider clocks for CMU_CDREX (DRAM Express Controller) which generates the clocks for DRAM and NoC (Network on Chip) bus. There is differnet source of MUX_MX_MSPLL_CCORE between exynos5420 and exynos5422, so each MUX_MX_MSPLL_CCORE uses the different parent source group. Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki 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), -- cgit v0.10.2 From 0299042dca9689cdccfaaf00c5f64425c3ac360f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 22 Aug 2016 11:14:49 +0200 Subject: clk: samsung: exynos5410: Expose the peripheral DMA gate clocks These clocks are needed in order to use the PL330 peripheral DMA controllers. Signed-off-by: Sylwester Nawrocki diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index 5488a44..eefed92 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -176,6 +176,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), -- cgit v0.10.2 From 1d9aa64c37f55d2c242f27a5788bf16a4f1578e4 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Aug 2016 17:01:20 +0200 Subject: clk: samsung: Use common registration function for pll2550x There is no such significant differences in pll2550x PLL type to justify a separate registration function. This patch adapts exynos5440 driver to use the common function and removes samsung_clk_register_pll2550x(). Signed-off-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Reviewed-by: Chanwoo Choi 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..b5ab055 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 */ @@ -1263,6 +1218,9 @@ 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; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 213de9a..df4ad8a 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -31,6 +31,7 @@ enum samsung_pll_type { pll_s3c2410_mpll, pll_s3c2410_upll, pll_s3c2440_mpll, + pll_2550x, pll_2550xx, pll_2650xx, pll_1450x, diff --git a/include/dt-bindings/clock/exynos5440.h b/include/dt-bindings/clock/exynos5440.h index c66fc40..842cdc0 100644 --- a/include/dt-bindings/clock/exynos5440.h +++ b/include/dt-bindings/clock/exynos5440.h @@ -14,6 +14,8 @@ #define CLK_XTAL 1 #define CLK_ARM_CLK 2 +#define CLK_CPLLA 3 +#define CLK_CPLLB 4 #define CLK_SPI_BAUD 16 #define CLK_PB0_250 17 #define CLK_PR0_250 18 -- cgit v0.10.2 From 7c3ca061d4cfb25537d90a9ad936667b909133a0 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 2 Sep 2016 18:23:47 +0200 Subject: clk: samsung: clk-exynos-audss: controller variant handling rework Then variant handling is reworked to make the code simpler when more variants are added. Signed-off-by: Sylwester Nawrocki diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index bdf8b97..7d4026b 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -14,18 +14,13 @@ #include #include #include +#include #include #include #include #include -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; @@ -73,14 +68,34 @@ 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 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 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,exynos5420-audss-clock", + .data = &exynos5420_drvdata, + }, + { }, }; static void exynos_audss_clk_teardown(void) @@ -106,19 +121,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 +139,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 +149,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,7 +158,7 @@ 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); @@ -210,7 +220,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); -- cgit v0.10.2 From 2ec865b79b3852de6c663073c7a004e1fb918c3b Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 2 Sep 2016 18:47:45 +0200 Subject: clk: samsung: clk-exynos-audss: Add exynos5410 compatible Exynos5410 Audio Subsystem Clock Controller, comparing to the already supported IP block revisions, has additionally an I2S_MST divider so a new compatible string is added. It is not clear from the Exynos5410 User's Manual released on 2012.03.09 where in the clock tree the I2S_MST clock divider can be found exactly so this clock is left unimplemented for now. Signed-off-by: Sylwester Nawrocki diff --git a/Documentation/devicetree/bindings/clock/clk-exynos-audss.txt b/Documentation/devicetree/bindings/clock/clk-exynos-audss.txt index 180e883..0c3d601 100644 --- a/Documentation/devicetree/bindings/clock/clk-exynos-audss.txt +++ b/Documentation/devicetree/bindings/clock/clk-exynos-audss.txt @@ -10,6 +10,8 @@ Required Properties: - "samsung,exynos4210-audss-clock" - controller compatible with all Exynos4 SoCs. - "samsung,exynos5250-audss-clock" - controller compatible with Exynos5250 SoCs. + - "samsung,exynos5410-audss-clock" - controller compatible with Exynos5410 + SoCs. - "samsung,exynos5420-audss-clock" - controller compatible with Exynos5420 SoCs. - reg: physical base address and length of the controller's register set. @@ -91,5 +93,5 @@ i2s0: i2s@03830000 { <&clock_audss EXYNOS_MOUT_AUDSS>, <&clock_audss EXYNOS_MOUT_I2S>; clock-names = "iis", "i2s_opclk0", "i2s_opclk1", - "mout_audss", "mout_i2s"; + "mout_audss", "mout_i2s"; }; diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 7d4026b..628f86b 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -70,6 +70,7 @@ static struct syscore_ops exynos_audss_clk_syscore_ops = { 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; }; @@ -78,6 +79,11 @@ 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, @@ -92,6 +98,9 @@ static const struct of_device_id exynos_audss_clk_of_match[] = { .compatible = "samsung,exynos5250-audss-clock", .data = &exynos4210_drvdata, }, { + .compatible = "samsung,exynos5410-audss-clock", + .data = &exynos5410_drvdata, + }, { .compatible = "samsung,exynos5420-audss-clock", .data = &exynos5420_drvdata, }, -- cgit v0.10.2 From c17a6163647a20d22fa03c00ba8714492b0311c6 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 2 Sep 2016 18:47:54 +0200 Subject: clk: samsung: clk-exynos-audss: Whitespace and debug trace cleanup There is no need to log probe() completion in normal conditions so the "setup completed" log is removed. Signed-off-by: Sylwester Nawrocki diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 628f86b..51d152f 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -39,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) @@ -173,7 +173,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) 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; } } @@ -253,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: -- cgit v0.10.2 From be95d2c7d918b2b7b973378a1e92bdc6559c21f9 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 9 Sep 2016 10:09:05 +0200 Subject: clk: samsung: Add support for EPLL on exynos5410 This patch adds code instantiating the EPLL, which is used as the audio subsystem's root clock. The requirement to specify the external root clock in clocks property is documented. Having the consumer 'clocks' property ensures proper initialization order by explicitly specifying dependencies in DT. It prevents situations when the SoC's clock controller driver has initialized, the external oscillator clock is not yet registered and setting clock frequencies through assigned-clock-rates property doesn't work properly due to unknown external oscillator frequency. Signed-off-by: Sylwester Nawrocki Reviewed-by: Chanwoo Choi diff --git a/Documentation/devicetree/bindings/clock/exynos5410-clock.txt b/Documentation/devicetree/bindings/clock/exynos5410-clock.txt index aeab635..4527de3 100644 --- a/Documentation/devicetree/bindings/clock/exynos5410-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5410-clock.txt @@ -12,24 +12,29 @@ Required Properties: - #clock-cells: should be 1. +- clocks: should contain an entry specifying the root clock from external + oscillator supplied through XXTI or XusbXTI pin. This clock should be + defined using standard clock bindings with "fin_pll" clock-output-name. + That clock is being passed internally to the 9 PLLs. + All available clocks are defined as preprocessor macros in dt-bindings/clock/exynos5410.h header and can be used in device tree sources. -External clock: - -There is clock that is generated outside the SoC. It -is expected that it is defined using standard clock bindings -with following clock-output-name: - - - "fin_pll" - PLL input clock from XXTI - Example 1: An example of a clock controller node is listed below. + fin_pll: xxti { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "fin_pll"; + #clock-cells = <0>; + }; + clock: clock-controller@0x10010000 { compatible = "samsung,exynos5410-clock"; reg = <0x10010000 0x30000>; #clock-cells = <1>; + clocks = <&fin_pll>; }; Example 2: UART controller node that consumes the clock generated by the clock diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index eefed92..fc471a4 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -14,6 +14,7 @@ #include #include #include +#include #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), @@ -219,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, @@ -247,6 +268,11 @@ static const struct samsung_cmu_info cmu __initconst = { /* register exynos5410 clocks */ static void __init exynos5410_clk_init(struct device_node *np) { + struct clk *xxti = of_clk_get(np, 0); + + if (!IS_ERR(xxti) && clk_get_rate(xxti) == 24 * MHZ) + exynos5410_plls[epll].rate_table = exynos5410_pll2550x_24mhz_tbl; + samsung_cmu_register_one(np, &cmu); pr_debug("Exynos5410: clock setup completed.\n"); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index b5ab055..9617825 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1018,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 */ @@ -1227,6 +1323,12 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, 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 df4ad8a..a1ca023 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -33,6 +33,7 @@ enum samsung_pll_type { pll_s3c2440_mpll, pll_2550x, pll_2550xx, + pll_2650x, pll_2650xx, pll_1450x, pll_1451x, -- cgit v0.10.2 From 7348b6ce94019548f64d54c6934d5ace3f2b50a9 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 9 Sep 2016 15:25:06 +0200 Subject: clk: rk808: Pass the right pointer as the get_hw context Right now we are passing a pointer to a pointer to the structure that will be used to fetch the clk hw, which gets casted later to a pointer to the structure, thus getting garbage in the hw structs. Signed-off-by: Tomeu Vizoso Fixes: a8b6e85db6a6 ("clk: rk808: Migrate to clk_hw based OF and registration APIs") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c index faa447e..6461f28 100644 --- a/drivers/clk/clk-rk808.c +++ b/drivers/clk/clk-rk808.c @@ -138,7 +138,7 @@ static int rk808_clkout_probe(struct platform_device *pdev) if (ret) return ret; - return of_clk_add_hw_provider(node, of_clk_rk808_get, &rk808_clkout); + return of_clk_add_hw_provider(node, of_clk_rk808_get, rk808_clkout); } static int rk808_clkout_remove(struct platform_device *pdev) -- cgit v0.10.2 From 6f91c601771c8ff158d4cea122ec0e5baf9c3756 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 30 Aug 2016 10:38:41 +0200 Subject: clk: sunxi-ng: div: Add mux table macros Add some macros to ease the declaration of clocks that are using them. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index 5d98549..a5c9eaf 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -77,13 +77,16 @@ struct ccu_div { _shift, _width, _table, 0, \ _flags) -#define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ - _mshift, _mwidth, _muxshift, _muxwidth, \ - _gate, _flags) \ +#define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ + _parents, _table, \ + _reg, \ + _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ struct ccu_div _struct = { \ .enable = _gate, \ .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ - .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ .common = { \ .reg = _reg, \ .hw.init = CLK_HW_INIT_PARENTS(_name, \ @@ -93,12 +96,23 @@ struct ccu_div { }, \ } +#define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, _muxshift, _muxwidth, \ + _gate, _flags) \ + SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ + _parents, NULL, \ + _reg, _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) + #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \ _mshift, _mwidth, _muxshift, _muxwidth, \ _flags) \ - SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ - _mshift, _mwidth, _muxshift, _muxwidth, \ - 0, _flags) + SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ + _parents, NULL, \ + _reg, _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + 0, _flags) #define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ -- cgit v0.10.2 From e9c959a6d17cd4fddc766bc182dd98478101c00c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Sep 2016 11:29:13 +0200 Subject: clk: sunxi-ng: div: Add kerneldoc for the _ccu_div structure The internal _ccu_div structure is meant to be embedded into other structures to combine the various dividers and to form the clock classes support. Start to document those structures by using kerneldoc. Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index a5c9eaf..e1b1326 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -19,6 +19,20 @@ #include "ccu_common.h" #include "ccu_mux.h" +/** + * struct _ccu_div - Internal divider description + * @shift: Bit offset of the divider in its register + * @width: Width of the divider field in its register + * @flags: clk_divider flags to apply on this divider + * @table: Divider table pointer (if applicable) + * + * That structure represents a single divider, and is meant to be + * embedded in other structures representing the various clock + * classes. + * + * It is basically a wrapper around the clk_divider functions + * arguments. + */ struct _ccu_div { u8 shift; u8 width; -- cgit v0.10.2 From 87ba9e5962f3f6e9a9a44cc332d1ad222d1c0302 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 6 Sep 2016 12:29:04 +0200 Subject: clk: sunxi-ng: div: Allow to set a maximum Some dividers might have a maximum value that is lower than the width of the register. Add a field to _ccu_div to handle those case properly. If the field is set to 0, the code will assume that the maximum value is the maximum one that can be used with the field register width. Otherwise, we'll use whatever value has been set. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index e1b1326..34c3388 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -23,6 +23,9 @@ * struct _ccu_div - Internal divider description * @shift: Bit offset of the divider in its register * @width: Width of the divider field in its register + * @max: Maximum value allowed for that divider. This is the + * arithmetic value, not the maximum value to be set in the + * register. * @flags: clk_divider flags to apply on this divider * @table: Divider table pointer (if applicable) * @@ -37,6 +40,8 @@ struct _ccu_div { u8 shift; u8 width; + u32 max; + u32 flags; struct clk_div_table *table; @@ -50,14 +55,25 @@ struct _ccu_div { .table = _table, \ } -#define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \ - _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, NULL, _flags) - #define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \ _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0) +#define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \ + { \ + .shift = _shift, \ + .width = _width, \ + .flags = _flags, \ + .max = _max, \ + } + +#define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \ + _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, 0, _flags) + +#define _SUNXI_CCU_DIV_MAX(_shift, _width, _max) \ + _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, 0) + #define _SUNXI_CCU_DIV(_shift, _width) \ - _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, NULL, 0) + _SUNXI_CCU_DIV_FLAGS(_shift, _width, 0) struct ccu_div { u32 enable; diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c index cbf33ef..ebb1b31 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.c +++ b/drivers/clk/sunxi-ng/ccu_mp.c @@ -21,9 +21,9 @@ static void ccu_mp_find_best(unsigned long parent, unsigned long rate, unsigned int best_m = 0, best_p = 0; unsigned int _m, _p; - for (_p = 0; _p <= max_p; _p++) { + for (_p = 1; _p <= max_p; _p <<= 1) { for (_m = 1; _m <= max_m; _m++) { - unsigned long tmp_rate = (parent >> _p) / _m; + unsigned long tmp_rate = parent / _p / _m; if (tmp_rate > rate) continue; @@ -46,13 +46,15 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux, void *data) { struct ccu_mp *cmp = data; + unsigned int max_m, max_p; unsigned int m, p; - ccu_mp_find_best(parent_rate, rate, - 1 << cmp->m.width, (1 << cmp->p.width) - 1, - &m, &p); + max_m = cmp->m.max ?: 1 << cmp->m.width; + max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); - return (parent_rate >> p) / m; + ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p); + + return parent_rate / p / m; } static void ccu_mp_disable(struct clk_hw *hw) @@ -108,13 +110,14 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate, { struct ccu_mp *cmp = hw_to_ccu_mp(hw); unsigned long flags; + unsigned int max_m, max_p; unsigned int m, p; u32 reg; - ccu_mp_find_best(parent_rate, rate, - 1 << cmp->m.width, (1 << cmp->p.width) - 1, - &m, &p); + max_m = cmp->m.max ?: 1 << cmp->m.width; + max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); + ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p); spin_lock_irqsave(cmp->common.lock, flags); @@ -122,7 +125,7 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate, reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift); reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift); - writel(reg | (p << cmp->p.shift) | ((m - 1) << cmp->m.shift), + writel(reg | (ilog2(p) << cmp->p.shift) | ((m - 1) << cmp->m.shift), cmp->common.base + cmp->common.reg); spin_unlock_irqrestore(cmp->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index 1824529..059fdc3 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -103,7 +103,7 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux, _nkm.max_n = 1 << nkm->n.width; _nkm.max_k = 1 << nkm->k.width; - _nkm.max_m = 1 << nkm->m.width; + _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; ccu_nkm_find_best(parent_rate, rate, &_nkm); @@ -129,7 +129,7 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate, _nkm.max_n = 1 << nkm->n.width; _nkm.max_k = 1 << nkm->k.width; - _nkm.max_m = 1 << nkm->m.width; + _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; ccu_nkm_find_best(parent_rate, rate, &_nkm); diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index 9f2b98e..9769dee 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -29,14 +29,14 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate, unsigned long _n, _k, _m, _p; for (_k = 1; _k <= nkmp->max_k; _k++) { - for (_p = 0; _p <= nkmp->max_p; _p++) { + for (_p = 1; _p <= nkmp->max_p; _p <<= 1) { unsigned long tmp_rate; - rational_best_approximation(rate / _k, parent >> _p, + rational_best_approximation(rate / _k, parent / _p, nkmp->max_n, nkmp->max_m, &_n, &_m); - tmp_rate = (parent * _n * _k >> _p) / _m; + tmp_rate = parent * _n * _k / (_m * _p); if (tmp_rate > rate) continue; @@ -110,13 +110,12 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, _nkmp.max_n = 1 << nkmp->n.width; _nkmp.max_k = 1 << nkmp->k.width; - _nkmp.max_m = 1 << nkmp->m.width; - _nkmp.max_p = (1 << nkmp->p.width) - 1; + _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; + _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1); - ccu_nkmp_find_best(*parent_rate, rate, - &_nkmp); + ccu_nkmp_find_best(*parent_rate, rate, &_nkmp); - return (*parent_rate * _nkmp.n * _nkmp.k >> _nkmp.p) / _nkmp.m; + return *parent_rate * _nkmp.n * _nkmp.k / (_nkmp.m * _nkmp.p); } static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, @@ -129,8 +128,8 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, _nkmp.max_n = 1 << nkmp->n.width; _nkmp.max_k = 1 << nkmp->k.width; - _nkmp.max_m = 1 << nkmp->m.width; - _nkmp.max_p = (1 << nkmp->p.width) - 1; + _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; + _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1); ccu_nkmp_find_best(parent_rate, rate, &_nkmp); @@ -145,7 +144,7 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, reg |= (_nkmp.n - 1) << nkmp->n.shift; reg |= (_nkmp.k - 1) << nkmp->k.shift; reg |= (_nkmp.m - 1) << nkmp->m.shift; - reg |= _nkmp.p << nkmp->p.shift; + reg |= ilog2(_nkmp.p) << nkmp->p.shift; writel(reg, nkmp->common.base + nkmp->common.reg); diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index e35ddd8..b61bdd8 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -61,11 +61,13 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { struct ccu_nm *nm = hw_to_ccu_nm(hw); + unsigned long max_n, max_m; unsigned long n, m; - rational_best_approximation(rate, *parent_rate, - 1 << nm->n.width, 1 << nm->m.width, - &n, &m); + max_n = 1 << nm->n.width; + max_m = nm->m.max ?: 1 << nm->m.width; + + rational_best_approximation(rate, *parent_rate, max_n, max_m, &n, &m); return *parent_rate * n / m; } @@ -75,6 +77,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, { struct ccu_nm *nm = hw_to_ccu_nm(hw); unsigned long flags; + unsigned long max_n, max_m; unsigned long n, m; u32 reg; @@ -83,9 +86,10 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, else ccu_frac_helper_disable(&nm->common, &nm->frac); - rational_best_approximation(rate, parent_rate, - 1 << nm->n.width, 1 << nm->m.width, - &n, &m); + max_n = 1 << nm->n.width; + max_m = nm->m.max ?: 1 << nm->m.width; + + rational_best_approximation(rate, parent_rate, max_n, max_m, &n, &m); spin_lock_irqsave(nm->common.lock, flags); -- cgit v0.10.2 From 13e91e4583973dff44c5cedc83b318f6518a58f0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 30 Aug 2016 10:38:51 +0200 Subject: clk: sunxi-ng: mux: Add mux table macro Add a new macro to declare muxes based on a table and a gate. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index f5123a1..47aba3a 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -43,9 +43,12 @@ struct ccu_mux { struct ccu_common common; }; -#define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width, _flags) \ +#define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table, \ + _reg, _shift, _width, _gate, \ + _flags) \ struct ccu_mux _struct = { \ - .mux = _SUNXI_CCU_MUX(_shift, _width), \ + .enable = _gate, \ + .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \ .common = { \ .reg = _reg, \ .hw.init = CLK_HW_INIT_PARENTS(_name, \ @@ -57,17 +60,14 @@ struct ccu_mux { #define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \ _shift, _width, _gate, _flags) \ - struct ccu_mux _struct = { \ - .enable = _gate, \ - .mux = _SUNXI_CCU_MUX(_shift, _width), \ - .common = { \ - .reg = _reg, \ - .hw.init = CLK_HW_INIT_PARENTS(_name, \ - _parents, \ - &ccu_mux_ops, \ - _flags), \ - } \ - } + SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL, \ + _reg, _shift, _width, _gate, \ + _flags) + +#define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width, \ + _flags) \ + SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL, \ + _reg, _shift, _width, 0, _flags) static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw) { -- cgit v0.10.2 From aa152335174825fa4b4cd9af0564774b61857898 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 30 Aug 2016 10:38:07 +0200 Subject: clk: sunxi-ng: Add N-class clocks support Add support for the class with a single factor, N, being a multiplier. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index a1dee86..c725877 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -19,6 +19,10 @@ config SUNXI_CCU_GATE config SUNXI_CCU_MUX bool +config SUNXI_CCU_MULT + bool + select SUNXI_CCU_MUX + config SUNXI_CCU_PHASE bool diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 261438b..462a5f8 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SUNXI_CCU_DIV) += ccu_div.o obj-$(CONFIG_SUNXI_CCU_FRAC) += ccu_frac.o obj-$(CONFIG_SUNXI_CCU_GATE) += ccu_gate.o obj-$(CONFIG_SUNXI_CCU_MUX) += ccu_mux.o +obj-$(CONFIG_SUNXI_CCU_MULT) += ccu_mult.o obj-$(CONFIG_SUNXI_CCU_PHASE) += ccu_phase.o # Multi-factor clocks diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c new file mode 100644 index 0000000..010e942 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu_mult.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2016 Maxime Ripard + * Maxime Ripard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include + +#include "ccu_gate.h" +#include "ccu_mult.h" + +static void ccu_mult_find_best(unsigned long parent, unsigned long rate, + unsigned int max_n, unsigned int *n) +{ + *n = rate / parent; +} + +static unsigned long ccu_mult_round_rate(struct ccu_mux_internal *mux, + unsigned long parent_rate, + unsigned long rate, + void *data) +{ + struct ccu_mult *cm = data; + unsigned int n; + + ccu_mult_find_best(parent_rate, rate, 1 << cm->mult.width, &n); + + return parent_rate * n; +} + +static void ccu_mult_disable(struct clk_hw *hw) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + + return ccu_gate_helper_disable(&cm->common, cm->enable); +} + +static int ccu_mult_enable(struct clk_hw *hw) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + + return ccu_gate_helper_enable(&cm->common, cm->enable); +} + +static int ccu_mult_is_enabled(struct clk_hw *hw) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + + return ccu_gate_helper_is_enabled(&cm->common, cm->enable); +} + +static unsigned long ccu_mult_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + unsigned long val; + u32 reg; + + reg = readl(cm->common.base + cm->common.reg); + val = reg >> cm->mult.shift; + val &= (1 << cm->mult.width) - 1; + + ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1, + &parent_rate); + + return parent_rate * (val + 1); +} + +static int ccu_mult_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + + return ccu_mux_helper_determine_rate(&cm->common, &cm->mux, + req, ccu_mult_round_rate, cm); +} + +static int ccu_mult_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + unsigned long flags; + unsigned int n; + u32 reg; + + ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1, + &parent_rate); + + ccu_mult_find_best(parent_rate, rate, 1 << cm->mult.width, &n); + + spin_lock_irqsave(cm->common.lock, flags); + + reg = readl(cm->common.base + cm->common.reg); + reg &= ~GENMASK(cm->mult.width + cm->mult.shift - 1, cm->mult.shift); + + writel(reg | ((n - 1) << cm->mult.shift), + cm->common.base + cm->common.reg); + + spin_unlock_irqrestore(cm->common.lock, flags); + + return 0; +} + +static u8 ccu_mult_get_parent(struct clk_hw *hw) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + + return ccu_mux_helper_get_parent(&cm->common, &cm->mux); +} + +static int ccu_mult_set_parent(struct clk_hw *hw, u8 index) +{ + struct ccu_mult *cm = hw_to_ccu_mult(hw); + + return ccu_mux_helper_set_parent(&cm->common, &cm->mux, index); +} + +const struct clk_ops ccu_mult_ops = { + .disable = ccu_mult_disable, + .enable = ccu_mult_enable, + .is_enabled = ccu_mult_is_enabled, + + .get_parent = ccu_mult_get_parent, + .set_parent = ccu_mult_set_parent, + + .determine_rate = ccu_mult_determine_rate, + .recalc_rate = ccu_mult_recalc_rate, + .set_rate = ccu_mult_set_rate, +}; diff --git a/drivers/clk/sunxi-ng/ccu_mult.h b/drivers/clk/sunxi-ng/ccu_mult.h index 609db66..5d2c8dc 100644 --- a/drivers/clk/sunxi-ng/ccu_mult.h +++ b/drivers/clk/sunxi-ng/ccu_mult.h @@ -1,6 +1,9 @@ #ifndef _CCU_MULT_H_ #define _CCU_MULT_H_ +#include "ccu_common.h" +#include "ccu_mux.h" + struct _ccu_mult { u8 shift; u8 width; @@ -12,4 +15,36 @@ struct _ccu_mult { .width = _width, \ } +struct ccu_mult { + u32 enable; + + struct _ccu_mult mult; + struct ccu_mux_internal mux; + struct ccu_common common; +}; + +#define SUNXI_CCU_N_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \ + _mshift, _mwidth, _gate, _lock, \ + _flags) \ + struct ccu_mult _struct = { \ + .enable = _gate, \ + .mult = _SUNXI_CCU_MULT(_mshift, _mwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &ccu_mult_ops, \ + _flags), \ + }, \ + } + +static inline struct ccu_mult *hw_to_ccu_mult(struct clk_hw *hw) +{ + struct ccu_common *common = hw_to_ccu_common(hw); + + return container_of(common, struct ccu_mult, common); +} + +extern const struct clk_ops ccu_mult_ops; + #endif /* _CCU_MULT_H_ */ -- cgit v0.10.2 From d05c748bd73015aa4aa10bafc178fc2be46a02cb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 24 Aug 2016 14:10:15 +0200 Subject: clk: sunxi-ng: Add A33 CCU support This commit introduces the clocks found in the Allwinner A33 CCU. Since this SoC is very similar to the A23, and we share a significant share of the DTSI, the clock IDs that are going to be used will also be shared with the A23, hence the name of the various header files. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt index eac4587..8fd765e 100644 --- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt +++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt @@ -4,6 +4,7 @@ Allwinner Clock Control Unit Binding Required properties : - compatible: must contain one of the following compatibles: - "allwinner,sun6i-a31-ccu" + - "allwinner,sun8i-a33-ccu" - "allwinner,sun8i-h3-ccu" - reg: Must contain the registers base address and length diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index c725877..dff3fef 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -65,6 +65,18 @@ config SUN6I_A31_CCU select SUNXI_CCU_PHASE default MACH_SUN6I +config SUN8I_A33_CCU + bool "Support for the Allwinner A33 CCU" + select SUNXI_CCU_DIV + select SUNXI_CCU_MULT + select SUNXI_CCU_NK + select SUNXI_CCU_NKM + select SUNXI_CCU_NKMP + select SUNXI_CCU_NM + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN8I + config SUN8I_H3_CCU bool "Support for the Allwinner H3 CCU" select SUNXI_CCU_DIV diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 462a5f8..4f7e99f 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -19,4 +19,5 @@ obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o # SoC support obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o +obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23-a33.h b/drivers/clk/sunxi-ng/ccu-sun8i-a23-a33.h new file mode 100644 index 0000000..62c0f8d --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23-a33.h @@ -0,0 +1,63 @@ +/* + * Copyright 2016 Maxime Ripard + * + * Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CCU_SUN8I_A23_A33_H_ +#define _CCU_SUN8I_A23_A33_H_ + +#include +#include + +#define CLK_PLL_CPUX 0 +#define CLK_PLL_AUDIO_BASE 1 +#define CLK_PLL_AUDIO 2 +#define CLK_PLL_AUDIO_2X 3 +#define CLK_PLL_AUDIO_4X 4 +#define CLK_PLL_AUDIO_8X 5 +#define CLK_PLL_VIDEO 6 +#define CLK_PLL_VIDEO_2X 7 +#define CLK_PLL_VE 8 +#define CLK_PLL_DDR0 9 +#define CLK_PLL_PERIPH 10 +#define CLK_PLL_PERIPH_2X 11 +#define CLK_PLL_GPU 12 +#define CLK_PLL_MIPI 13 +#define CLK_PLL_HSIC 14 +#define CLK_PLL_DE 15 +#define CLK_PLL_DDR1 16 +#define CLK_PLL_DDR 17 + +/* The CPUX clock is exported */ + +#define CLK_AXI 19 +#define CLK_AHB1 20 +#define CLK_APB1 21 +#define CLK_APB2 22 + +/* All the bus gates are exported */ + +/* The first part of the mod clocks is exported */ + +#define CLK_DRAM 79 + +/* Some more module clocks are exported */ + +#define CLK_MBUS 95 + +/* And the last module clocks are exported */ + +#define CLK_NUMBER (CLK_ATS + 1) + +#endif /* _CCU_SUN8I_A23_A33_H_ */ diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c new file mode 100644 index 0000000..fc00892 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2016 Maxime Ripard. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_phase.h" + +#include "ccu-sun8i-a23-a33.h" + +static struct ccu_nkmp pll_cpux_clk = { + .enable = BIT(31), + .lock = BIT(28), + + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT(4, 2), + .m = _SUNXI_CCU_DIV(0, 2), + .p = _SUNXI_CCU_DIV_MAX(16, 2, 4), + + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", + &ccu_nkmp_ops, + 0), + }, +}; + +/* + * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from + * the base (2x, 4x and 8x), and one variable divider (the one true + * pll audio). + * + * We don't have any need for the variable divider for now, so we just + * hardcode it to match with the clock names + */ +#define SUN8I_A33_PLL_AUDIO_REG 0x008 + +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video", + "osc24M", 0x010, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", + "osc24M", 0x018, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr0_clk, "pll-ddr0", + "osc24M", 0x020, + 8, 5, /* N */ + 4, 2, /* K */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph_clk, "pll-periph", + "osc24M", 0x028, + 8, 5, /* N */ + 4, 2, /* K */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 2, /* post-div */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", + "osc24M", 0x038, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +/* + * The MIPI PLL has 2 modes: "MIPI" and "HDMI". + * + * The MIPI mode is a standard NKM-style clock. The HDMI mode is an + * integer / fractional clock with switchable multipliers and dividers. + * This is not supported here. We hardcode the PLL to MIPI mode. + */ +#define SUN8I_A33_PLL_MIPI_REG 0x040 +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_mipi_clk, "pll-mipi", + "pll-video", 0x040, + 8, 4, /* N */ + 4, 2, /* K */ + 0, 4, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_hsic_clk, "pll-hsic", + "osc24M", 0x044, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de", + "osc24M", 0x048, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +/* TODO: Fix N */ +static SUNXI_CCU_N_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1", + "osc24M", 0x04c, + 8, 6, /* N */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static const char * const cpux_parents[] = { "osc32k", "osc24M", + "pll-cpux" , "pll-cpux" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x050, 16, 2, CLK_IS_CRITICAL); + +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0); + +static const char * const ahb1_parents[] = { "osc32k", "osc24M", + "axi" , "pll-periph" }; +static struct ccu_div ahb1_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 12, + .width = 2, + + .variable_prediv = { + .index = 3, + .shift = 6, + .width = 2, + }, + }, + + .common = { + .reg = 0x054, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ahb1", + ahb1_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct clk_div_table apb1_div_table[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { /* Sentinel */ }, +}; +static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1", + 0x054, 8, 2, apb1_div_table, 0); + +static const char * const apb2_parents[] = { "osc32k", "osc24M", + "pll-periph" , "pll-periph" }; +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb1", + 0x060, BIT(1), 0); +static SUNXI_CCU_GATE(bus_ss_clk, "bus-ss", "ahb1", + 0x060, BIT(5), 0); +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1", + 0x060, BIT(6), 0); +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1", + 0x060, BIT(8), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1", + 0x060, BIT(9), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1", + 0x060, BIT(10), 0); +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1", + 0x060, BIT(14), 0); +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1", + 0x060, BIT(19), 0); +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1", + 0x060, BIT(20), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1", + 0x060, BIT(21), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1", + 0x060, BIT(24), 0); +static SUNXI_CCU_GATE(bus_ehci_clk, "bus-ehci", "ahb1", + 0x060, BIT(26), 0); +static SUNXI_CCU_GATE(bus_ohci_clk, "bus-ohci", "ahb1", + 0x060, BIT(29), 0); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1", + 0x064, BIT(0), 0); +static SUNXI_CCU_GATE(bus_lcd_clk, "bus-lcd", "ahb1", + 0x064, BIT(4), 0); +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1", + 0x064, BIT(8), 0); +static SUNXI_CCU_GATE(bus_de_be_clk, "bus-de-be", "ahb1", + 0x064, BIT(12), 0); +static SUNXI_CCU_GATE(bus_de_fe_clk, "bus-de-fe", "ahb1", + 0x064, BIT(14), 0); +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1", + 0x064, BIT(20), 0); +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1", + 0x064, BIT(21), 0); +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1", + 0x064, BIT(22), 0); +static SUNXI_CCU_GATE(bus_drc_clk, "bus-drc", "ahb1", + 0x064, BIT(25), 0); +static SUNXI_CCU_GATE(bus_sat_clk, "bus-sat", "ahb1", + 0x064, BIT(26), 0); + +static SUNXI_CCU_GATE(bus_codec_clk, "bus-codec", "apb1", + 0x068, BIT(0), 0); +static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1", + 0x068, BIT(5), 0); +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", + 0x068, BIT(12), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", + 0x068, BIT(13), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", + 0x06c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", + 0x06c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", + 0x06c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", + 0x06c, BIT(16), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", + 0x06c, BIT(17), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", + 0x06c, BIT(18), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", + 0x06c, BIT(19), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", + 0x06c, BIT(20), 0); + +static const char * const mod0_default_parents[] = { "osc24M", "pll-periph" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_default_parents, 0x088, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_default_parents, 0x08c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1_sample", "mmc1", + 0x08c, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1_output", "mmc1", + 0x08c, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mod0_default_parents, 0x090, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2_sample", "mmc2", + 0x090, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc2_output_clk, "mmc2_output", "mmc2", + 0x090, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(ss_clk, "ss", mod0_default_parents, 0x09c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents, 0x0a0, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x", + "pll-audio-2x", "pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents, + 0x0b0, 16, 2, BIT(31), 0); + +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents, + 0x0b4, 16, 2, BIT(31), 0); + +/* TODO: the parent for most of the USB clocks is not known */ +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", + 0x0cc, BIT(8), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", + 0x0cc, BIT(9), 0); +static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "pll-hsic", + 0x0cc, BIT(10), 0); +static SUNXI_CCU_GATE(usb_hsic_12M_clk, "usb-hsic-12M", "osc24M", + 0x0cc, BIT(11), 0); +static SUNXI_CCU_GATE(usb_ohci_clk, "usb-ohci", "osc24M", + 0x0cc, BIT(16), 0); + +static SUNXI_CCU_M(dram_clk, "dram", "pll-ddr", + 0x0f4, 0, 4, CLK_IS_CRITICAL); + +static const char * const pll_ddr_parents[] = { "pll-ddr0", "pll-ddr1" }; +static SUNXI_CCU_MUX(pll_ddr_clk, "pll-ddr", pll_ddr_parents, + 0x0f8, 16, 1, 0); + +static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram", + 0x100, BIT(0), 0); +static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram", + 0x100, BIT(1), 0); +static SUNXI_CCU_GATE(dram_drc_clk, "dram-drc", "dram", + 0x100, BIT(16), 0); +static SUNXI_CCU_GATE(dram_de_fe_clk, "dram-de-fe", "dram", + 0x100, BIT(24), 0); +static SUNXI_CCU_GATE(dram_de_be_clk, "dram-de-be", "dram", + 0x100, BIT(26), 0); + +static const char * const de_parents[] = { "pll-video", "pll-periph-2x", + "pll-gpu", "pll-de" }; +static const u8 de_table[] = { 0, 2, 3, 5 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(de_be_clk, "de-be", + de_parents, de_table, + 0x104, 0, 4, 24, 3, BIT(31), 0); + +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(de_fe_clk, "de-fe", + de_parents, de_table, + 0x10c, 0, 4, 24, 3, BIT(31), 0); + +static const char * const lcd_ch0_parents[] = { "pll-video", "pll-video-2x", + "pll-mipi" }; +static const u8 lcd_ch0_table[] = { 0, 2, 4 }; +static SUNXI_CCU_MUX_TABLE_WITH_GATE(lcd_ch0_clk, "lcd-ch0", + lcd_ch0_parents, lcd_ch0_table, + 0x118, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); + +static const char * const lcd_ch1_parents[] = { "pll-video", "pll-video-2x" }; +static const u8 lcd_ch1_table[] = { 0, 2 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(lcd_ch1_clk, "lcd-ch1", + lcd_ch1_parents, lcd_ch1_table, + 0x12c, 0, 4, 24, 2, BIT(31), 0); + +static const char * const csi_sclk_parents[] = { "pll-video", "pll-de", + "pll-mipi", "pll-ve" }; +static const u8 csi_sclk_table[] = { 0, 3, 4, 5 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_sclk_clk, "csi-sclk", + csi_sclk_parents, csi_sclk_table, + 0x134, 16, 4, 24, 3, BIT(31), 0); + +static const char * const csi_mclk_parents[] = { "pll-video", "pll-de", + "osc24M" }; +static const u8 csi_mclk_table[] = { 0, 3, 5 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_mclk_clk, "csi-mclk", + csi_mclk_parents, csi_mclk_table, + 0x134, 0, 5, 8, 3, BIT(15), 0); + +static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", + 0x13c, 16, 3, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", + 0x140, BIT(31), 0); +static SUNXI_CCU_GATE(ac_dig_4x_clk, "ac-dig-4x", "pll-audio-4x", + 0x140, BIT(30), 0); +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", + 0x144, BIT(31), 0); + +static const char * const mbus_parents[] = { "osc24M", "pll-periph-2x", + "pll-ddr0", "pll-ddr1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, + 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL); + +static const char * const dsi_sclk_parents[] = { "pll-video", "pll-video-2x" }; +static const u8 dsi_sclk_table[] = { 0, 2 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_sclk_clk, "dsi-sclk", + dsi_sclk_parents, dsi_sclk_table, + 0x168, 16, 4, 24, 2, BIT(31), 0); + +static const char * const dsi_dphy_parents[] = { "pll-video", "pll-periph" }; +static const u8 dsi_dphy_table[] = { 0, 2 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_dphy_clk, "dsi-dphy", + dsi_dphy_parents, dsi_dphy_table, + 0x168, 0, 4, 8, 2, BIT(15), 0); + +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(drc_clk, "drc", + de_parents, de_table, + 0x180, 0, 4, 24, 3, BIT(31), 0); + +static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", + 0x1a0, 0, 3, BIT(31), 0); + +static const char * const ats_parents[] = { "osc24M", "pll-periph" }; +static SUNXI_CCU_M_WITH_MUX_GATE(ats_clk, "ats", ats_parents, + 0x1b0, 0, 3, 24, 2, BIT(31), 0); + +static struct ccu_common *sun8i_a33_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_audio_base_clk.common, + &pll_video_clk.common, + &pll_ve_clk.common, + &pll_ddr0_clk.common, + &pll_periph_clk.common, + &pll_gpu_clk.common, + &pll_mipi_clk.common, + &pll_hsic_clk.common, + &pll_de_clk.common, + &pll_ddr1_clk.common, + &pll_ddr_clk.common, + &cpux_clk.common, + &axi_clk.common, + &ahb1_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &bus_mipi_dsi_clk.common, + &bus_ss_clk.common, + &bus_dma_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_nand_clk.common, + &bus_dram_clk.common, + &bus_hstimer_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &bus_otg_clk.common, + &bus_ehci_clk.common, + &bus_ohci_clk.common, + &bus_ve_clk.common, + &bus_lcd_clk.common, + &bus_csi_clk.common, + &bus_de_fe_clk.common, + &bus_de_be_clk.common, + &bus_gpu_clk.common, + &bus_msgbox_clk.common, + &bus_spinlock_clk.common, + &bus_drc_clk.common, + &bus_sat_clk.common, + &bus_codec_clk.common, + &bus_pio_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_uart4_clk.common, + &nand_clk.common, + &mmc0_clk.common, + &mmc0_sample_clk.common, + &mmc0_output_clk.common, + &mmc1_clk.common, + &mmc1_sample_clk.common, + &mmc1_output_clk.common, + &mmc2_clk.common, + &mmc2_sample_clk.common, + &mmc2_output_clk.common, + &ss_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &usb_phy0_clk.common, + &usb_phy1_clk.common, + &usb_hsic_clk.common, + &usb_hsic_12M_clk.common, + &usb_ohci_clk.common, + &dram_clk.common, + &dram_ve_clk.common, + &dram_csi_clk.common, + &dram_drc_clk.common, + &dram_de_fe_clk.common, + &dram_de_be_clk.common, + &de_be_clk.common, + &de_fe_clk.common, + &lcd_ch0_clk.common, + &lcd_ch1_clk.common, + &csi_sclk_clk.common, + &csi_mclk_clk.common, + &ve_clk.common, + &ac_dig_clk.common, + &ac_dig_4x_clk.common, + &avs_clk.common, + &mbus_clk.common, + &dsi_sclk_clk.common, + &dsi_dphy_clk.common, + &drc_clk.common, + &gpu_clk.common, + &ats_clk.common, +}; + +/* We hardcode the divider to 4 for now */ +static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", + "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x", + "pll-periph", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x", + "pll-video", 1, 2, 0); + +static struct clk_hw_onecell_data sun8i_a33_hw_clks = { + .hws = { + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, + [CLK_PLL_VIDEO] = &pll_video_clk.common.hw, + [CLK_PLL_VIDEO_2X] = &pll_video_2x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, + [CLK_PLL_PERIPH] = &pll_periph_clk.common.hw, + [CLK_PLL_PERIPH_2X] = &pll_periph_2x_clk.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_MIPI] = &pll_mipi_clk.common.hw, + [CLK_PLL_HSIC] = &pll_hsic_clk.common.hw, + [CLK_PLL_DE] = &pll_de_clk.common.hw, + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, + [CLK_PLL_DDR] = &pll_ddr_clk.common.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_AHB1] = &ahb1_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw, + [CLK_BUS_SS] = &bus_ss_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw, + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw, + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_EHCI] = &bus_ehci_clk.common.hw, + [CLK_BUS_OHCI] = &bus_ohci_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_BUS_LCD] = &bus_lcd_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_BUS_DE_BE] = &bus_de_be_clk.common.hw, + [CLK_BUS_DE_FE] = &bus_de_fe_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_DRC] = &bus_drc_clk.common.hw, + [CLK_BUS_SAT] = &bus_sat_clk.common.hw, + [CLK_BUS_CODEC] = &bus_codec_clk.common.hw, + [CLK_BUS_PIO] = &bus_pio_clk.common.hw, + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw, + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw, + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw, + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw, + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, + [CLK_BUS_UART4] = &bus_uart4_clk.common.hw, + [CLK_NAND] = &nand_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC0_SAMPLE] = &mmc0_sample_clk.common.hw, + [CLK_MMC0_OUTPUT] = &mmc0_output_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC1_SAMPLE] = &mmc1_sample_clk.common.hw, + [CLK_MMC1_OUTPUT] = &mmc1_output_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_MMC2_SAMPLE] = &mmc2_sample_clk.common.hw, + [CLK_MMC2_OUTPUT] = &mmc2_output_clk.common.hw, + [CLK_SS] = &ss_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_HSIC] = &usb_hsic_clk.common.hw, + [CLK_USB_HSIC_12M] = &usb_hsic_12M_clk.common.hw, + [CLK_USB_OHCI] = &usb_ohci_clk.common.hw, + [CLK_DRAM] = &dram_clk.common.hw, + [CLK_DRAM_VE] = &dram_ve_clk.common.hw, + [CLK_DRAM_CSI] = &dram_csi_clk.common.hw, + [CLK_DRAM_DRC] = &dram_drc_clk.common.hw, + [CLK_DRAM_DE_FE] = &dram_de_fe_clk.common.hw, + [CLK_DRAM_DE_BE] = &dram_de_be_clk.common.hw, + [CLK_DE_BE] = &de_be_clk.common.hw, + [CLK_DE_FE] = &de_fe_clk.common.hw, + [CLK_LCD_CH0] = &lcd_ch0_clk.common.hw, + [CLK_LCD_CH1] = &lcd_ch1_clk.common.hw, + [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw, + [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_AC_DIG] = &ac_dig_clk.common.hw, + [CLK_AC_DIG_4X] = &ac_dig_4x_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_DSI_SCLK] = &dsi_sclk_clk.common.hw, + [CLK_DSI_DPHY] = &dsi_dphy_clk.common.hw, + [CLK_DRC] = &drc_clk.common.hw, + [CLK_GPU] = &gpu_clk.common.hw, + [CLK_ATS] = &ats_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun8i_a33_ccu_resets[] = { + [RST_USB_PHY0] = { 0x0cc, BIT(0) }, + [RST_USB_PHY1] = { 0x0cc, BIT(1) }, + [RST_USB_HSIC] = { 0x0cc, BIT(2) }, + + [RST_MBUS] = { 0x0fc, BIT(31) }, + + [RST_BUS_MIPI_DSI] = { 0x2c0, BIT(1) }, + [RST_BUS_SS] = { 0x2c0, BIT(5) }, + [RST_BUS_DMA] = { 0x2c0, BIT(6) }, + [RST_BUS_MMC0] = { 0x2c0, BIT(8) }, + [RST_BUS_MMC1] = { 0x2c0, BIT(9) }, + [RST_BUS_MMC2] = { 0x2c0, BIT(10) }, + [RST_BUS_NAND] = { 0x2c0, BIT(13) }, + [RST_BUS_DRAM] = { 0x2c0, BIT(14) }, + [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) }, + [RST_BUS_SPI0] = { 0x2c0, BIT(20) }, + [RST_BUS_SPI1] = { 0x2c0, BIT(21) }, + [RST_BUS_OTG] = { 0x2c0, BIT(24) }, + [RST_BUS_EHCI] = { 0x2c0, BIT(26) }, + [RST_BUS_OHCI] = { 0x2c0, BIT(29) }, + + [RST_BUS_VE] = { 0x2c4, BIT(0) }, + [RST_BUS_LCD] = { 0x2c4, BIT(4) }, + [RST_BUS_CSI] = { 0x2c4, BIT(8) }, + [RST_BUS_DE_BE] = { 0x2c4, BIT(12) }, + [RST_BUS_DE_FE] = { 0x2c4, BIT(14) }, + [RST_BUS_GPU] = { 0x2c4, BIT(20) }, + [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) }, + [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) }, + [RST_BUS_DRC] = { 0x2c4, BIT(25) }, + [RST_BUS_SAT] = { 0x2c4, BIT(26) }, + + [RST_BUS_LVDS] = { 0x2c8, BIT(0) }, + + [RST_BUS_CODEC] = { 0x2d0, BIT(0) }, + [RST_BUS_I2S0] = { 0x2d0, BIT(12) }, + [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, + + [RST_BUS_I2C0] = { 0x2d4, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d4, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d4, BIT(2) }, + [RST_BUS_UART0] = { 0x2d4, BIT(16) }, + [RST_BUS_UART1] = { 0x2d4, BIT(17) }, + [RST_BUS_UART2] = { 0x2d4, BIT(18) }, + [RST_BUS_UART3] = { 0x2d4, BIT(19) }, + [RST_BUS_UART4] = { 0x2d4, BIT(20) }, +}; + +static const struct sunxi_ccu_desc sun8i_a33_ccu_desc = { + .ccu_clks = sun8i_a33_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_a33_ccu_clks), + + .hw_clks = &sun8i_a33_hw_clks, + + .resets = sun8i_a33_ccu_resets, + .num_resets = ARRAY_SIZE(sun8i_a33_ccu_resets), +}; + +static void __init sun8i_a33_ccu_setup(struct device_node *node) +{ + void __iomem *reg; + u32 val; + + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(reg)) { + pr_err("%s: Could not map the clock registers\n", + of_node_full_name(node)); + return; + } + + /* Force the PLL-Audio-1x divider to 4 */ + val = readl(reg + SUN8I_A33_PLL_AUDIO_REG); + val &= ~GENMASK(19, 16); + writel(val | (3 << 16), reg + SUN8I_A33_PLL_AUDIO_REG); + + /* Force PLL-MIPI to MIPI mode */ + val = readl(reg + SUN8I_A33_PLL_MIPI_REG); + val &= ~BIT(16); + writel(val, reg + SUN8I_A33_PLL_MIPI_REG); + + sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc); +} +CLK_OF_DECLARE(sun8i_a33_ccu, "allwinner,sun8i-a33-ccu", + sun8i_a33_ccu_setup); diff --git a/include/dt-bindings/clock/sun8i-a23-a33-ccu.h b/include/dt-bindings/clock/sun8i-a23-a33-ccu.h new file mode 100644 index 0000000..f8222b6 --- /dev/null +++ b/include/dt-bindings/clock/sun8i-a23-a33-ccu.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 Maxime Ripard + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DT_BINDINGS_CLK_SUN8I_A23_A33_H_ +#define _DT_BINDINGS_CLK_SUN8I_A23_A33_H_ + +#define CLK_CPUX 18 + +#define CLK_BUS_MIPI_DSI 23 +#define CLK_BUS_SS 24 +#define CLK_BUS_DMA 25 +#define CLK_BUS_MMC0 26 +#define CLK_BUS_MMC1 27 +#define CLK_BUS_MMC2 28 +#define CLK_BUS_NAND 29 +#define CLK_BUS_DRAM 30 +#define CLK_BUS_HSTIMER 31 +#define CLK_BUS_SPI0 32 +#define CLK_BUS_SPI1 33 +#define CLK_BUS_OTG 34 +#define CLK_BUS_EHCI 35 +#define CLK_BUS_OHCI 36 +#define CLK_BUS_VE 37 +#define CLK_BUS_LCD 38 +#define CLK_BUS_CSI 39 +#define CLK_BUS_DE_BE 40 +#define CLK_BUS_DE_FE 41 +#define CLK_BUS_GPU 42 +#define CLK_BUS_MSGBOX 43 +#define CLK_BUS_SPINLOCK 44 +#define CLK_BUS_DRC 45 +#define CLK_BUS_SAT 46 +#define CLK_BUS_CODEC 47 +#define CLK_BUS_PIO 48 +#define CLK_BUS_I2S0 49 +#define CLK_BUS_I2S1 50 +#define CLK_BUS_I2C0 51 +#define CLK_BUS_I2C1 52 +#define CLK_BUS_I2C2 53 +#define CLK_BUS_UART0 54 +#define CLK_BUS_UART1 55 +#define CLK_BUS_UART2 56 +#define CLK_BUS_UART3 57 +#define CLK_BUS_UART4 58 +#define CLK_NAND 59 +#define CLK_MMC0 60 +#define CLK_MMC0_SAMPLE 61 +#define CLK_MMC0_OUTPUT 62 +#define CLK_MMC1 63 +#define CLK_MMC1_SAMPLE 64 +#define CLK_MMC1_OUTPUT 65 +#define CLK_MMC2 66 +#define CLK_MMC2_SAMPLE 67 +#define CLK_MMC2_OUTPUT 68 +#define CLK_SS 69 +#define CLK_SPI0 70 +#define CLK_SPI1 71 +#define CLK_I2S0 72 +#define CLK_I2S1 73 +#define CLK_USB_PHY0 74 +#define CLK_USB_PHY1 75 +#define CLK_USB_HSIC 76 +#define CLK_USB_HSIC_12M 77 +#define CLK_USB_OHCI 78 + +#define CLK_DRAM_VE 80 +#define CLK_DRAM_CSI 81 +#define CLK_DRAM_DRC 82 +#define CLK_DRAM_DE_FE 83 +#define CLK_DRAM_DE_BE 84 +#define CLK_DE_BE 85 +#define CLK_DE_FE 86 +#define CLK_LCD_CH0 87 +#define CLK_LCD_CH1 88 +#define CLK_CSI_SCLK 89 +#define CLK_CSI_MCLK 90 +#define CLK_VE 91 +#define CLK_AC_DIG 92 +#define CLK_AC_DIG_4X 93 +#define CLK_AVS 94 + +#define CLK_DSI_SCLK 96 +#define CLK_DSI_DPHY 97 +#define CLK_DRC 98 +#define CLK_GPU 99 +#define CLK_ATS 100 + +#endif /* _DT_BINDINGS_CLK_SUN8I_A23_A33_H_ */ diff --git a/include/dt-bindings/reset/sun8i-a23-a33-ccu.h b/include/dt-bindings/reset/sun8i-a23-a33-ccu.h new file mode 100644 index 0000000..6121f2b --- /dev/null +++ b/include/dt-bindings/reset/sun8i-a23-a33-ccu.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 Maxime Ripard + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DT_BINDINGS_RST_SUN8I_A23_A33_H_ +#define _DT_BINDINGS_RST_SUN8I_A23_A33_H_ + +#define RST_USB_PHY0 0 +#define RST_USB_PHY1 1 +#define RST_USB_HSIC 2 +#define RST_MBUS 3 +#define RST_BUS_MIPI_DSI 4 +#define RST_BUS_SS 5 +#define RST_BUS_DMA 6 +#define RST_BUS_MMC0 7 +#define RST_BUS_MMC1 8 +#define RST_BUS_MMC2 9 +#define RST_BUS_NAND 10 +#define RST_BUS_DRAM 11 +#define RST_BUS_HSTIMER 12 +#define RST_BUS_SPI0 13 +#define RST_BUS_SPI1 14 +#define RST_BUS_OTG 15 +#define RST_BUS_EHCI 16 +#define RST_BUS_OHCI 17 +#define RST_BUS_VE 18 +#define RST_BUS_LCD 19 +#define RST_BUS_CSI 20 +#define RST_BUS_DE_BE 21 +#define RST_BUS_DE_FE 22 +#define RST_BUS_GPU 23 +#define RST_BUS_MSGBOX 24 +#define RST_BUS_SPINLOCK 25 +#define RST_BUS_DRC 26 +#define RST_BUS_SAT 27 +#define RST_BUS_LVDS 28 +#define RST_BUS_CODEC 29 +#define RST_BUS_I2S0 30 +#define RST_BUS_I2S1 31 +#define RST_BUS_I2C0 32 +#define RST_BUS_I2C1 33 +#define RST_BUS_I2C2 34 +#define RST_BUS_UART0 35 +#define RST_BUS_UART1 36 +#define RST_BUS_UART2 37 +#define RST_BUS_UART3 38 +#define RST_BUS_UART4 39 + +#endif /* _DT_BINDINGS_RST_SUN8I_A23_A33_H_ */ -- cgit v0.10.2 From 5690879d93e8d3706908ec2959b0905227e68cf1 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 31 Aug 2016 16:55:00 +0200 Subject: clk: sunxi-ng: Add A23 CCU Add support for the clock unit found in the A23. Due to the similarities with the A33, it also shares its clock IDs to allow sharing the DTSI. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt index 8fd765e..3868458 100644 --- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt +++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt @@ -4,6 +4,7 @@ Allwinner Clock Control Unit Binding Required properties : - compatible: must contain one of the following compatibles: - "allwinner,sun6i-a31-ccu" + - "allwinner,sun8i-a23-ccu" - "allwinner,sun8i-a33-ccu" - "allwinner,sun8i-h3-ccu" diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index dff3fef..90fd1e4 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -65,6 +65,18 @@ config SUN6I_A31_CCU select SUNXI_CCU_PHASE default MACH_SUN6I +config SUN8I_A23_CCU + bool "Support for the Allwinner A23 CCU" + select SUNXI_CCU_DIV + select SUNXI_CCU_MULT + select SUNXI_CCU_NK + select SUNXI_CCU_NKM + select SUNXI_CCU_NKMP + select SUNXI_CCU_NM + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN8I + config SUN8I_A33_CCU bool "Support for the Allwinner A33 CCU" select SUNXI_CCU_DIV diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 4f7e99f..106cba2 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -19,5 +19,6 @@ obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o # SoC support obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o +obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c new file mode 100644 index 0000000..11e624a --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -0,0 +1,737 @@ +/* + * Copyright (c) 2016 Maxime Ripard. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_phase.h" + +#include "ccu-sun8i-a23-a33.h" + + +static struct ccu_nkmp pll_cpux_clk = { + .enable = BIT(31), + .lock = BIT(28), + + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT(4, 2), + .m = _SUNXI_CCU_DIV(0, 2), + .p = _SUNXI_CCU_DIV_MAX(16, 2, 4), + + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", + &ccu_nkmp_ops, + 0), + }, +}; + +/* + * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from + * the base (2x, 4x and 8x), and one variable divider (the one true + * pll audio). + * + * We don't have any need for the variable divider for now, so we just + * hardcode it to match with the clock names + */ +#define SUN8I_A23_PLL_AUDIO_REG 0x008 + +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video", + "osc24M", 0x010, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", + "osc24M", 0x018, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", + "osc24M", 0x020, + 8, 5, /* N */ + 4, 2, /* K */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + +static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph_clk, "pll-periph", + "osc24M", 0x028, + 8, 5, /* N */ + 4, 2, /* K */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 2, /* post-div */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", + "osc24M", 0x038, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +/* + * The MIPI PLL has 2 modes: "MIPI" and "HDMI". + * + * The MIPI mode is a standard NKM-style clock. The HDMI mode is an + * integer / fractional clock with switchable multipliers and dividers. + * This is not supported here. We hardcode the PLL to MIPI mode. + */ +#define SUN8I_A23_PLL_MIPI_REG 0x040 +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_mipi_clk, "pll-mipi", + "pll-video", 0x040, + 8, 4, /* N */ + 4, 2, /* K */ + 0, 4, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_hsic_clk, "pll-hsic", + "osc24M", 0x044, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de", + "osc24M", 0x048, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static const char * const cpux_parents[] = { "osc32k", "osc24M", + "pll-cpux" , "pll-cpux" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x050, 16, 2, CLK_IS_CRITICAL); + +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0); + +static const char * const ahb1_parents[] = { "osc32k", "osc24M", + "axi" , "pll-periph" }; +static struct ccu_div ahb1_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 12, + .width = 2, + + .variable_prediv = { + .index = 3, + .shift = 6, + .width = 2, + }, + }, + + .common = { + .reg = 0x054, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ahb1", + ahb1_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct clk_div_table apb1_div_table[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { /* Sentinel */ }, +}; +static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1", + 0x054, 8, 2, apb1_div_table, 0); + +static const char * const apb2_parents[] = { "osc32k", "osc24M", + "pll-periph" , "pll-periph" }; +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb1", + 0x060, BIT(1), 0); +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1", + 0x060, BIT(6), 0); +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1", + 0x060, BIT(8), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1", + 0x060, BIT(9), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1", + 0x060, BIT(10), 0); +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1", + 0x060, BIT(14), 0); +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1", + 0x060, BIT(19), 0); +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1", + 0x060, BIT(20), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1", + 0x060, BIT(21), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1", + 0x060, BIT(24), 0); +static SUNXI_CCU_GATE(bus_ehci_clk, "bus-ehci", "ahb1", + 0x060, BIT(26), 0); +static SUNXI_CCU_GATE(bus_ohci_clk, "bus-ohci", "ahb1", + 0x060, BIT(29), 0); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1", + 0x064, BIT(0), 0); +static SUNXI_CCU_GATE(bus_lcd_clk, "bus-lcd", "ahb1", + 0x064, BIT(4), 0); +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1", + 0x064, BIT(8), 0); +static SUNXI_CCU_GATE(bus_de_be_clk, "bus-de-be", "ahb1", + 0x064, BIT(12), 0); +static SUNXI_CCU_GATE(bus_de_fe_clk, "bus-de-fe", "ahb1", + 0x064, BIT(14), 0); +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1", + 0x064, BIT(20), 0); +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1", + 0x064, BIT(21), 0); +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1", + 0x064, BIT(22), 0); +static SUNXI_CCU_GATE(bus_drc_clk, "bus-drc", "ahb1", + 0x064, BIT(25), 0); + +static SUNXI_CCU_GATE(bus_codec_clk, "bus-codec", "apb1", + 0x068, BIT(0), 0); +static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1", + 0x068, BIT(5), 0); +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", + 0x068, BIT(12), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", + 0x068, BIT(13), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", + 0x06c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", + 0x06c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", + 0x06c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", + 0x06c, BIT(16), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", + 0x06c, BIT(17), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", + 0x06c, BIT(18), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", + 0x06c, BIT(19), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", + 0x06c, BIT(20), 0); + +static const char * const mod0_default_parents[] = { "osc24M", "pll-periph" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_default_parents, 0x088, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0", + 0x088, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0", + 0x088, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_default_parents, 0x08c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1_sample", "mmc1", + 0x08c, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1_output", "mmc1", + 0x08c, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mod0_default_parents, 0x090, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2_sample", "mmc2", + 0x090, 20, 3, 0); +static SUNXI_CCU_PHASE(mmc2_output_clk, "mmc2_output", "mmc2", + 0x090, 8, 3, 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents, 0x0a0, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x", + "pll-audio-2x", "pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents, + 0x0b0, 16, 2, BIT(31), 0); + +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents, + 0x0b4, 16, 2, BIT(31), 0); + +/* TODO: the parent for most of the USB clocks is not known */ +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", + 0x0cc, BIT(8), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", + 0x0cc, BIT(9), 0); +static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "pll-hsic", + 0x0cc, BIT(10), 0); +static SUNXI_CCU_GATE(usb_hsic_12M_clk, "usb-hsic-12M", "osc24M", + 0x0cc, BIT(11), 0); +static SUNXI_CCU_GATE(usb_ohci_clk, "usb-ohci", "osc24M", + 0x0cc, BIT(16), 0); + +static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "pll-ddr", + 0x100, BIT(0), 0); +static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "pll-ddr", + 0x100, BIT(1), 0); +static SUNXI_CCU_GATE(dram_drc_clk, "dram-drc", "pll-ddr", + 0x100, BIT(16), 0); +static SUNXI_CCU_GATE(dram_de_fe_clk, "dram-de-fe", "pll-ddr", + 0x100, BIT(24), 0); +static SUNXI_CCU_GATE(dram_de_be_clk, "dram-de-be", "pll-ddr", + 0x100, BIT(26), 0); + +static const char * const de_parents[] = { "pll-video", "pll-periph-2x", + "pll-gpu", "pll-de" }; +static const u8 de_table[] = { 0, 2, 3, 5 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(de_be_clk, "de-be", + de_parents, de_table, + 0x104, 0, 4, 24, 3, BIT(31), 0); + +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(de_fe_clk, "de-fe", + de_parents, de_table, + 0x10c, 0, 4, 24, 3, BIT(31), 0); + +static const char * const lcd_ch0_parents[] = { "pll-video", "pll-video-2x", + "pll-mipi" }; +static const u8 lcd_ch0_table[] = { 0, 2, 4 }; +static SUNXI_CCU_MUX_TABLE_WITH_GATE(lcd_ch0_clk, "lcd-ch0", + lcd_ch0_parents, lcd_ch0_table, + 0x118, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); + +static const char * const lcd_ch1_parents[] = { "pll-video", "pll-video-2x" }; +static const u8 lcd_ch1_table[] = { 0, 2 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(lcd_ch1_clk, "lcd-ch1", + lcd_ch1_parents, lcd_ch1_table, + 0x12c, 0, 4, 24, 2, BIT(31), 0); + +static const char * const csi_sclk_parents[] = { "pll-video", "pll-de", + "pll-mipi", "pll-ve" }; +static const u8 csi_sclk_table[] = { 0, 3, 4, 5 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_sclk_clk, "csi-sclk", + csi_sclk_parents, csi_sclk_table, + 0x134, 16, 4, 24, 3, BIT(31), 0); + +static const char * const csi_mclk_parents[] = { "pll-video", "pll-de", + "osc24M" }; +static const u8 csi_mclk_table[] = { 0, 3, 5 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_mclk_clk, "csi-mclk", + csi_mclk_parents, csi_mclk_table, + 0x134, 0, 5, 8, 3, BIT(15), 0); + +static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", + 0x13c, 16, 3, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", + 0x140, BIT(31), 0); +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", + 0x144, BIT(31), 0); + +static const char * const mbus_parents[] = { "osc24M", "pll-periph-2x", + "pll-ddr" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, + 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL); + +static const char * const dsi_sclk_parents[] = { "pll-video", "pll-video-2x" }; +static const u8 dsi_sclk_table[] = { 0, 2 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_sclk_clk, "dsi-sclk", + dsi_sclk_parents, dsi_sclk_table, + 0x168, 16, 4, 24, 2, BIT(31), 0); + +static const char * const dsi_dphy_parents[] = { "pll-video", "pll-periph" }; +static const u8 dsi_dphy_table[] = { 0, 2 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_dphy_clk, "dsi-dphy", + dsi_dphy_parents, dsi_dphy_table, + 0x168, 0, 4, 8, 2, BIT(15), 0); + +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(drc_clk, "drc", + de_parents, de_table, + 0x180, 0, 4, 24, 3, BIT(31), 0); + +static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", + 0x1a0, 0, 3, BIT(31), 0); + +static const char * const ats_parents[] = { "osc24M", "pll-periph" }; +static SUNXI_CCU_M_WITH_MUX_GATE(ats_clk, "ats", ats_parents, + 0x1b0, 0, 3, 24, 2, BIT(31), 0); + +static struct ccu_common *sun8i_a23_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_audio_base_clk.common, + &pll_video_clk.common, + &pll_ve_clk.common, + &pll_ddr_clk.common, + &pll_periph_clk.common, + &pll_gpu_clk.common, + &pll_mipi_clk.common, + &pll_hsic_clk.common, + &pll_de_clk.common, + &cpux_clk.common, + &axi_clk.common, + &ahb1_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &bus_mipi_dsi_clk.common, + &bus_dma_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_nand_clk.common, + &bus_dram_clk.common, + &bus_hstimer_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &bus_otg_clk.common, + &bus_ehci_clk.common, + &bus_ohci_clk.common, + &bus_ve_clk.common, + &bus_lcd_clk.common, + &bus_csi_clk.common, + &bus_de_fe_clk.common, + &bus_de_be_clk.common, + &bus_gpu_clk.common, + &bus_msgbox_clk.common, + &bus_spinlock_clk.common, + &bus_drc_clk.common, + &bus_codec_clk.common, + &bus_pio_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_uart4_clk.common, + &nand_clk.common, + &mmc0_clk.common, + &mmc0_sample_clk.common, + &mmc0_output_clk.common, + &mmc1_clk.common, + &mmc1_sample_clk.common, + &mmc1_output_clk.common, + &mmc2_clk.common, + &mmc2_sample_clk.common, + &mmc2_output_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &usb_phy0_clk.common, + &usb_phy1_clk.common, + &usb_hsic_clk.common, + &usb_hsic_12M_clk.common, + &usb_ohci_clk.common, + &dram_ve_clk.common, + &dram_csi_clk.common, + &dram_drc_clk.common, + &dram_de_fe_clk.common, + &dram_de_be_clk.common, + &de_be_clk.common, + &de_fe_clk.common, + &lcd_ch0_clk.common, + &lcd_ch1_clk.common, + &csi_sclk_clk.common, + &csi_mclk_clk.common, + &ve_clk.common, + &ac_dig_clk.common, + &avs_clk.common, + &mbus_clk.common, + &dsi_sclk_clk.common, + &dsi_dphy_clk.common, + &drc_clk.common, + &gpu_clk.common, + &ats_clk.common, +}; + +/* We hardcode the divider to 4 for now */ +static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", + "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x", + "pll-periph", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x", + "pll-video", 1, 2, 0); + +static struct clk_hw_onecell_data sun8i_a23_hw_clks = { + .hws = { + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, + [CLK_PLL_VIDEO] = &pll_video_clk.common.hw, + [CLK_PLL_VIDEO_2X] = &pll_video_2x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr_clk.common.hw, + [CLK_PLL_PERIPH] = &pll_periph_clk.common.hw, + [CLK_PLL_PERIPH_2X] = &pll_periph_2x_clk.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_MIPI] = &pll_mipi_clk.common.hw, + [CLK_PLL_HSIC] = &pll_hsic_clk.common.hw, + [CLK_PLL_DE] = &pll_de_clk.common.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_AHB1] = &ahb1_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw, + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw, + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_EHCI] = &bus_ehci_clk.common.hw, + [CLK_BUS_OHCI] = &bus_ohci_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_BUS_LCD] = &bus_lcd_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_BUS_DE_BE] = &bus_de_be_clk.common.hw, + [CLK_BUS_DE_FE] = &bus_de_fe_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_DRC] = &bus_drc_clk.common.hw, + [CLK_BUS_CODEC] = &bus_codec_clk.common.hw, + [CLK_BUS_PIO] = &bus_pio_clk.common.hw, + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw, + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw, + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw, + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw, + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, + [CLK_BUS_UART4] = &bus_uart4_clk.common.hw, + [CLK_NAND] = &nand_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC0_SAMPLE] = &mmc0_sample_clk.common.hw, + [CLK_MMC0_OUTPUT] = &mmc0_output_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC1_SAMPLE] = &mmc1_sample_clk.common.hw, + [CLK_MMC1_OUTPUT] = &mmc1_output_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_MMC2_SAMPLE] = &mmc2_sample_clk.common.hw, + [CLK_MMC2_OUTPUT] = &mmc2_output_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_HSIC] = &usb_hsic_clk.common.hw, + [CLK_USB_HSIC_12M] = &usb_hsic_12M_clk.common.hw, + [CLK_USB_OHCI] = &usb_ohci_clk.common.hw, + [CLK_DRAM_VE] = &dram_ve_clk.common.hw, + [CLK_DRAM_CSI] = &dram_csi_clk.common.hw, + [CLK_DRAM_DRC] = &dram_drc_clk.common.hw, + [CLK_DRAM_DE_FE] = &dram_de_fe_clk.common.hw, + [CLK_DRAM_DE_BE] = &dram_de_be_clk.common.hw, + [CLK_DE_BE] = &de_be_clk.common.hw, + [CLK_DE_FE] = &de_fe_clk.common.hw, + [CLK_LCD_CH0] = &lcd_ch0_clk.common.hw, + [CLK_LCD_CH1] = &lcd_ch1_clk.common.hw, + [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw, + [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_AC_DIG] = &ac_dig_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_DSI_SCLK] = &dsi_sclk_clk.common.hw, + [CLK_DSI_DPHY] = &dsi_dphy_clk.common.hw, + [CLK_DRC] = &drc_clk.common.hw, + [CLK_GPU] = &gpu_clk.common.hw, + [CLK_ATS] = &ats_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun8i_a23_ccu_resets[] = { + [RST_USB_PHY0] = { 0x0cc, BIT(0) }, + [RST_USB_PHY1] = { 0x0cc, BIT(1) }, + [RST_USB_HSIC] = { 0x0cc, BIT(2) }, + + [RST_MBUS] = { 0x0fc, BIT(31) }, + + [RST_BUS_MIPI_DSI] = { 0x2c0, BIT(1) }, + [RST_BUS_DMA] = { 0x2c0, BIT(6) }, + [RST_BUS_MMC0] = { 0x2c0, BIT(8) }, + [RST_BUS_MMC1] = { 0x2c0, BIT(9) }, + [RST_BUS_MMC2] = { 0x2c0, BIT(10) }, + [RST_BUS_NAND] = { 0x2c0, BIT(13) }, + [RST_BUS_DRAM] = { 0x2c0, BIT(14) }, + [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) }, + [RST_BUS_SPI0] = { 0x2c0, BIT(20) }, + [RST_BUS_SPI1] = { 0x2c0, BIT(21) }, + [RST_BUS_OTG] = { 0x2c0, BIT(24) }, + [RST_BUS_EHCI] = { 0x2c0, BIT(26) }, + [RST_BUS_OHCI] = { 0x2c0, BIT(29) }, + + [RST_BUS_VE] = { 0x2c4, BIT(0) }, + [RST_BUS_LCD] = { 0x2c4, BIT(4) }, + [RST_BUS_CSI] = { 0x2c4, BIT(8) }, + [RST_BUS_DE_BE] = { 0x2c4, BIT(12) }, + [RST_BUS_DE_FE] = { 0x2c4, BIT(14) }, + [RST_BUS_GPU] = { 0x2c4, BIT(20) }, + [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) }, + [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) }, + [RST_BUS_DRC] = { 0x2c4, BIT(25) }, + + [RST_BUS_LVDS] = { 0x2c8, BIT(0) }, + + [RST_BUS_CODEC] = { 0x2d0, BIT(0) }, + [RST_BUS_I2S0] = { 0x2d0, BIT(12) }, + [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, + + [RST_BUS_I2C0] = { 0x2d4, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d4, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d4, BIT(2) }, + [RST_BUS_UART0] = { 0x2d4, BIT(16) }, + [RST_BUS_UART1] = { 0x2d4, BIT(17) }, + [RST_BUS_UART2] = { 0x2d4, BIT(18) }, + [RST_BUS_UART3] = { 0x2d4, BIT(19) }, + [RST_BUS_UART4] = { 0x2d4, BIT(20) }, +}; + +static const struct sunxi_ccu_desc sun8i_a23_ccu_desc = { + .ccu_clks = sun8i_a23_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_a23_ccu_clks), + + .hw_clks = &sun8i_a23_hw_clks, + + .resets = sun8i_a23_ccu_resets, + .num_resets = ARRAY_SIZE(sun8i_a23_ccu_resets), +}; + +static void __init sun8i_a23_ccu_setup(struct device_node *node) +{ + void __iomem *reg; + u32 val; + + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(reg)) { + pr_err("%s: Could not map the clock registers\n", + of_node_full_name(node)); + return; + } + + /* Force the PLL-Audio-1x divider to 4 */ + val = readl(reg + SUN8I_A23_PLL_AUDIO_REG); + val &= ~GENMASK(19, 16); + writel(val | (3 << 16), reg + SUN8I_A23_PLL_AUDIO_REG); + + /* Force PLL-MIPI to MIPI mode */ + val = readl(reg + SUN8I_A23_PLL_MIPI_REG); + val &= ~BIT(16); + writel(val, reg + SUN8I_A23_PLL_MIPI_REG); + + sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc); +} +CLK_OF_DECLARE(sun8i_a23_ccu, "allwinner,sun8i-a23-ccu", + sun8i_a23_ccu_setup); -- cgit v0.10.2 From d63a5e7c713a68bd368016f2022326a1a91310d8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 8 Sep 2016 23:28:29 +0200 Subject: clk: sunxi-ng: Add hardware dependency The sunxi-ng clock driver is useless for other architectures. Signed-off-by: Jean Delvare Acked-by: Stephen Boyd Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 90fd1e4..254d952 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -1,5 +1,6 @@ config SUNXI_CCU bool "Clock support for Allwinner SoCs" + depends on ARCH_SUNXI || COMPILE_TEST default ARCH_SUNXI if SUNXI_CCU -- cgit v0.10.2 From 5576df81d28d46b603e5af10d1d0e1c7cc93a4bc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 6 Sep 2016 16:57:30 +0300 Subject: clk: renesas: r8a7796: Add RAVB clock Signed-off-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 271fc3b..8b69f70 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -117,6 +117,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("rwdt0", 402, R8A7796_CLK_R), DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1), DEF_MOD("thermal", 522, R8A7796_CLK_CP), + DEF_MOD("etheravb", 812, R8A7796_CLK_S0D6), DEF_MOD("gpio7", 905, R8A7796_CLK_S3D4), DEF_MOD("gpio6", 906, R8A7796_CLK_S3D4), DEF_MOD("gpio5", 907, R8A7796_CLK_S3D4), -- cgit v0.10.2 From 591d7b145a57dd9e8354fa776b0d9f678e2cda8c Mon Sep 17 00:00:00 2001 From: Bui Duc Phuc Date: Fri, 9 Sep 2016 20:43:10 +0900 Subject: clk: renesas: r8a7795: Add CMT clocks This patch adds CMT module clocks for r8a7795 SoC. Signed-off-by: Bui Duc Phuc Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index d359c92..61d061d 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -122,6 +122,10 @@ static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S3D1), DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1), DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S3D1), + DEF_MOD("cmt3", 300, R8A7795_CLK_R), + DEF_MOD("cmt2", 301, R8A7795_CLK_R), + DEF_MOD("cmt1", 302, R8A7795_CLK_R), + DEF_MOD("cmt0", 303, R8A7795_CLK_R), DEF_MOD("scif2", 310, R8A7795_CLK_S3D4), DEF_MOD("sdif3", 311, R8A7795_CLK_SD3), DEF_MOD("sdif2", 312, R8A7795_CLK_SD2), -- cgit v0.10.2 From 5fad71f58f4c236118358c98f65a7251e9c718f7 Mon Sep 17 00:00:00 2001 From: Bui Duc Phuc Date: Fri, 9 Sep 2016 20:43:11 +0900 Subject: clk: renesas: r8a7796: Add CMT clocks This patch adds CMT module clocks for r8a7796 SoC. Signed-off-by: Bui Duc Phuc Signed-off-by: Geert Uytterhoeven diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 8b69f70..eb347ed 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -109,6 +109,10 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { + DEF_MOD("cmt3", 300, R8A7796_CLK_R), + DEF_MOD("cmt2", 301, R8A7796_CLK_R), + DEF_MOD("cmt1", 302, R8A7796_CLK_R), + DEF_MOD("cmt0", 303, R8A7796_CLK_R), DEF_MOD("scif2", 310, R8A7796_CLK_S3D4), DEF_MOD("sdif3", 311, R8A7796_CLK_SD3), DEF_MOD("sdif2", 312, R8A7796_CLK_SD2), -- cgit v0.10.2 From 8edeae56a1da30f0d33848fdd3bd8dafbcc2ad87 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 10 Sep 2016 12:02:49 +0000 Subject: meson: clk: Use builtin_platform_driver to simplify the code Use the builtin_platform_driver() macro to make the code simpler. Signed-off-by: Wei Yongjun Signed-off-by: Stephen Boyd diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index e1d4aa1..aaa3e39 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -673,8 +673,4 @@ static struct platform_driver meson8b_driver = { }, }; -static int __init meson8b_clkc_init(void) -{ - return platform_driver_register(&meson8b_driver); -} -device_initcall(meson8b_clkc_init); +builtin_platform_driver(meson8b_driver); -- cgit v0.10.2 From 344dcc02b0578bb3f2523aaa54d7f33730c7f5af Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Wed, 14 Sep 2016 14:23:28 +0800 Subject: clk: mmp: add missing header dependencies We get 1 warning when building kernel with W=1: drivers/clk/mmp/clk-mmp2.c:75:13: warning: no previous prototype for 'mmp2_clk_init' [-Wmissing-prototypes] In fact, this function is declared in linux/clk/mmp.h, so this patch add missing header dependencies. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c index 383f6a4..0380234 100644 --- a/drivers/clk/mmp/clk-mmp2.c +++ b/drivers/clk/mmp/clk-mmp2.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "clk.h" -- cgit v0.10.2 From 0d5aa65e329e7f0b753686e116c99e2d7263bced Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 6 Sep 2016 15:01:10 +0200 Subject: clk: meson: fix CLKID_GCLK_VENCI_INT typo The addition of many gate clocks added two entries in an array for the same value: drivers/clk/meson/meson8b.c:479:10: error: initialized field overwritten [-Werror=override-init] [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_vencp_int.hw, This was clearly an accident, and since all other identifiers are listed in the order in which they are defined, I'm changing the first one to CLKID_GCLK_VENCI_INT0, making it all consistent again. Signed-off-by: Arnd Bergmann Fixes: e31a1900c1ff ("meson: clk: Add support for clock gates") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index aaa3e39..3f1be46 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -476,7 +476,7 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, - [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_GCLK_VENCP_INT] = &meson8b_gclk_vencp_int.hw, [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, -- cgit v0.10.2 From fcff03813a7c612873303037cef5ba0329850c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 8 Sep 2016 11:30:21 +0200 Subject: ARM: clk-imx35: fix name for ckil clk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes [ 0.000000] i.MX clk 82: register failed with -17 because the name is duplicated. Signed-off-by: Uwe Kleine-König Fixes: 3713e3f5e927 ("clk: imx35: define two clocks for rtc") Acked-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index b0978d3..d302ed3 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -115,7 +115,7 @@ static void __init _mx35_clocks_init(void) } clk[ckih] = imx_clk_fixed("ckih", 24000000); - clk[ckil] = imx_clk_fixed("ckih", 32768); + clk[ckil] = imx_clk_fixed("ckil", 32768); clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL); clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL); -- cgit v0.10.2 From ece59749c3e4c0f75a114424e1e6059c4002b4a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 8 Sep 2016 11:30:22 +0200 Subject: ARM: clk-imx35: annotate clk enum with number values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps to decode error messages like: [ 0.000000] i.MX clk 82: register failed with -17 Signed-off-by: Uwe Kleine-König Acked-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index d302ed3..203cad6 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -66,20 +66,22 @@ static const char *std_sel[] = {"ppll", "arm"}; static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"}; enum mx35_clks { - ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, - arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel, - esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre, - spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre, - ssi2_div_post, usb_sel, usb_div, nfc_div, asrc_gate, pata_gate, - audmux_gate, can1_gate, can2_gate, cspi1_gate, cspi2_gate, ect_gate, - edio_gate, emi_gate, epit1_gate, epit2_gate, esai_gate, esdhc1_gate, - esdhc2_gate, esdhc3_gate, fec_gate, gpio1_gate, gpio2_gate, gpio3_gate, - gpt_gate, i2c1_gate, i2c2_gate, i2c3_gate, iomuxc_gate, ipu_gate, - kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate, - rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate, - ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate, - wdog_gate, max_gate, admux_gate, csi_gate, csi_div, csi_sel, iim_gate, - gpu2d_gate, ckil, clk_max + /* 0 */ ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, + /* 9 */ ipg, arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, + /* 15 */ esdhc_sel, esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, + /* 20 */ spdif_div_pre, spdif_div_post, ssi_sel, ssi1_div_pre, + /* 24 */ ssi1_div_post, ssi2_div_pre, ssi2_div_post, usb_sel, usb_div, + /* 29 */ nfc_div, asrc_gate, pata_gate, audmux_gate, can1_gate, + /* 34 */ can2_gate, cspi1_gate, cspi2_gate, ect_gate, edio_gate, + /* 39 */ emi_gate, epit1_gate, epit2_gate, esai_gate, esdhc1_gate, + /* 44 */ esdhc2_gate, esdhc3_gate, fec_gate, gpio1_gate, gpio2_gate, + /* 49 */ gpio3_gate, gpt_gate, i2c1_gate, i2c2_gate, i2c3_gate, + /* 54 */ iomuxc_gate, ipu_gate, kpp_gate, mlb_gate, mshc_gate, + /* 59 */ owire_gate, pwm_gate, rngc_gate, rtc_gate, rtic_gate, scc_gate, + /* 65 */ sdma_gate, spba_gate, spdif_gate, ssi1_gate, ssi2_gate, + /* 70 */ uart1_gate, uart2_gate, uart3_gate, usbotg_gate, wdog_gate, + /* 75 */ max_gate, admux_gate, csi_gate, csi_div, csi_sel, iim_gate, + /* 81 */ gpu2d_gate, ckil, clk_max }; static struct clk *clk[clk_max]; -- cgit v0.10.2 From 6e2e7c9fdae316bfb2724d2dbf230678d3f09092 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 14 Sep 2016 20:26:05 +0200 Subject: clk-kona-setup: Use kmalloc_array() in parent_process() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Alex Elder [sboyd@codeaurora.org: Save a line] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index f2359b3..c37a7f0 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -586,8 +586,8 @@ static u32 *parent_process(const char *clocks[], } /* There is at least one parent, so allocate a selector array */ - - parent_sel = kmalloc(parent_count * sizeof(*parent_sel), GFP_KERNEL); + parent_sel = kmalloc_array(parent_count, sizeof(*parent_sel), + GFP_KERNEL); if (!parent_sel) { pr_err("%s: error allocating %u parent selectors\n", __func__, parent_count); -- cgit v0.10.2 From 8d9a0860b75525e3cf240bc152bfdeaeb2e562a1 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 6 Sep 2016 14:02:41 +0800 Subject: clk: zx: reform pll config info to ease code extension Add power down bit and pll lock bit in pll config structure to ease new SoC support. Signed-off-by: Jun Nie Signed-off-by: Stephen Boyd diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c index 7c73c53..c4c1251 100644 --- a/drivers/clk/zte/clk.c +++ b/drivers/clk/zte/clk.c @@ -21,8 +21,8 @@ #define to_clk_zx_audio(_hw) container_of(_hw, struct clk_zx_audio, hw) #define CFG0_CFG1_OFFSET 4 -#define LOCK_FLAG BIT(30) -#define POWER_DOWN BIT(31) +#define LOCK_FLAG 30 +#define POWER_DOWN 31 static int rate_to_idx(struct clk_zx_pll *zx_pll, unsigned long rate) { @@ -50,8 +50,8 @@ static int hw_to_idx(struct clk_zx_pll *zx_pll) hw_cfg1 = readl_relaxed(zx_pll->reg_base + CFG0_CFG1_OFFSET); /* For matching the value in lookup table */ - hw_cfg0 &= ~LOCK_FLAG; - hw_cfg0 |= POWER_DOWN; + hw_cfg0 &= ~BIT(zx_pll->lock_bit); + hw_cfg0 |= BIT(zx_pll->pd_bit); for (i = 0; i < zx_pll->count; i++) { if (hw_cfg0 == config[i].cfg0 && hw_cfg1 == config[i].cfg1) @@ -108,10 +108,10 @@ static int zx_pll_enable(struct clk_hw *hw) u32 reg; reg = readl_relaxed(zx_pll->reg_base); - writel_relaxed(reg & ~POWER_DOWN, zx_pll->reg_base); + writel_relaxed(reg & ~BIT(zx_pll->pd_bit), zx_pll->reg_base); return readl_relaxed_poll_timeout(zx_pll->reg_base, reg, - reg & LOCK_FLAG, 0, 100); + reg & BIT(zx_pll->lock_bit), 0, 100); } static void zx_pll_disable(struct clk_hw *hw) @@ -120,7 +120,7 @@ static void zx_pll_disable(struct clk_hw *hw) u32 reg; reg = readl_relaxed(zx_pll->reg_base); - writel_relaxed(reg | POWER_DOWN, zx_pll->reg_base); + writel_relaxed(reg | BIT(zx_pll->pd_bit), zx_pll->reg_base); } static int zx_pll_is_enabled(struct clk_hw *hw) @@ -130,10 +130,10 @@ static int zx_pll_is_enabled(struct clk_hw *hw) reg = readl_relaxed(zx_pll->reg_base); - return !(reg & POWER_DOWN); + return !(reg & BIT(zx_pll->pd_bit)); } -static const struct clk_ops zx_pll_ops = { +const struct clk_ops zx_pll_ops = { .recalc_rate = zx_pll_recalc_rate, .round_rate = zx_pll_round_rate, .set_rate = zx_pll_set_rate, @@ -141,6 +141,7 @@ static const struct clk_ops zx_pll_ops = { .disable = zx_pll_disable, .is_enabled = zx_pll_is_enabled, }; +EXPORT_SYMBOL(zx_pll_ops); struct clk *clk_register_zx_pll(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg_base, @@ -164,6 +165,8 @@ struct clk *clk_register_zx_pll(const char *name, const char *parent_name, zx_pll->reg_base = reg_base; zx_pll->lookup_table = lookup_table; zx_pll->count = count; + zx_pll->lock_bit = LOCK_FLAG; + zx_pll->pd_bit = POWER_DOWN; zx_pll->lock = lock; zx_pll->hw.init = &init; diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index 65ae08b..8f6b5f0 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -24,6 +24,8 @@ struct clk_zx_pll { const struct zx_pll_config *lookup_table; /* order by rate asc */ int count; spinlock_t *lock; + u8 pd_bit; /* power down bit */ + u8 lock_bit; /* pll lock flag bit */ }; struct clk *clk_register_zx_pll(const char *name, const char *parent_name, @@ -38,4 +40,6 @@ struct clk_zx_audio { struct clk *clk_register_zx_audio(const char *name, const char * const parent_name, unsigned long flags, void __iomem *reg_base); + +extern const struct clk_ops zx_pll_ops; #endif -- cgit v0.10.2 From ca0233285a93222b2b0c7384b9345711b3d68b5c Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 6 Sep 2016 14:02:42 +0800 Subject: clk: zx: register ZX296718 clocks The ZX296718 clocks are statically listed and registered. More clock will be added later. Signed-off-by: Jun Nie Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/zx296718-clk.txt b/Documentation/devicetree/bindings/clock/zx296718-clk.txt new file mode 100644 index 0000000..8c18b7b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zx296718-clk.txt @@ -0,0 +1,35 @@ +Device Tree Clock bindings for ZTE zx296718 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "zte,zx296718-topcrm": + zx296718 top clock selection, divider and gating + + "zte,zx296718-lsp0crm" and + "zte,zx296718-lsp1crm": + zx296718 device level clock selection and gating + +- reg: Address and length of the register set + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/zx296718-clock.h +for the full list of zx296718 clock IDs. + + +topclk: topcrm@1461000 { + compatible = "zte,zx296718-topcrm-clk"; + reg = <0x01461000 0x1000>; + #clock-cells = <1>; +}; + +usbphy0:usb-phy0 { + compatible = "zte,zx296718-usb-phy"; + #phy-cells = <0>; + clocks = <&topclk USB20_PHY_CLK>; + clock-names = "phyclk"; + status = "okay"; +}; diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile index 74005aa..83374bf 100644 --- a/drivers/clk/zte/Makefile +++ b/drivers/clk/zte/Makefile @@ -1,2 +1,3 @@ obj-y := clk.o obj-$(CONFIG_SOC_ZX296702) += clk-zx296702.o +obj-$(CONFIG_ARCH_ZX) += clk-zx296718.o diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c new file mode 100644 index 0000000..025e324 --- /dev/null +++ b/drivers/clk/zte/clk-zx296718.c @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2015 - 2016 ZTE Corporation. + * Copyright (C) 2016 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. + */ +#include +#include +#include +#include +#include +#include + +#include +#include "clk.h" + +/* TOP CRM */ +#define TOP_CLK_MUX0 0x04 +#define TOP_CLK_MUX1 0x08 +#define TOP_CLK_MUX2 0x0c +#define TOP_CLK_MUX3 0x10 +#define TOP_CLK_MUX4 0x14 +#define TOP_CLK_MUX5 0x18 +#define TOP_CLK_MUX6 0x1c +#define TOP_CLK_MUX7 0x20 +#define TOP_CLK_MUX9 0x28 + + +#define TOP_CLK_GATE0 0x34 +#define TOP_CLK_GATE1 0x38 +#define TOP_CLK_GATE2 0x3c +#define TOP_CLK_GATE3 0x40 +#define TOP_CLK_GATE4 0x44 +#define TOP_CLK_GATE5 0x48 +#define TOP_CLK_GATE6 0x4c + +#define TOP_CLK_DIV0 0x58 + +#define PLL_CPU_REG 0x80 +#define PLL_VGA_REG 0xb0 +#define PLL_DDR_REG 0xa0 + +/* LSP0 CRM */ +#define LSP0_TIMER3_CLK 0x4 +#define LSP0_TIMER4_CLK 0x8 +#define LSP0_TIMER5_CLK 0xc +#define LSP0_UART3_CLK 0x10 +#define LSP0_UART1_CLK 0x14 +#define LSP0_UART2_CLK 0x18 +#define LSP0_SPIFC0_CLK 0x1c +#define LSP0_I2C4_CLK 0x20 +#define LSP0_I2C5_CLK 0x24 +#define LSP0_SSP0_CLK 0x28 +#define LSP0_SSP1_CLK 0x2c +#define LSP0_USIM0_CLK 0x30 +#define LSP0_GPIO_CLK 0x34 +#define LSP0_I2C3_CLK 0x38 + +/* LSP1 CRM */ +#define LSP1_UART4_CLK 0x08 +#define LSP1_UART5_CLK 0x0c +#define LSP1_PWM_CLK 0x10 +#define LSP1_I2C2_CLK 0x14 +#define LSP1_SSP2_CLK 0x1c +#define LSP1_SSP3_CLK 0x20 +#define LSP1_SSP4_CLK 0x24 +#define LSP1_USIM1_CLK 0x28 + +/* audio lsp */ +#define AUDIO_I2S0_DIV_CFG1 0x10 +#define AUDIO_I2S0_DIV_CFG2 0x14 +#define AUDIO_I2S0_CLK 0x18 +#define AUDIO_I2S1_DIV_CFG1 0x20 +#define AUDIO_I2S1_DIV_CFG2 0x24 +#define AUDIO_I2S1_CLK 0x28 +#define AUDIO_I2S2_DIV_CFG1 0x30 +#define AUDIO_I2S2_DIV_CFG2 0x34 +#define AUDIO_I2S2_CLK 0x38 +#define AUDIO_I2S3_DIV_CFG1 0x40 +#define AUDIO_I2S3_DIV_CFG2 0x44 +#define AUDIO_I2S3_CLK 0x48 +#define AUDIO_I2C0_CLK 0x50 +#define AUDIO_SPDIF0_DIV_CFG1 0x60 +#define AUDIO_SPDIF0_DIV_CFG2 0x64 +#define AUDIO_SPDIF0_CLK 0x68 +#define AUDIO_SPDIF1_DIV_CFG1 0x70 +#define AUDIO_SPDIF1_DIV_CFG2 0x74 +#define AUDIO_SPDIF1_CLK 0x78 +#define AUDIO_TIMER_CLK 0x80 +#define AUDIO_TDM_CLK 0x90 +#define AUDIO_TS_CLK 0xa0 + +static DEFINE_SPINLOCK(clk_lock); + +static struct zx_pll_config pll_cpu_table[] = { + PLL_RATE(1312000000, 0x00103621, 0x04aaaaaa), + PLL_RATE(1407000000, 0x00103a21, 0x04aaaaaa), + PLL_RATE(1503000000, 0x00103e21, 0x04aaaaaa), + PLL_RATE(1600000000, 0x00104221, 0x04aaaaaa), +}; + +PNAME(osc) = { + "osc24m", + "osc32k", +}; + +PNAME(dbg_wclk_p) = { + "clk334m", + "clk466m", + "clk396m", + "clk250m", +}; + +PNAME(a72_coreclk_p) = { + "osc24m", + "pll_mm0_1188m", + "pll_mm1_1296m", + "clk1000m", + "clk648m", + "clk1600m", + "pll_audio_1800m", + "pll_vga_1800m", +}; + +PNAME(cpu_periclk_p) = { + "osc24m", + "clk500m", + "clk594m", + "clk466m", + "clk294m", + "clk334m", + "clk250m", + "clk125m", +}; + +PNAME(a53_coreclk_p) = { + "osc24m", + "clk1000m", + "pll_mm0_1188m", + "clk648m", + "clk500m", + "clk800m", + "clk1600m", + "pll_audio_1800m", +}; + +PNAME(sec_wclk_p) = { + "osc24m", + "clk396m", + "clk334m", + "clk297m", + "clk250m", + "clk198m", + "clk148m5", + "clk99m", +}; + +PNAME(sd_nand_wclk_p) = { + "osc24m", + "clk49m5", + "clk99m", + "clk198m", + "clk167m", + "clk148m5", + "clk125m", + "clk216m", +}; + +PNAME(emmc_wclk_p) = { + "osc24m", + "clk198m", + "clk99m", + "clk396m", + "clk334m", + "clk297m", + "clk250m", + "clk148m5", +}; + +PNAME(clk32_p) = { + "osc32k", + "clk32k768", +}; + +PNAME(usb_ref24m_p) = { + "osc32k", + "clk32k768", +}; + +PNAME(sys_noc_alck_p) = { + "osc24m", + "clk250m", + "clk198m", + "clk148m5", + "clk108m", + "clk54m", + "clk216m", + "clk240m", +}; + +PNAME(vde_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk480m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(vce_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(hde_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(gpu_aclk_p) = { + "clk334m", + "clk648m", + "clk594m", + "clk500m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(sappu_aclk_p) = { + "clk396m", + "clk500m", + "clk250m", + "clk148m5", +}; + +PNAME(sappu_wclk_p) = { + "clk198m", + "clk396m", + "clk334m", + "clk297m", + "clk250m", + "clk148m5", + "clk125m", + "clk99m", +}; + +PNAME(vou_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(vou_main_wclk_p) = { + "clk108m", + "clk594m", + "clk297m", + "clk148m5", + "clk74m25", + "clk54m", + "clk27m", + "clk_vga", +}; + +PNAME(vou_aux_wclk_p) = { + "clk108m", + "clk148m5", + "clk74m25", + "clk54m", + "clk27m", + "clk_vga", + "clk54m_mm0", + "clk" +}; + +PNAME(vou_ppu_wclk_p) = { + "clk334m", + "clk432m", + "clk396m", + "clk297m", + "clk250m", + "clk125m", + "clk198m", + "clk99m", +}; + +PNAME(vga_i2c_wclk_p) = { + "osc24m", + "clk99m", +}; + +PNAME(viu_m0_aclk_p) = { + "clk334m", + "clk432m", + "clk396m", + "clk297m", + "clk250m", + "clk125m", + "clk198m", + "osc24m", +}; + +PNAME(viu_m1_aclk_p) = { + "clk198m", + "clk250m", + "clk297m", + "clk125m", + "clk396m", + "clk334m", + "clk148m5", + "osc24m", +}; + +PNAME(viu_clk_p) = { + "clk198m", + "clk334m", + "clk297m", + "clk250m", + "clk396m", + "clk125m", + "clk99m", + "clk148m5", +}; + +PNAME(viu_jpeg_clk_p) = { + "clk334m", + "clk480m", + "clk432m", + "clk396m", + "clk297m", + "clk250m", + "clk125m", + "clk198m", +}; + +PNAME(ts_sys_clk_p) = { + "clk192m", + "clk167m", + "clk125m", + "clk99m", +}; + +PNAME(wdt_ares_p) = { + "osc24m", + "clk32k" +}; + +static struct clk_zx_pll zx296718_pll_clk[] = { + ZX296718_PLL("pll_cpu", "osc24m", PLL_CPU_REG, pll_cpu_table), +}; + +static struct zx_clk_fixed_factor top_ffactor_clk[] = { + FFACTOR(0, "clk4m", "osc24m", 1, 6, 0), + FFACTOR(0, "clk2m", "osc24m", 1, 12, 0), + /* pll cpu */ + FFACTOR(0, "clk1600m", "pll_cpu", 1, 1, CLK_SET_RATE_PARENT), + FFACTOR(0, "clk800m", "pll_cpu", 1, 2, CLK_SET_RATE_PARENT), + /* pll mac */ + FFACTOR(0, "clk25m", "pll_mac", 1, 40, 0), + FFACTOR(0, "clk125m", "pll_mac", 1, 8, 0), + FFACTOR(0, "clk250m", "pll_mac", 1, 4, 0), + FFACTOR(0, "clk50m", "pll_mac", 1, 20, 0), + FFACTOR(0, "clk500m", "pll_mac", 1, 2, 0), + FFACTOR(0, "clk1000m", "pll_mac", 1, 1, 0), + FFACTOR(0, "clk334m", "pll_mac", 1, 3, 0), + FFACTOR(0, "clk167m", "pll_mac", 1, 6, 0), + /* pll mm */ + FFACTOR(0, "clk54m_mm0", "pll_mm0", 1, 22, 0), + FFACTOR(0, "clk74m25", "pll_mm0", 1, 16, 0), + FFACTOR(0, "clk148m5", "pll_mm0", 1, 8, 0), + FFACTOR(0, "clk297m", "pll_mm0", 1, 4, 0), + FFACTOR(0, "clk594m", "pll_mm0", 1, 2, 0), + FFACTOR(0, "pll_mm0_1188m", "pll_mm0", 1, 1, 0), + FFACTOR(0, "clk396m", "pll_mm0", 1, 3, 0), + FFACTOR(0, "clk198m", "pll_mm0", 1, 6, 0), + FFACTOR(0, "clk99m", "pll_mm0", 1, 12, 0), + FFACTOR(0, "clk49m5", "pll_mm0", 1, 24, 0), + /* pll mm */ + FFACTOR(0, "clk324m", "pll_mm1", 1, 4, 0), + FFACTOR(0, "clk648m", "pll_mm1", 1, 2, 0), + FFACTOR(0, "pll_mm1_1296m", "pll_mm1", 1, 1, 0), + FFACTOR(0, "clk216m", "pll_mm1", 1, 6, 0), + FFACTOR(0, "clk432m", "pll_mm1", 1, 3, 0), + FFACTOR(0, "clk108m", "pll_mm1", 1, 12, 0), + FFACTOR(0, "clk72m", "pll_mm1", 1, 18, 0), + FFACTOR(0, "clk27m", "pll_mm1", 1, 48, 0), + FFACTOR(0, "clk54m", "pll_mm1", 1, 24, 0), + /* vga */ + FFACTOR(0, "pll_vga_1800m", "pll_vga", 1, 1, 0), + FFACTOR(0, "clk_vga", "pll_vga", 1, 2, 0), + /* pll ddr */ + FFACTOR(0, "clk466m", "pll_ddr", 1, 2, 0), + + /* pll audio */ + FFACTOR(0, "pll_audio_1800m", "pll_audio", 1, 1, 0), + FFACTOR(0, "clk32k768", "pll_audio", 1, 27000, 0), + FFACTOR(0, "clk16m384", "pll_audio", 1, 54, 0), + FFACTOR(0, "clk294m", "pll_audio", 1, 3, 0), + + /* pll hsic*/ + FFACTOR(0, "clk240m", "pll_hsic", 1, 4, 0), + FFACTOR(0, "clk480m", "pll_hsic", 1, 2, 0), + FFACTOR(0, "clk192m", "pll_hsic", 1, 5, 0), + FFACTOR(0, "clk_pll_24m", "pll_hsic", 1, 40, 0), + FFACTOR(0, "emmc_mux_div2", "emmc_mux", 1, 2, CLK_SET_RATE_PARENT), +}; + +static struct clk_div_table noc_div_table[] = { + { .val = 1, .div = 2, }, + { .val = 3, .div = 4, }, +}; +static struct zx_clk_div top_div_clk[] = { + DIV_T(0, "sys_noc_hclk", "sys_noc_aclk", TOP_CLK_DIV0, 0, 2, 0, noc_div_table), + DIV_T(0, "sys_noc_pclk", "sys_noc_aclk", TOP_CLK_DIV0, 4, 2, 0, noc_div_table), +}; + +static struct zx_clk_mux top_mux_clk[] = { + MUX(0, "dbg_mux", dbg_wclk_p, TOP_CLK_MUX0, 12, 2), + MUX(0, "a72_mux", a72_coreclk_p, TOP_CLK_MUX0, 8, 3), + MUX(0, "cpu_peri_mux", cpu_periclk_p, TOP_CLK_MUX0, 4, 3), + MUX_F(0, "a53_mux", a53_coreclk_p, TOP_CLK_MUX0, 0, 3, CLK_SET_RATE_PARENT, 0), + MUX(0, "sys_noc_aclk", sys_noc_alck_p, TOP_CLK_MUX1, 0, 3), + MUX(0, "sec_mux", sec_wclk_p, TOP_CLK_MUX2, 16, 3), + MUX(0, "sd1_mux", sd_nand_wclk_p, TOP_CLK_MUX2, 12, 3), + MUX(0, "sd0_mux", sd_nand_wclk_p, TOP_CLK_MUX2, 8, 3), + MUX(0, "emmc_mux", emmc_wclk_p, TOP_CLK_MUX2, 4, 3), + MUX(0, "nand_mux", sd_nand_wclk_p, TOP_CLK_MUX2, 0, 3), + MUX(0, "usb_ref24m_mux", usb_ref24m_p, TOP_CLK_MUX9, 16, 1), + MUX(0, "clk32k", clk32_p, TOP_CLK_MUX9, 12, 1), + MUX_F(0, "wdt_mux", wdt_ares_p, TOP_CLK_MUX9, 8, 1, CLK_SET_RATE_PARENT, 0), + MUX(0, "timer_mux", osc, TOP_CLK_MUX9, 4, 1), + MUX(0, "vde_mux", vde_aclk_p, TOP_CLK_MUX4, 0, 3), + MUX(0, "vce_mux", vce_aclk_p, TOP_CLK_MUX4, 4, 3), + MUX(0, "hde_mux", hde_aclk_p, TOP_CLK_MUX4, 8, 3), + MUX(0, "gpu_mux", gpu_aclk_p, TOP_CLK_MUX5, 0, 3), + MUX(0, "sappu_a_mux", sappu_aclk_p, TOP_CLK_MUX5, 4, 2), + MUX(0, "sappu_w_mux", sappu_wclk_p, TOP_CLK_MUX5, 8, 3), + MUX(0, "vou_a_mux", vou_aclk_p, TOP_CLK_MUX7, 0, 3), + MUX(0, "vou_main_w_mux", vou_main_wclk_p, TOP_CLK_MUX7, 4, 3), + MUX(0, "vou_aux_w_mux", vou_aux_wclk_p, TOP_CLK_MUX7, 8, 3), + MUX(0, "vou_ppu_w_mux", vou_ppu_wclk_p, TOP_CLK_MUX7, 12, 3), + MUX(0, "vga_i2c_mux", vga_i2c_wclk_p, TOP_CLK_MUX7, 16, 1), + MUX(0, "viu_m0_a_mux", viu_m0_aclk_p, TOP_CLK_MUX6, 0, 3), + MUX(0, "viu_m1_a_mux", viu_m1_aclk_p, TOP_CLK_MUX6, 4, 3), + MUX(0, "viu_w_mux", viu_clk_p, TOP_CLK_MUX6, 8, 3), + MUX(0, "viu_jpeg_w_mux", viu_jpeg_clk_p, TOP_CLK_MUX6, 12, 3), + MUX(0, "ts_sys_mux", ts_sys_clk_p, TOP_CLK_MUX6, 16, 2), +}; + +static struct zx_clk_gate top_gate_clk[] = { + GATE(CPU_DBG_GATE, "dbg_wclk", "dbg_mux", TOP_CLK_GATE0, 4, CLK_SET_RATE_PARENT, 0), + GATE(A72_GATE, "a72_coreclk", "a72_mux", TOP_CLK_GATE0, 3, CLK_SET_RATE_PARENT, 0), + GATE(CPU_PERI_GATE, "cpu_peri", "cpu_peri_mux", TOP_CLK_GATE0, 1, CLK_SET_RATE_PARENT, 0), + GATE(A53_GATE, "a53_coreclk", "a53_mux", TOP_CLK_GATE0, 0, CLK_SET_RATE_PARENT, 0), + GATE(SD1_WCLK, "sd1_wclk", "sd1_mux", TOP_CLK_GATE1, 13, CLK_SET_RATE_PARENT, 0), + GATE(SD0_WCLK, "sd0_wclk", "sd0_mux", TOP_CLK_GATE1, 9, CLK_SET_RATE_PARENT, 0), + GATE(EMMC_WCLK, "emmc_wclk", "emmc_mux_div2", TOP_CLK_GATE0, 5, CLK_SET_RATE_PARENT, 0), + GATE(EMMC_NAND_AXI, "emmc_nand_aclk", "sys_noc_aclk", TOP_CLK_GATE1, 4, CLK_SET_RATE_PARENT, 0), + GATE(NAND_WCLK, "nand_wclk", "nand_mux", TOP_CLK_GATE0, 1, CLK_SET_RATE_PARENT, 0), + GATE(EMMC_NAND_AHB, "emmc_nand_hclk", "sys_noc_hclk", TOP_CLK_GATE1, 0, CLK_SET_RATE_PARENT, 0), + GATE(0, "lsp1_pclk", "sys_noc_pclk", TOP_CLK_GATE2, 31, 0, 0), + GATE(LSP1_148M5, "lsp1_148m5", "clk148m5", TOP_CLK_GATE2, 30, 0, 0), + GATE(LSP1_99M, "lsp1_99m", "clk99m", TOP_CLK_GATE2, 29, 0, 0), + GATE(LSP1_24M, "lsp1_24m", "osc24m", TOP_CLK_GATE2, 28, 0, 0), + GATE(LSP0_74M25, "lsp0_74m25", "clk74m25", TOP_CLK_GATE2, 25, 0, 0), + GATE(0, "lsp0_pclk", "sys_noc_pclk", TOP_CLK_GATE2, 24, 0, 0), + GATE(LSP0_32K, "lsp0_32k", "osc32k", TOP_CLK_GATE2, 23, 0, 0), + GATE(LSP0_148M5, "lsp0_148m5", "clk148m5", TOP_CLK_GATE2, 22, 0, 0), + GATE(LSP0_99M, "lsp0_99m", "clk99m", TOP_CLK_GATE2, 21, 0, 0), + GATE(LSP0_24M, "lsp0_24m", "osc24m", TOP_CLK_GATE2, 20, 0, 0), + GATE(AUDIO_99M, "audio_99m", "clk99m", TOP_CLK_GATE5, 27, 0, 0), + GATE(AUDIO_24M, "audio_24m", "osc24m", TOP_CLK_GATE5, 28, 0, 0), + GATE(AUDIO_16M384, "audio_16m384", "clk16m384", TOP_CLK_GATE5, 29, 0, 0), + GATE(AUDIO_32K, "audio_32k", "clk32k", TOP_CLK_GATE5, 30, 0, 0), + GATE(WDT_WCLK, "wdt_wclk", "wdt_mux", TOP_CLK_GATE6, 9, CLK_SET_RATE_PARENT, 0), + GATE(TIMER_WCLK, "timer_wclk", "timer_mux", TOP_CLK_GATE6, 5, CLK_SET_RATE_PARENT, 0), + GATE(VDE_ACLK, "vde_aclk", "vde_mux", TOP_CLK_GATE3, 0, CLK_SET_RATE_PARENT, 0), + GATE(VCE_ACLK, "vce_aclk", "vce_mux", TOP_CLK_GATE3, 4, CLK_SET_RATE_PARENT, 0), + GATE(HDE_ACLK, "hde_aclk", "hde_mux", TOP_CLK_GATE3, 8, CLK_SET_RATE_PARENT, 0), + GATE(GPU_ACLK, "gpu_aclk", "gpu_mux", TOP_CLK_GATE3, 16, CLK_SET_RATE_PARENT, 0), + GATE(SAPPU_ACLK, "sappu_aclk", "sappu_a_mux", TOP_CLK_GATE3, 20, CLK_SET_RATE_PARENT, 0), + GATE(SAPPU_WCLK, "sappu_wclk", "sappu_w_mux", TOP_CLK_GATE3, 22, CLK_SET_RATE_PARENT, 0), + GATE(VOU_ACLK, "vou_aclk", "vou_a_mux", TOP_CLK_GATE4, 16, CLK_SET_RATE_PARENT, 0), + GATE(VOU_MAIN_WCLK, "vou_main_wclk", "vou_main_w_mux", TOP_CLK_GATE4, 18, CLK_SET_RATE_PARENT, 0), + GATE(VOU_AUX_WCLK, "vou_aux_wclk", "vou_aux_w_mux", TOP_CLK_GATE4, 19, CLK_SET_RATE_PARENT, 0), + GATE(VOU_PPU_WCLK, "vou_ppu_wclk", "vou_ppu_w_mux", TOP_CLK_GATE4, 20, CLK_SET_RATE_PARENT, 0), + GATE(MIPI_CFG_CLK, "mipi_cfg_clk", "osc24m", TOP_CLK_GATE4, 21, 0, 0), + GATE(VGA_I2C_WCLK, "vga_i2c_wclk", "vga_i2c_mux", TOP_CLK_GATE4, 23, CLK_SET_RATE_PARENT, 0), + GATE(MIPI_REF_CLK, "mipi_ref_clk", "clk27m", TOP_CLK_GATE4, 24, 0, 0), + GATE(HDMI_OSC_CEC, "hdmi_osc_cec", "clk2m", TOP_CLK_GATE4, 22, 0, 0), + GATE(HDMI_OSC_CLK, "hdmi_osc_clk", "clk240m", TOP_CLK_GATE4, 25, 0, 0), + GATE(HDMI_XCLK, "hdmi_xclk", "osc24m", TOP_CLK_GATE4, 26, 0, 0), + GATE(VIU_M0_ACLK, "viu_m0_aclk", "viu_m0_a_mux", TOP_CLK_GATE4, 0, CLK_SET_RATE_PARENT, 0), + GATE(VIU_M1_ACLK, "viu_m1_aclk", "viu_m1_a_mux", TOP_CLK_GATE4, 1, CLK_SET_RATE_PARENT, 0), + GATE(VIU_WCLK, "viu_wclk", "viu_w_mux", TOP_CLK_GATE4, 2, CLK_SET_RATE_PARENT, 0), + GATE(VIU_JPEG_WCLK, "viu_jpeg_wclk", "viu_jpeg_w_mux", TOP_CLK_GATE4, 3, CLK_SET_RATE_PARENT, 0), + GATE(VIU_CFG_CLK, "viu_cfg_clk", "osc24m", TOP_CLK_GATE4, 6, 0, 0), + GATE(TS_SYS_WCLK, "ts_sys_wclk", "ts_sys_mux", TOP_CLK_GATE5, 2, CLK_SET_RATE_PARENT, 0), + GATE(TS_SYS_108M, "ts_sys_108m", "clk108m", TOP_CLK_GATE5, 3, 0, 0), + GATE(USB20_HCLK, "usb20_hclk", "sys_noc_hclk", TOP_CLK_GATE2, 12, 0, 0), + GATE(USB20_PHY_CLK, "usb20_phy_clk", "usb_ref24m_mux", TOP_CLK_GATE2, 13, 0, 0), + GATE(USB21_HCLK, "usb21_hclk", "sys_noc_hclk", TOP_CLK_GATE2, 14, 0, 0), + GATE(USB21_PHY_CLK, "usb21_phy_clk", "usb_ref24m_mux", TOP_CLK_GATE2, 15, 0, 0), + GATE(GMAC_RMIICLK, "gmac_rmii_clk", "clk50m", TOP_CLK_GATE2, 3, 0, 0), + GATE(GMAC_PCLK, "gmac_pclk", "clk198m", TOP_CLK_GATE2, 1, 0, 0), + GATE(GMAC_ACLK, "gmac_aclk", "clk49m5", TOP_CLK_GATE2, 0, 0, 0), + GATE(GMAC_RFCLK, "gmac_refclk", "clk25m", TOP_CLK_GATE2, 4, 0, 0), + GATE(SD1_AHB, "sd1_hclk", "sys_noc_hclk", TOP_CLK_GATE1, 12, 0, 0), + GATE(SD0_AHB, "sd0_hclk", "sys_noc_hclk", TOP_CLK_GATE1, 8, 0, 0), + GATE(TEMPSENSOR_GATE, "tempsensor_gate", "clk4m", TOP_CLK_GATE5, 31, 0, 0), +}; + +static struct clk_hw_onecell_data top_hw_onecell_data = { + .num = TOP_NR_CLKS, + .hws = { + [TOP_NR_CLKS - 1] = NULL, + }, +}; + +static int __init top_clocks_init(struct device_node *np) +{ + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(zx296718_pll_clk); i++) { + zx296718_pll_clk[i].reg_base += (u64)reg_base; + ret = clk_hw_register(NULL, &zx296718_pll_clk[i].hw); + if (ret) { + pr_warn("top clk %s init error!\n", + zx296718_pll_clk[i].hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_ffactor_clk); i++) { + if (top_ffactor_clk[i].id) + top_hw_onecell_data.hws[top_ffactor_clk[i].id] = + &top_ffactor_clk[i].factor.hw; + + ret = clk_hw_register(NULL, &top_ffactor_clk[i].factor.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_ffactor_clk[i].factor.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_mux_clk); i++) { + if (top_mux_clk[i].id) + top_hw_onecell_data.hws[top_mux_clk[i].id] = + &top_mux_clk[i].mux.hw; + + top_mux_clk[i].mux.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &top_mux_clk[i].mux.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_mux_clk[i].mux.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_gate_clk); i++) { + if (top_gate_clk[i].id) + top_hw_onecell_data.hws[top_gate_clk[i].id] = + &top_gate_clk[i].gate.hw; + + top_gate_clk[i].gate.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &top_gate_clk[i].gate.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_gate_clk[i].gate.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_div_clk); i++) { + if (top_div_clk[i].id) + top_hw_onecell_data.hws[top_div_clk[i].id] = + &top_div_clk[i].div.hw; + + top_div_clk[i].div.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &top_div_clk[i].div.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_div_clk[i].div.hw.init->name); + } + } + + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &top_hw_onecell_data)) + panic("could not register clk provider\n"); + pr_info("top clk init over, nr:%d\n", TOP_NR_CLKS); + + return 0; +} + +static struct clk_div_table common_even_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 3, .div = 4, }, + { .val = 5, .div = 6, }, + { .val = 7, .div = 8, }, + { .val = 9, .div = 10, }, + { .val = 11, .div = 12, }, + { .val = 13, .div = 14, }, + { .val = 15, .div = 16, }, +}; + +static struct clk_div_table common_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 3, }, + { .val = 3, .div = 4, }, + { .val = 4, .div = 5, }, + { .val = 5, .div = 6, }, + { .val = 6, .div = 7, }, + { .val = 7, .div = 8, }, + { .val = 8, .div = 9, }, + { .val = 9, .div = 10, }, + { .val = 10, .div = 11, }, + { .val = 11, .div = 12, }, + { .val = 12, .div = 13, }, + { .val = 13, .div = 14, }, + { .val = 14, .div = 15, }, + { .val = 15, .div = 16, }, +}; + +PNAME(lsp0_wclk_common_p) = { + "lsp0_24m", + "lsp0_99m", +}; + +PNAME(lsp0_wclk_timer3_p) = { + "timer3_div", + "lsp0_32k" +}; + +PNAME(lsp0_wclk_timer4_p) = { + "timer4_div", + "lsp0_32k" +}; + +PNAME(lsp0_wclk_timer5_p) = { + "timer5_div", + "lsp0_32k" +}; + +PNAME(lsp0_wclk_spifc0_p) = { + "lsp0_148m5", + "lsp0_24m", + "lsp0_99m", + "lsp0_74m25" +}; + +PNAME(lsp0_wclk_ssp_p) = { + "lsp0_148m5", + "lsp0_99m", + "lsp0_24m", +}; + +static struct zx_clk_mux lsp0_mux_clk[] = { + MUX(0, "timer3_wclk_mux", lsp0_wclk_timer3_p, LSP0_TIMER3_CLK, 4, 1), + MUX(0, "timer4_wclk_mux", lsp0_wclk_timer4_p, LSP0_TIMER4_CLK, 4, 1), + MUX(0, "timer5_wclk_mux", lsp0_wclk_timer5_p, LSP0_TIMER5_CLK, 4, 1), + MUX(0, "uart3_wclk_mux", lsp0_wclk_common_p, LSP0_UART3_CLK, 4, 1), + MUX(0, "uart1_wclk_mux", lsp0_wclk_common_p, LSP0_UART1_CLK, 4, 1), + MUX(0, "uart2_wclk_mux", lsp0_wclk_common_p, LSP0_UART2_CLK, 4, 1), + MUX(0, "spifc0_wclk_mux", lsp0_wclk_spifc0_p, LSP0_SPIFC0_CLK, 4, 2), + MUX(0, "i2c4_wclk_mux", lsp0_wclk_common_p, LSP0_I2C4_CLK, 4, 1), + MUX(0, "i2c5_wclk_mux", lsp0_wclk_common_p, LSP0_I2C5_CLK, 4, 1), + MUX(0, "ssp0_wclk_mux", lsp0_wclk_ssp_p, LSP0_SSP0_CLK, 4, 1), + MUX(0, "ssp1_wclk_mux", lsp0_wclk_ssp_p, LSP0_SSP1_CLK, 4, 1), + MUX(0, "i2c3_wclk_mux", lsp0_wclk_common_p, LSP0_I2C3_CLK, 4, 1), +}; + +static struct zx_clk_gate lsp0_gate_clk[] = { + GATE(LSP0_TIMER3_WCLK, "timer3_wclk", "timer3_wclk_mux", LSP0_TIMER3_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_TIMER4_WCLK, "timer4_wclk", "timer4_wclk_mux", LSP0_TIMER4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_TIMER5_WCLK, "timer5_wclk", "timer5_wclk_mux", LSP0_TIMER5_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_UART3_WCLK, "uart3_wclk", "uart3_wclk_mux", LSP0_UART3_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_UART1_WCLK, "uart1_wclk", "uart1_wclk_mux", LSP0_UART1_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_UART2_WCLK, "uart2_wclk", "uart2_wclk_mux", LSP0_UART2_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_SPIFC0_WCLK, "spifc0_wclk", "spifc0_wclk_mux", LSP0_SPIFC0_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_I2C4_WCLK, "i2c4_wclk", "i2c4_wclk_mux", LSP0_I2C4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_I2C5_WCLK, "i2c5_wclk", "i2c5_wclk_mux", LSP0_I2C5_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_SSP0_WCLK, "ssp0_wclk", "ssp0_div", LSP0_SSP0_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_SSP1_WCLK, "ssp1_wclk", "ssp1_div", LSP0_SSP1_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_I2C3_WCLK, "i2c3_wclk", "i2c3_wclk_mux", LSP0_I2C3_CLK, 1, CLK_SET_RATE_PARENT, 0), +}; + +static struct zx_clk_div lsp0_div_clk[] = { + DIV_T(0, "timer3_div", "lsp0_24m", LSP0_TIMER3_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "timer4_div", "lsp0_24m", LSP0_TIMER4_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "timer5_div", "lsp0_24m", LSP0_TIMER5_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "ssp0_div", "ssp0_wclk_mux", LSP0_SSP0_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "ssp1_div", "ssp1_wclk_mux", LSP0_SSP1_CLK, 12, 4, 0, common_even_div_table), +}; + +static struct clk_hw_onecell_data lsp0_hw_onecell_data = { + .num = LSP0_NR_CLKS, + .hws = { + [LSP0_NR_CLKS - 1] = NULL, + }, +}; + +static int __init lsp0_clocks_init(struct device_node *np) +{ + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(lsp0_mux_clk); i++) { + if (lsp0_mux_clk[i].id) + lsp0_hw_onecell_data.hws[lsp0_mux_clk[i].id] = + &lsp0_mux_clk[i].mux.hw; + + lsp0_mux_clk[i].mux.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp0_mux_clk[i].mux.hw); + if (ret) { + pr_warn("lsp0 clk %s init error!\n", + lsp0_mux_clk[i].mux.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp0_gate_clk); i++) { + if (lsp0_gate_clk[i].id) + lsp0_hw_onecell_data.hws[lsp0_gate_clk[i].id] = + &lsp0_gate_clk[i].gate.hw; + + lsp0_gate_clk[i].gate.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp0_gate_clk[i].gate.hw); + if (ret) { + pr_warn("lsp0 clk %s init error!\n", + lsp0_gate_clk[i].gate.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp0_div_clk); i++) { + if (lsp0_div_clk[i].id) + lsp0_hw_onecell_data.hws[lsp0_div_clk[i].id] = + &lsp0_div_clk[i].div.hw; + + lsp0_div_clk[i].div.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp0_div_clk[i].div.hw); + if (ret) { + pr_warn("lsp0 clk %s init error!\n", + lsp0_div_clk[i].div.hw.init->name); + } + } + + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp0_hw_onecell_data)) + panic("could not register clk provider\n"); + pr_info("lsp0-clk init over:%d\n", LSP0_NR_CLKS); + + return 0; +} + +PNAME(lsp1_wclk_common_p) = { + "lsp1_24m", + "lsp1_99m", +}; + +PNAME(lsp1_wclk_ssp_p) = { + "lsp1_148m5", + "lsp1_99m", + "lsp1_24m", +}; + +static struct zx_clk_mux lsp1_mux_clk[] = { + MUX(0, "uart4_wclk_mux", lsp1_wclk_common_p, LSP1_UART4_CLK, 4, 1), + MUX(0, "uart5_wclk_mux", lsp1_wclk_common_p, LSP1_UART5_CLK, 4, 1), + MUX(0, "pwm_wclk_mux", lsp1_wclk_common_p, LSP1_PWM_CLK, 4, 1), + MUX(0, "i2c2_wclk_mux", lsp1_wclk_common_p, LSP1_I2C2_CLK, 4, 1), + MUX(0, "ssp2_wclk_mux", lsp1_wclk_ssp_p, LSP1_SSP2_CLK, 4, 2), + MUX(0, "ssp3_wclk_mux", lsp1_wclk_ssp_p, LSP1_SSP3_CLK, 4, 2), + MUX(0, "ssp4_wclk_mux", lsp1_wclk_ssp_p, LSP1_SSP4_CLK, 4, 2), + MUX(0, "usim1_wclk_mux", lsp1_wclk_common_p, LSP1_USIM1_CLK, 4, 1), +}; + +static struct zx_clk_div lsp1_div_clk[] = { + DIV_T(0, "pwm_div", "pwm_wclk_mux", LSP1_PWM_CLK, 12, 4, CLK_SET_RATE_PARENT, common_div_table), + DIV_T(0, "ssp2_div", "ssp2_wclk_mux", LSP1_SSP2_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table), + DIV_T(0, "ssp3_div", "ssp3_wclk_mux", LSP1_SSP3_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table), + DIV_T(0, "ssp4_div", "ssp4_wclk_mux", LSP1_SSP4_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table), +}; + +static struct zx_clk_gate lsp1_gate_clk[] = { + GATE(LSP1_UART4_WCLK, "lsp1_uart4_wclk", "uart4_wclk_mux", LSP1_UART4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_UART5_WCLK, "lsp1_uart5_wclk", "uart5_wclk_mux", LSP1_UART5_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_PWM_WCLK, "lsp1_pwm_wclk", "pwm_div", LSP1_PWM_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_PWM_PCLK, "lsp1_pwm_pclk", "lsp1_pclk", LSP1_PWM_CLK, 0, 0, 0), + GATE(LSP1_I2C2_WCLK, "lsp1_i2c2_wclk", "i2c2_wclk_mux", LSP1_I2C2_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_SSP2_WCLK, "lsp1_ssp2_wclk", "ssp2_div", LSP1_SSP2_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_SSP3_WCLK, "lsp1_ssp3_wclk", "ssp3_div", LSP1_SSP3_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_SSP4_WCLK, "lsp1_ssp4_wclk", "ssp4_div", LSP1_SSP4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_USIM1_WCLK, "lsp1_usim1_wclk", "usim1_wclk_mux", LSP1_USIM1_CLK, 1, CLK_SET_RATE_PARENT, 0), +}; + +static struct clk_hw_onecell_data lsp1_hw_onecell_data = { + .num = LSP1_NR_CLKS, + .hws = { + [LSP1_NR_CLKS - 1] = NULL, + }, +}; + +static int __init lsp1_clocks_init(struct device_node *np) +{ + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(lsp1_mux_clk); i++) { + if (lsp1_mux_clk[i].id) + lsp1_hw_onecell_data.hws[lsp1_mux_clk[i].id] = + &lsp0_mux_clk[i].mux.hw; + + lsp1_mux_clk[i].mux.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp1_mux_clk[i].mux.hw); + if (ret) { + pr_warn("lsp1 clk %s init error!\n", + lsp1_mux_clk[i].mux.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp1_gate_clk); i++) { + if (lsp1_gate_clk[i].id) + lsp1_hw_onecell_data.hws[lsp1_gate_clk[i].id] = + &lsp1_gate_clk[i].gate.hw; + + lsp1_gate_clk[i].gate.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp1_gate_clk[i].gate.hw); + if (ret) { + pr_warn("lsp1 clk %s init error!\n", + lsp1_gate_clk[i].gate.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp1_div_clk); i++) { + if (lsp1_div_clk[i].id) + lsp1_hw_onecell_data.hws[lsp1_div_clk[i].id] = + &lsp1_div_clk[i].div.hw; + + lsp1_div_clk[i].div.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp1_div_clk[i].div.hw); + if (ret) { + pr_warn("lsp1 clk %s init error!\n", + lsp1_div_clk[i].div.hw.init->name); + } + } + + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp1_hw_onecell_data)) + panic("could not register clk provider\n"); + pr_info("lsp1-clk init over, nr:%d\n", LSP1_NR_CLKS); + + return 0; +} + +static const struct of_device_id zx_clkc_match_table[] = { + { .compatible = "zte,zx296718-topcrm", .data = &top_clocks_init }, + { .compatible = "zte,zx296718-lsp0crm", .data = &lsp0_clocks_init }, + { .compatible = "zte,zx296718-lsp1crm", .data = &lsp1_clocks_init }, + { } +}; + +static int zx_clkc_probe(struct platform_device *pdev) +{ + int (*init_fn)(struct device_node *np); + struct device_node *np = pdev->dev.of_node; + + init_fn = of_device_get_match_data(&pdev->dev); + if (!init_fn) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + + return init_fn(np); +} + +static struct platform_driver zx_clk_driver = { + .probe = zx_clkc_probe, + .driver = { + .name = "zx296718-clkc", + .of_match_table = zx_clkc_match_table, + }, +}; + +static int __init zx_clkc_init(void) +{ + return platform_driver_register(&zx_clk_driver); +} +device_initcall(zx_clkc_init); diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index 8f6b5f0..0df3474 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -12,6 +12,26 @@ #include #include +#define PNAME(x) static const char *x[] + +#define CLK_HW_INIT(_name, _parent, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = (const char *[]) { _parent }, \ + .num_parents = 1, \ + .ops = _ops, \ + } + +#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .ops = _ops, \ + } + struct zx_pll_config { unsigned long rate; u32 cfg0; @@ -28,6 +48,111 @@ struct clk_zx_pll { u8 lock_bit; /* pll lock flag bit */ }; +#define PLL_RATE(_rate, _cfg0, _cfg1) \ +{ \ + .rate = _rate, \ + .cfg0 = _cfg0, \ + .cfg1 = _cfg1, \ +} + +#define ZX_PLL(_name, _parent, _reg, _table, _pd, _lock) \ +{ \ + .reg_base = (void __iomem *) _reg, \ + .lookup_table = _table, \ + .count = ARRAY_SIZE(_table), \ + .pd_bit = _pd, \ + .lock_bit = _lock, \ + .hw.init = CLK_HW_INIT(_name, _parent, &zx_pll_ops, \ + CLK_GET_RATE_NOCACHE), \ +} + +#define ZX296718_PLL(_name, _parent, _reg, _table) \ +ZX_PLL(_name, _parent, _reg, _table, 0, 30) + +struct zx_clk_gate { + struct clk_gate gate; + u16 id; +}; + +#define GATE(_id, _name, _parent, _reg, _bit, _flag, _gflags) \ +{ \ + .gate = { \ + .reg = (void __iomem *) _reg, \ + .bit_idx = (_bit), \ + .flags = _gflags, \ + .lock = &clk_lock, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &clk_gate_ops, \ + _flag | CLK_IGNORE_UNUSED), \ + }, \ + .id = _id, \ +} + +struct zx_clk_fixed_factor { + struct clk_fixed_factor factor; + u16 id; +}; + +#define FFACTOR(_id, _name, _parent, _mult, _div, _flag) \ +{ \ + .factor = { \ + .div = _div, \ + .mult = _mult, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &clk_fixed_factor_ops, \ + _flag), \ + }, \ + .id = _id, \ +} + +struct zx_clk_mux { + struct clk_mux mux; + u16 id; +}; + +#define MUX_F(_id, _name, _parent, _reg, _shift, _width, _flag, _mflag) \ +{ \ + .mux = { \ + .reg = (void __iomem *) _reg, \ + .mask = BIT(_width) - 1, \ + .shift = _shift, \ + .flags = _mflag, \ + .lock = &clk_lock, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parent, \ + &clk_mux_ops, \ + _flag), \ + }, \ + .id = _id, \ +} + +#define MUX(_id, _name, _parent, _reg, _shift, _width) \ +MUX_F(_id, _name, _parent, _reg, _shift, _width, 0, 0) + +struct zx_clk_div { + struct clk_divider div; + u16 id; +}; + +#define DIV_T(_id, _name, _parent, _reg, _shift, _width, _flag, _table) \ +{ \ + .div = { \ + .reg = (void __iomem *) _reg, \ + .shift = _shift, \ + .width = _width, \ + .flags = 0, \ + .table = _table, \ + .lock = &clk_lock, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &clk_divider_ops, \ + _flag), \ + }, \ + .id = _id, \ +} + struct clk *clk_register_zx_pll(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg_base, const struct zx_pll_config *lookup_table, int count, spinlock_t *lock); diff --git a/include/dt-bindings/clock/zx296718-clock.h b/include/dt-bindings/clock/zx296718-clock.h new file mode 100644 index 0000000..822d523 --- /dev/null +++ b/include/dt-bindings/clock/zx296718-clock.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2015 - 2016 ZTE Corporation. + * + * 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. + */ +#ifndef __DT_BINDINGS_CLOCK_ZX296718_H +#define __DT_BINDINGS_CLOCK_ZX296718_H + +/* PLL */ +#define ZX296718_PLL_CPU 1 +#define ZX296718_PLL_MAC 2 +#define ZX296718_PLL_MM0 3 +#define ZX296718_PLL_MM1 4 +#define ZX296718_PLL_VGA 5 +#define ZX296718_PLL_DDR 6 +#define ZX296718_PLL_AUDIO 7 +#define ZX296718_PLL_HSIC 8 +#define CPU_DBG_GATE 9 +#define A72_GATE 10 +#define CPU_PERI_GATE 11 +#define A53_GATE 12 +#define DDR1_GATE 13 +#define DDR0_GATE 14 +#define SD1_WCLK 15 +#define SD1_AHB 16 +#define SD0_WCLK 17 +#define SD0_AHB 18 +#define EMMC_WCLK 19 +#define EMMC_NAND_AXI 20 +#define NAND_WCLK 21 +#define EMMC_NAND_AHB 22 +#define LSP1_148M5 23 +#define LSP1_99M 24 +#define LSP1_24M 25 +#define LSP0_74M25 26 +#define LSP0_32K 27 +#define LSP0_148M5 28 +#define LSP0_99M 29 +#define LSP0_24M 30 +#define DEMUX_AXI 31 +#define DEMUX_APB 32 +#define DEMUX_148M5 33 +#define DEMUX_108M 34 +#define AUDIO_APB 35 +#define AUDIO_99M 36 +#define AUDIO_24M 37 +#define AUDIO_16M384 38 +#define AUDIO_32K 39 +#define WDT_WCLK 40 +#define TIMER_WCLK 41 +#define VDE_ACLK 42 +#define VCE_ACLK 43 +#define HDE_ACLK 44 +#define GPU_ACLK 45 +#define SAPPU_ACLK 46 +#define SAPPU_WCLK 47 +#define VOU_ACLK 48 +#define VOU_MAIN_WCLK 49 +#define VOU_AUX_WCLK 50 +#define VOU_PPU_WCLK 51 +#define MIPI_CFG_CLK 52 +#define VGA_I2C_WCLK 53 +#define MIPI_REF_CLK 54 +#define HDMI_OSC_CEC 55 +#define HDMI_OSC_CLK 56 +#define HDMI_XCLK 57 +#define VIU_M0_ACLK 58 +#define VIU_M1_ACLK 59 +#define VIU_WCLK 60 +#define VIU_JPEG_WCLK 61 +#define VIU_CFG_CLK 62 +#define TS_SYS_WCLK 63 +#define TS_SYS_108M 64 +#define USB20_HCLK 65 +#define USB20_PHY_CLK 66 +#define USB21_HCLK 67 +#define USB21_PHY_CLK 68 +#define GMAC_RMIICLK 69 +#define GMAC_PCLK 70 +#define GMAC_ACLK 71 +#define GMAC_RFCLK 72 +#define TEMPSENSOR_GATE 73 + +#define TOP_NR_CLKS 74 + + +#define LSP0_TIMER3_PCLK 1 +#define LSP0_TIMER3_WCLK 2 +#define LSP0_TIMER4_PCLK 3 +#define LSP0_TIMER4_WCLK 4 +#define LSP0_TIMER5_PCLK 5 +#define LSP0_TIMER5_WCLK 6 +#define LSP0_UART3_PCLK 7 +#define LSP0_UART3_WCLK 8 +#define LSP0_UART1_PCLK 9 +#define LSP0_UART1_WCLK 10 +#define LSP0_UART2_PCLK 11 +#define LSP0_UART2_WCLK 12 +#define LSP0_SPIFC0_PCLK 13 +#define LSP0_SPIFC0_WCLK 14 +#define LSP0_I2C4_PCLK 15 +#define LSP0_I2C4_WCLK 16 +#define LSP0_I2C5_PCLK 17 +#define LSP0_I2C5_WCLK 18 +#define LSP0_SSP0_PCLK 19 +#define LSP0_SSP0_WCLK 20 +#define LSP0_SSP1_PCLK 21 +#define LSP0_SSP1_WCLK 22 +#define LSP0_USIM_PCLK 23 +#define LSP0_USIM_WCLK 24 +#define LSP0_GPIO_PCLK 25 +#define LSP0_GPIO_WCLK 26 +#define LSP0_I2C3_PCLK 27 +#define LSP0_I2C3_WCLK 28 + +#define LSP0_NR_CLKS 29 + + +#define LSP1_UART4_PCLK 1 +#define LSP1_UART4_WCLK 2 +#define LSP1_UART5_PCLK 3 +#define LSP1_UART5_WCLK 4 +#define LSP1_PWM_PCLK 5 +#define LSP1_PWM_WCLK 6 +#define LSP1_I2C2_PCLK 7 +#define LSP1_I2C2_WCLK 8 +#define LSP1_SSP2_PCLK 9 +#define LSP1_SSP2_WCLK 10 +#define LSP1_SSP3_PCLK 11 +#define LSP1_SSP3_WCLK 12 +#define LSP1_SSP4_PCLK 13 +#define LSP1_SSP4_WCLK 14 +#define LSP1_USIM1_PCLK 15 +#define LSP1_USIM1_WCLK 16 + +#define LSP1_NR_CLKS 17 + + +#define AUDIO_I2S0_WCLK 1 +#define AUDIO_I2S0_PCLK 2 +#define AUDIO_I2S1_WCLK 3 +#define AUDIO_I2S1_PCLK 4 +#define AUDIO_I2S2_WCLK 5 +#define AUDIO_I2S2_PCLK 6 +#define AUDIO_I2S3_WCLK 7 +#define AUDIO_I2S3_PCLK 8 +#define AUDIO_I2C0_WCLK 9 +#define AUDIO_I2C0_PCLK 10 +#define AUDIO_SPDIF0_WCLK 11 +#define AUDIO_SPDIF0_PCLK 12 +#define AUDIO_SPDIF1_WCLK 13 +#define AUDIO_SPDIF1_PCLK 14 +#define AUDIO_TIMER_WCLK 15 +#define AUDIO_TIMER_PCLK 16 +#define AUDIO_TDM_WCLK 17 +#define AUDIO_TDM_PCLK 18 +#define AUDIO_TS_PCLK 19 + +#define AUDIO_NR_CLKS 20 + +#endif -- cgit v0.10.2 From e9f262314ebf2cbe466afe74338e8d6c4c9b8897 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 6 Sep 2016 14:02:41 +0800 Subject: clk: zx: reform pll config info to ease code extension Add power down bit and pll lock bit in pll config structure to ease new SoC support. Signed-off-by: Jun Nie Signed-off-by: Stephen Boyd diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c index 7c73c53..c4c1251 100644 --- a/drivers/clk/zte/clk.c +++ b/drivers/clk/zte/clk.c @@ -21,8 +21,8 @@ #define to_clk_zx_audio(_hw) container_of(_hw, struct clk_zx_audio, hw) #define CFG0_CFG1_OFFSET 4 -#define LOCK_FLAG BIT(30) -#define POWER_DOWN BIT(31) +#define LOCK_FLAG 30 +#define POWER_DOWN 31 static int rate_to_idx(struct clk_zx_pll *zx_pll, unsigned long rate) { @@ -50,8 +50,8 @@ static int hw_to_idx(struct clk_zx_pll *zx_pll) hw_cfg1 = readl_relaxed(zx_pll->reg_base + CFG0_CFG1_OFFSET); /* For matching the value in lookup table */ - hw_cfg0 &= ~LOCK_FLAG; - hw_cfg0 |= POWER_DOWN; + hw_cfg0 &= ~BIT(zx_pll->lock_bit); + hw_cfg0 |= BIT(zx_pll->pd_bit); for (i = 0; i < zx_pll->count; i++) { if (hw_cfg0 == config[i].cfg0 && hw_cfg1 == config[i].cfg1) @@ -108,10 +108,10 @@ static int zx_pll_enable(struct clk_hw *hw) u32 reg; reg = readl_relaxed(zx_pll->reg_base); - writel_relaxed(reg & ~POWER_DOWN, zx_pll->reg_base); + writel_relaxed(reg & ~BIT(zx_pll->pd_bit), zx_pll->reg_base); return readl_relaxed_poll_timeout(zx_pll->reg_base, reg, - reg & LOCK_FLAG, 0, 100); + reg & BIT(zx_pll->lock_bit), 0, 100); } static void zx_pll_disable(struct clk_hw *hw) @@ -120,7 +120,7 @@ static void zx_pll_disable(struct clk_hw *hw) u32 reg; reg = readl_relaxed(zx_pll->reg_base); - writel_relaxed(reg | POWER_DOWN, zx_pll->reg_base); + writel_relaxed(reg | BIT(zx_pll->pd_bit), zx_pll->reg_base); } static int zx_pll_is_enabled(struct clk_hw *hw) @@ -130,10 +130,10 @@ static int zx_pll_is_enabled(struct clk_hw *hw) reg = readl_relaxed(zx_pll->reg_base); - return !(reg & POWER_DOWN); + return !(reg & BIT(zx_pll->pd_bit)); } -static const struct clk_ops zx_pll_ops = { +const struct clk_ops zx_pll_ops = { .recalc_rate = zx_pll_recalc_rate, .round_rate = zx_pll_round_rate, .set_rate = zx_pll_set_rate, @@ -141,6 +141,7 @@ static const struct clk_ops zx_pll_ops = { .disable = zx_pll_disable, .is_enabled = zx_pll_is_enabled, }; +EXPORT_SYMBOL(zx_pll_ops); struct clk *clk_register_zx_pll(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg_base, @@ -164,6 +165,8 @@ struct clk *clk_register_zx_pll(const char *name, const char *parent_name, zx_pll->reg_base = reg_base; zx_pll->lookup_table = lookup_table; zx_pll->count = count; + zx_pll->lock_bit = LOCK_FLAG; + zx_pll->pd_bit = POWER_DOWN; zx_pll->lock = lock; zx_pll->hw.init = &init; diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index 65ae08b..8f6b5f0 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -24,6 +24,8 @@ struct clk_zx_pll { const struct zx_pll_config *lookup_table; /* order by rate asc */ int count; spinlock_t *lock; + u8 pd_bit; /* power down bit */ + u8 lock_bit; /* pll lock flag bit */ }; struct clk *clk_register_zx_pll(const char *name, const char *parent_name, @@ -38,4 +40,6 @@ struct clk_zx_audio { struct clk *clk_register_zx_audio(const char *name, const char * const parent_name, unsigned long flags, void __iomem *reg_base); + +extern const struct clk_ops zx_pll_ops; #endif -- cgit v0.10.2 From f31a3433ab5bae61f7626f45536a3e2b7a8f5a45 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 6 Sep 2016 14:02:42 +0800 Subject: clk: zx: register ZX296718 clocks The ZX296718 clocks are statically listed and registered. More clock will be added later. Signed-off-by: Jun Nie Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/zx296718-clk.txt b/Documentation/devicetree/bindings/clock/zx296718-clk.txt new file mode 100644 index 0000000..8c18b7b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zx296718-clk.txt @@ -0,0 +1,35 @@ +Device Tree Clock bindings for ZTE zx296718 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "zte,zx296718-topcrm": + zx296718 top clock selection, divider and gating + + "zte,zx296718-lsp0crm" and + "zte,zx296718-lsp1crm": + zx296718 device level clock selection and gating + +- reg: Address and length of the register set + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/zx296718-clock.h +for the full list of zx296718 clock IDs. + + +topclk: topcrm@1461000 { + compatible = "zte,zx296718-topcrm-clk"; + reg = <0x01461000 0x1000>; + #clock-cells = <1>; +}; + +usbphy0:usb-phy0 { + compatible = "zte,zx296718-usb-phy"; + #phy-cells = <0>; + clocks = <&topclk USB20_PHY_CLK>; + clock-names = "phyclk"; + status = "okay"; +}; diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile index 74005aa..83374bf 100644 --- a/drivers/clk/zte/Makefile +++ b/drivers/clk/zte/Makefile @@ -1,2 +1,3 @@ obj-y := clk.o obj-$(CONFIG_SOC_ZX296702) += clk-zx296702.o +obj-$(CONFIG_ARCH_ZX) += clk-zx296718.o diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c new file mode 100644 index 0000000..025e324 --- /dev/null +++ b/drivers/clk/zte/clk-zx296718.c @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2015 - 2016 ZTE Corporation. + * Copyright (C) 2016 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. + */ +#include +#include +#include +#include +#include +#include + +#include +#include "clk.h" + +/* TOP CRM */ +#define TOP_CLK_MUX0 0x04 +#define TOP_CLK_MUX1 0x08 +#define TOP_CLK_MUX2 0x0c +#define TOP_CLK_MUX3 0x10 +#define TOP_CLK_MUX4 0x14 +#define TOP_CLK_MUX5 0x18 +#define TOP_CLK_MUX6 0x1c +#define TOP_CLK_MUX7 0x20 +#define TOP_CLK_MUX9 0x28 + + +#define TOP_CLK_GATE0 0x34 +#define TOP_CLK_GATE1 0x38 +#define TOP_CLK_GATE2 0x3c +#define TOP_CLK_GATE3 0x40 +#define TOP_CLK_GATE4 0x44 +#define TOP_CLK_GATE5 0x48 +#define TOP_CLK_GATE6 0x4c + +#define TOP_CLK_DIV0 0x58 + +#define PLL_CPU_REG 0x80 +#define PLL_VGA_REG 0xb0 +#define PLL_DDR_REG 0xa0 + +/* LSP0 CRM */ +#define LSP0_TIMER3_CLK 0x4 +#define LSP0_TIMER4_CLK 0x8 +#define LSP0_TIMER5_CLK 0xc +#define LSP0_UART3_CLK 0x10 +#define LSP0_UART1_CLK 0x14 +#define LSP0_UART2_CLK 0x18 +#define LSP0_SPIFC0_CLK 0x1c +#define LSP0_I2C4_CLK 0x20 +#define LSP0_I2C5_CLK 0x24 +#define LSP0_SSP0_CLK 0x28 +#define LSP0_SSP1_CLK 0x2c +#define LSP0_USIM0_CLK 0x30 +#define LSP0_GPIO_CLK 0x34 +#define LSP0_I2C3_CLK 0x38 + +/* LSP1 CRM */ +#define LSP1_UART4_CLK 0x08 +#define LSP1_UART5_CLK 0x0c +#define LSP1_PWM_CLK 0x10 +#define LSP1_I2C2_CLK 0x14 +#define LSP1_SSP2_CLK 0x1c +#define LSP1_SSP3_CLK 0x20 +#define LSP1_SSP4_CLK 0x24 +#define LSP1_USIM1_CLK 0x28 + +/* audio lsp */ +#define AUDIO_I2S0_DIV_CFG1 0x10 +#define AUDIO_I2S0_DIV_CFG2 0x14 +#define AUDIO_I2S0_CLK 0x18 +#define AUDIO_I2S1_DIV_CFG1 0x20 +#define AUDIO_I2S1_DIV_CFG2 0x24 +#define AUDIO_I2S1_CLK 0x28 +#define AUDIO_I2S2_DIV_CFG1 0x30 +#define AUDIO_I2S2_DIV_CFG2 0x34 +#define AUDIO_I2S2_CLK 0x38 +#define AUDIO_I2S3_DIV_CFG1 0x40 +#define AUDIO_I2S3_DIV_CFG2 0x44 +#define AUDIO_I2S3_CLK 0x48 +#define AUDIO_I2C0_CLK 0x50 +#define AUDIO_SPDIF0_DIV_CFG1 0x60 +#define AUDIO_SPDIF0_DIV_CFG2 0x64 +#define AUDIO_SPDIF0_CLK 0x68 +#define AUDIO_SPDIF1_DIV_CFG1 0x70 +#define AUDIO_SPDIF1_DIV_CFG2 0x74 +#define AUDIO_SPDIF1_CLK 0x78 +#define AUDIO_TIMER_CLK 0x80 +#define AUDIO_TDM_CLK 0x90 +#define AUDIO_TS_CLK 0xa0 + +static DEFINE_SPINLOCK(clk_lock); + +static struct zx_pll_config pll_cpu_table[] = { + PLL_RATE(1312000000, 0x00103621, 0x04aaaaaa), + PLL_RATE(1407000000, 0x00103a21, 0x04aaaaaa), + PLL_RATE(1503000000, 0x00103e21, 0x04aaaaaa), + PLL_RATE(1600000000, 0x00104221, 0x04aaaaaa), +}; + +PNAME(osc) = { + "osc24m", + "osc32k", +}; + +PNAME(dbg_wclk_p) = { + "clk334m", + "clk466m", + "clk396m", + "clk250m", +}; + +PNAME(a72_coreclk_p) = { + "osc24m", + "pll_mm0_1188m", + "pll_mm1_1296m", + "clk1000m", + "clk648m", + "clk1600m", + "pll_audio_1800m", + "pll_vga_1800m", +}; + +PNAME(cpu_periclk_p) = { + "osc24m", + "clk500m", + "clk594m", + "clk466m", + "clk294m", + "clk334m", + "clk250m", + "clk125m", +}; + +PNAME(a53_coreclk_p) = { + "osc24m", + "clk1000m", + "pll_mm0_1188m", + "clk648m", + "clk500m", + "clk800m", + "clk1600m", + "pll_audio_1800m", +}; + +PNAME(sec_wclk_p) = { + "osc24m", + "clk396m", + "clk334m", + "clk297m", + "clk250m", + "clk198m", + "clk148m5", + "clk99m", +}; + +PNAME(sd_nand_wclk_p) = { + "osc24m", + "clk49m5", + "clk99m", + "clk198m", + "clk167m", + "clk148m5", + "clk125m", + "clk216m", +}; + +PNAME(emmc_wclk_p) = { + "osc24m", + "clk198m", + "clk99m", + "clk396m", + "clk334m", + "clk297m", + "clk250m", + "clk148m5", +}; + +PNAME(clk32_p) = { + "osc32k", + "clk32k768", +}; + +PNAME(usb_ref24m_p) = { + "osc32k", + "clk32k768", +}; + +PNAME(sys_noc_alck_p) = { + "osc24m", + "clk250m", + "clk198m", + "clk148m5", + "clk108m", + "clk54m", + "clk216m", + "clk240m", +}; + +PNAME(vde_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk480m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(vce_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(hde_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(gpu_aclk_p) = { + "clk334m", + "clk648m", + "clk594m", + "clk500m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(sappu_aclk_p) = { + "clk396m", + "clk500m", + "clk250m", + "clk148m5", +}; + +PNAME(sappu_wclk_p) = { + "clk198m", + "clk396m", + "clk334m", + "clk297m", + "clk250m", + "clk148m5", + "clk125m", + "clk99m", +}; + +PNAME(vou_aclk_p) = { + "clk334m", + "clk594m", + "clk500m", + "clk432m", + "clk396m", + "clk297m", + "clk_vga", /*600MHz*/ + "clk294m", +}; + +PNAME(vou_main_wclk_p) = { + "clk108m", + "clk594m", + "clk297m", + "clk148m5", + "clk74m25", + "clk54m", + "clk27m", + "clk_vga", +}; + +PNAME(vou_aux_wclk_p) = { + "clk108m", + "clk148m5", + "clk74m25", + "clk54m", + "clk27m", + "clk_vga", + "clk54m_mm0", + "clk" +}; + +PNAME(vou_ppu_wclk_p) = { + "clk334m", + "clk432m", + "clk396m", + "clk297m", + "clk250m", + "clk125m", + "clk198m", + "clk99m", +}; + +PNAME(vga_i2c_wclk_p) = { + "osc24m", + "clk99m", +}; + +PNAME(viu_m0_aclk_p) = { + "clk334m", + "clk432m", + "clk396m", + "clk297m", + "clk250m", + "clk125m", + "clk198m", + "osc24m", +}; + +PNAME(viu_m1_aclk_p) = { + "clk198m", + "clk250m", + "clk297m", + "clk125m", + "clk396m", + "clk334m", + "clk148m5", + "osc24m", +}; + +PNAME(viu_clk_p) = { + "clk198m", + "clk334m", + "clk297m", + "clk250m", + "clk396m", + "clk125m", + "clk99m", + "clk148m5", +}; + +PNAME(viu_jpeg_clk_p) = { + "clk334m", + "clk480m", + "clk432m", + "clk396m", + "clk297m", + "clk250m", + "clk125m", + "clk198m", +}; + +PNAME(ts_sys_clk_p) = { + "clk192m", + "clk167m", + "clk125m", + "clk99m", +}; + +PNAME(wdt_ares_p) = { + "osc24m", + "clk32k" +}; + +static struct clk_zx_pll zx296718_pll_clk[] = { + ZX296718_PLL("pll_cpu", "osc24m", PLL_CPU_REG, pll_cpu_table), +}; + +static struct zx_clk_fixed_factor top_ffactor_clk[] = { + FFACTOR(0, "clk4m", "osc24m", 1, 6, 0), + FFACTOR(0, "clk2m", "osc24m", 1, 12, 0), + /* pll cpu */ + FFACTOR(0, "clk1600m", "pll_cpu", 1, 1, CLK_SET_RATE_PARENT), + FFACTOR(0, "clk800m", "pll_cpu", 1, 2, CLK_SET_RATE_PARENT), + /* pll mac */ + FFACTOR(0, "clk25m", "pll_mac", 1, 40, 0), + FFACTOR(0, "clk125m", "pll_mac", 1, 8, 0), + FFACTOR(0, "clk250m", "pll_mac", 1, 4, 0), + FFACTOR(0, "clk50m", "pll_mac", 1, 20, 0), + FFACTOR(0, "clk500m", "pll_mac", 1, 2, 0), + FFACTOR(0, "clk1000m", "pll_mac", 1, 1, 0), + FFACTOR(0, "clk334m", "pll_mac", 1, 3, 0), + FFACTOR(0, "clk167m", "pll_mac", 1, 6, 0), + /* pll mm */ + FFACTOR(0, "clk54m_mm0", "pll_mm0", 1, 22, 0), + FFACTOR(0, "clk74m25", "pll_mm0", 1, 16, 0), + FFACTOR(0, "clk148m5", "pll_mm0", 1, 8, 0), + FFACTOR(0, "clk297m", "pll_mm0", 1, 4, 0), + FFACTOR(0, "clk594m", "pll_mm0", 1, 2, 0), + FFACTOR(0, "pll_mm0_1188m", "pll_mm0", 1, 1, 0), + FFACTOR(0, "clk396m", "pll_mm0", 1, 3, 0), + FFACTOR(0, "clk198m", "pll_mm0", 1, 6, 0), + FFACTOR(0, "clk99m", "pll_mm0", 1, 12, 0), + FFACTOR(0, "clk49m5", "pll_mm0", 1, 24, 0), + /* pll mm */ + FFACTOR(0, "clk324m", "pll_mm1", 1, 4, 0), + FFACTOR(0, "clk648m", "pll_mm1", 1, 2, 0), + FFACTOR(0, "pll_mm1_1296m", "pll_mm1", 1, 1, 0), + FFACTOR(0, "clk216m", "pll_mm1", 1, 6, 0), + FFACTOR(0, "clk432m", "pll_mm1", 1, 3, 0), + FFACTOR(0, "clk108m", "pll_mm1", 1, 12, 0), + FFACTOR(0, "clk72m", "pll_mm1", 1, 18, 0), + FFACTOR(0, "clk27m", "pll_mm1", 1, 48, 0), + FFACTOR(0, "clk54m", "pll_mm1", 1, 24, 0), + /* vga */ + FFACTOR(0, "pll_vga_1800m", "pll_vga", 1, 1, 0), + FFACTOR(0, "clk_vga", "pll_vga", 1, 2, 0), + /* pll ddr */ + FFACTOR(0, "clk466m", "pll_ddr", 1, 2, 0), + + /* pll audio */ + FFACTOR(0, "pll_audio_1800m", "pll_audio", 1, 1, 0), + FFACTOR(0, "clk32k768", "pll_audio", 1, 27000, 0), + FFACTOR(0, "clk16m384", "pll_audio", 1, 54, 0), + FFACTOR(0, "clk294m", "pll_audio", 1, 3, 0), + + /* pll hsic*/ + FFACTOR(0, "clk240m", "pll_hsic", 1, 4, 0), + FFACTOR(0, "clk480m", "pll_hsic", 1, 2, 0), + FFACTOR(0, "clk192m", "pll_hsic", 1, 5, 0), + FFACTOR(0, "clk_pll_24m", "pll_hsic", 1, 40, 0), + FFACTOR(0, "emmc_mux_div2", "emmc_mux", 1, 2, CLK_SET_RATE_PARENT), +}; + +static struct clk_div_table noc_div_table[] = { + { .val = 1, .div = 2, }, + { .val = 3, .div = 4, }, +}; +static struct zx_clk_div top_div_clk[] = { + DIV_T(0, "sys_noc_hclk", "sys_noc_aclk", TOP_CLK_DIV0, 0, 2, 0, noc_div_table), + DIV_T(0, "sys_noc_pclk", "sys_noc_aclk", TOP_CLK_DIV0, 4, 2, 0, noc_div_table), +}; + +static struct zx_clk_mux top_mux_clk[] = { + MUX(0, "dbg_mux", dbg_wclk_p, TOP_CLK_MUX0, 12, 2), + MUX(0, "a72_mux", a72_coreclk_p, TOP_CLK_MUX0, 8, 3), + MUX(0, "cpu_peri_mux", cpu_periclk_p, TOP_CLK_MUX0, 4, 3), + MUX_F(0, "a53_mux", a53_coreclk_p, TOP_CLK_MUX0, 0, 3, CLK_SET_RATE_PARENT, 0), + MUX(0, "sys_noc_aclk", sys_noc_alck_p, TOP_CLK_MUX1, 0, 3), + MUX(0, "sec_mux", sec_wclk_p, TOP_CLK_MUX2, 16, 3), + MUX(0, "sd1_mux", sd_nand_wclk_p, TOP_CLK_MUX2, 12, 3), + MUX(0, "sd0_mux", sd_nand_wclk_p, TOP_CLK_MUX2, 8, 3), + MUX(0, "emmc_mux", emmc_wclk_p, TOP_CLK_MUX2, 4, 3), + MUX(0, "nand_mux", sd_nand_wclk_p, TOP_CLK_MUX2, 0, 3), + MUX(0, "usb_ref24m_mux", usb_ref24m_p, TOP_CLK_MUX9, 16, 1), + MUX(0, "clk32k", clk32_p, TOP_CLK_MUX9, 12, 1), + MUX_F(0, "wdt_mux", wdt_ares_p, TOP_CLK_MUX9, 8, 1, CLK_SET_RATE_PARENT, 0), + MUX(0, "timer_mux", osc, TOP_CLK_MUX9, 4, 1), + MUX(0, "vde_mux", vde_aclk_p, TOP_CLK_MUX4, 0, 3), + MUX(0, "vce_mux", vce_aclk_p, TOP_CLK_MUX4, 4, 3), + MUX(0, "hde_mux", hde_aclk_p, TOP_CLK_MUX4, 8, 3), + MUX(0, "gpu_mux", gpu_aclk_p, TOP_CLK_MUX5, 0, 3), + MUX(0, "sappu_a_mux", sappu_aclk_p, TOP_CLK_MUX5, 4, 2), + MUX(0, "sappu_w_mux", sappu_wclk_p, TOP_CLK_MUX5, 8, 3), + MUX(0, "vou_a_mux", vou_aclk_p, TOP_CLK_MUX7, 0, 3), + MUX(0, "vou_main_w_mux", vou_main_wclk_p, TOP_CLK_MUX7, 4, 3), + MUX(0, "vou_aux_w_mux", vou_aux_wclk_p, TOP_CLK_MUX7, 8, 3), + MUX(0, "vou_ppu_w_mux", vou_ppu_wclk_p, TOP_CLK_MUX7, 12, 3), + MUX(0, "vga_i2c_mux", vga_i2c_wclk_p, TOP_CLK_MUX7, 16, 1), + MUX(0, "viu_m0_a_mux", viu_m0_aclk_p, TOP_CLK_MUX6, 0, 3), + MUX(0, "viu_m1_a_mux", viu_m1_aclk_p, TOP_CLK_MUX6, 4, 3), + MUX(0, "viu_w_mux", viu_clk_p, TOP_CLK_MUX6, 8, 3), + MUX(0, "viu_jpeg_w_mux", viu_jpeg_clk_p, TOP_CLK_MUX6, 12, 3), + MUX(0, "ts_sys_mux", ts_sys_clk_p, TOP_CLK_MUX6, 16, 2), +}; + +static struct zx_clk_gate top_gate_clk[] = { + GATE(CPU_DBG_GATE, "dbg_wclk", "dbg_mux", TOP_CLK_GATE0, 4, CLK_SET_RATE_PARENT, 0), + GATE(A72_GATE, "a72_coreclk", "a72_mux", TOP_CLK_GATE0, 3, CLK_SET_RATE_PARENT, 0), + GATE(CPU_PERI_GATE, "cpu_peri", "cpu_peri_mux", TOP_CLK_GATE0, 1, CLK_SET_RATE_PARENT, 0), + GATE(A53_GATE, "a53_coreclk", "a53_mux", TOP_CLK_GATE0, 0, CLK_SET_RATE_PARENT, 0), + GATE(SD1_WCLK, "sd1_wclk", "sd1_mux", TOP_CLK_GATE1, 13, CLK_SET_RATE_PARENT, 0), + GATE(SD0_WCLK, "sd0_wclk", "sd0_mux", TOP_CLK_GATE1, 9, CLK_SET_RATE_PARENT, 0), + GATE(EMMC_WCLK, "emmc_wclk", "emmc_mux_div2", TOP_CLK_GATE0, 5, CLK_SET_RATE_PARENT, 0), + GATE(EMMC_NAND_AXI, "emmc_nand_aclk", "sys_noc_aclk", TOP_CLK_GATE1, 4, CLK_SET_RATE_PARENT, 0), + GATE(NAND_WCLK, "nand_wclk", "nand_mux", TOP_CLK_GATE0, 1, CLK_SET_RATE_PARENT, 0), + GATE(EMMC_NAND_AHB, "emmc_nand_hclk", "sys_noc_hclk", TOP_CLK_GATE1, 0, CLK_SET_RATE_PARENT, 0), + GATE(0, "lsp1_pclk", "sys_noc_pclk", TOP_CLK_GATE2, 31, 0, 0), + GATE(LSP1_148M5, "lsp1_148m5", "clk148m5", TOP_CLK_GATE2, 30, 0, 0), + GATE(LSP1_99M, "lsp1_99m", "clk99m", TOP_CLK_GATE2, 29, 0, 0), + GATE(LSP1_24M, "lsp1_24m", "osc24m", TOP_CLK_GATE2, 28, 0, 0), + GATE(LSP0_74M25, "lsp0_74m25", "clk74m25", TOP_CLK_GATE2, 25, 0, 0), + GATE(0, "lsp0_pclk", "sys_noc_pclk", TOP_CLK_GATE2, 24, 0, 0), + GATE(LSP0_32K, "lsp0_32k", "osc32k", TOP_CLK_GATE2, 23, 0, 0), + GATE(LSP0_148M5, "lsp0_148m5", "clk148m5", TOP_CLK_GATE2, 22, 0, 0), + GATE(LSP0_99M, "lsp0_99m", "clk99m", TOP_CLK_GATE2, 21, 0, 0), + GATE(LSP0_24M, "lsp0_24m", "osc24m", TOP_CLK_GATE2, 20, 0, 0), + GATE(AUDIO_99M, "audio_99m", "clk99m", TOP_CLK_GATE5, 27, 0, 0), + GATE(AUDIO_24M, "audio_24m", "osc24m", TOP_CLK_GATE5, 28, 0, 0), + GATE(AUDIO_16M384, "audio_16m384", "clk16m384", TOP_CLK_GATE5, 29, 0, 0), + GATE(AUDIO_32K, "audio_32k", "clk32k", TOP_CLK_GATE5, 30, 0, 0), + GATE(WDT_WCLK, "wdt_wclk", "wdt_mux", TOP_CLK_GATE6, 9, CLK_SET_RATE_PARENT, 0), + GATE(TIMER_WCLK, "timer_wclk", "timer_mux", TOP_CLK_GATE6, 5, CLK_SET_RATE_PARENT, 0), + GATE(VDE_ACLK, "vde_aclk", "vde_mux", TOP_CLK_GATE3, 0, CLK_SET_RATE_PARENT, 0), + GATE(VCE_ACLK, "vce_aclk", "vce_mux", TOP_CLK_GATE3, 4, CLK_SET_RATE_PARENT, 0), + GATE(HDE_ACLK, "hde_aclk", "hde_mux", TOP_CLK_GATE3, 8, CLK_SET_RATE_PARENT, 0), + GATE(GPU_ACLK, "gpu_aclk", "gpu_mux", TOP_CLK_GATE3, 16, CLK_SET_RATE_PARENT, 0), + GATE(SAPPU_ACLK, "sappu_aclk", "sappu_a_mux", TOP_CLK_GATE3, 20, CLK_SET_RATE_PARENT, 0), + GATE(SAPPU_WCLK, "sappu_wclk", "sappu_w_mux", TOP_CLK_GATE3, 22, CLK_SET_RATE_PARENT, 0), + GATE(VOU_ACLK, "vou_aclk", "vou_a_mux", TOP_CLK_GATE4, 16, CLK_SET_RATE_PARENT, 0), + GATE(VOU_MAIN_WCLK, "vou_main_wclk", "vou_main_w_mux", TOP_CLK_GATE4, 18, CLK_SET_RATE_PARENT, 0), + GATE(VOU_AUX_WCLK, "vou_aux_wclk", "vou_aux_w_mux", TOP_CLK_GATE4, 19, CLK_SET_RATE_PARENT, 0), + GATE(VOU_PPU_WCLK, "vou_ppu_wclk", "vou_ppu_w_mux", TOP_CLK_GATE4, 20, CLK_SET_RATE_PARENT, 0), + GATE(MIPI_CFG_CLK, "mipi_cfg_clk", "osc24m", TOP_CLK_GATE4, 21, 0, 0), + GATE(VGA_I2C_WCLK, "vga_i2c_wclk", "vga_i2c_mux", TOP_CLK_GATE4, 23, CLK_SET_RATE_PARENT, 0), + GATE(MIPI_REF_CLK, "mipi_ref_clk", "clk27m", TOP_CLK_GATE4, 24, 0, 0), + GATE(HDMI_OSC_CEC, "hdmi_osc_cec", "clk2m", TOP_CLK_GATE4, 22, 0, 0), + GATE(HDMI_OSC_CLK, "hdmi_osc_clk", "clk240m", TOP_CLK_GATE4, 25, 0, 0), + GATE(HDMI_XCLK, "hdmi_xclk", "osc24m", TOP_CLK_GATE4, 26, 0, 0), + GATE(VIU_M0_ACLK, "viu_m0_aclk", "viu_m0_a_mux", TOP_CLK_GATE4, 0, CLK_SET_RATE_PARENT, 0), + GATE(VIU_M1_ACLK, "viu_m1_aclk", "viu_m1_a_mux", TOP_CLK_GATE4, 1, CLK_SET_RATE_PARENT, 0), + GATE(VIU_WCLK, "viu_wclk", "viu_w_mux", TOP_CLK_GATE4, 2, CLK_SET_RATE_PARENT, 0), + GATE(VIU_JPEG_WCLK, "viu_jpeg_wclk", "viu_jpeg_w_mux", TOP_CLK_GATE4, 3, CLK_SET_RATE_PARENT, 0), + GATE(VIU_CFG_CLK, "viu_cfg_clk", "osc24m", TOP_CLK_GATE4, 6, 0, 0), + GATE(TS_SYS_WCLK, "ts_sys_wclk", "ts_sys_mux", TOP_CLK_GATE5, 2, CLK_SET_RATE_PARENT, 0), + GATE(TS_SYS_108M, "ts_sys_108m", "clk108m", TOP_CLK_GATE5, 3, 0, 0), + GATE(USB20_HCLK, "usb20_hclk", "sys_noc_hclk", TOP_CLK_GATE2, 12, 0, 0), + GATE(USB20_PHY_CLK, "usb20_phy_clk", "usb_ref24m_mux", TOP_CLK_GATE2, 13, 0, 0), + GATE(USB21_HCLK, "usb21_hclk", "sys_noc_hclk", TOP_CLK_GATE2, 14, 0, 0), + GATE(USB21_PHY_CLK, "usb21_phy_clk", "usb_ref24m_mux", TOP_CLK_GATE2, 15, 0, 0), + GATE(GMAC_RMIICLK, "gmac_rmii_clk", "clk50m", TOP_CLK_GATE2, 3, 0, 0), + GATE(GMAC_PCLK, "gmac_pclk", "clk198m", TOP_CLK_GATE2, 1, 0, 0), + GATE(GMAC_ACLK, "gmac_aclk", "clk49m5", TOP_CLK_GATE2, 0, 0, 0), + GATE(GMAC_RFCLK, "gmac_refclk", "clk25m", TOP_CLK_GATE2, 4, 0, 0), + GATE(SD1_AHB, "sd1_hclk", "sys_noc_hclk", TOP_CLK_GATE1, 12, 0, 0), + GATE(SD0_AHB, "sd0_hclk", "sys_noc_hclk", TOP_CLK_GATE1, 8, 0, 0), + GATE(TEMPSENSOR_GATE, "tempsensor_gate", "clk4m", TOP_CLK_GATE5, 31, 0, 0), +}; + +static struct clk_hw_onecell_data top_hw_onecell_data = { + .num = TOP_NR_CLKS, + .hws = { + [TOP_NR_CLKS - 1] = NULL, + }, +}; + +static int __init top_clocks_init(struct device_node *np) +{ + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(zx296718_pll_clk); i++) { + zx296718_pll_clk[i].reg_base += (u64)reg_base; + ret = clk_hw_register(NULL, &zx296718_pll_clk[i].hw); + if (ret) { + pr_warn("top clk %s init error!\n", + zx296718_pll_clk[i].hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_ffactor_clk); i++) { + if (top_ffactor_clk[i].id) + top_hw_onecell_data.hws[top_ffactor_clk[i].id] = + &top_ffactor_clk[i].factor.hw; + + ret = clk_hw_register(NULL, &top_ffactor_clk[i].factor.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_ffactor_clk[i].factor.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_mux_clk); i++) { + if (top_mux_clk[i].id) + top_hw_onecell_data.hws[top_mux_clk[i].id] = + &top_mux_clk[i].mux.hw; + + top_mux_clk[i].mux.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &top_mux_clk[i].mux.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_mux_clk[i].mux.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_gate_clk); i++) { + if (top_gate_clk[i].id) + top_hw_onecell_data.hws[top_gate_clk[i].id] = + &top_gate_clk[i].gate.hw; + + top_gate_clk[i].gate.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &top_gate_clk[i].gate.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_gate_clk[i].gate.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(top_div_clk); i++) { + if (top_div_clk[i].id) + top_hw_onecell_data.hws[top_div_clk[i].id] = + &top_div_clk[i].div.hw; + + top_div_clk[i].div.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &top_div_clk[i].div.hw); + if (ret) { + pr_warn("top clk %s init error!\n", + top_div_clk[i].div.hw.init->name); + } + } + + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &top_hw_onecell_data)) + panic("could not register clk provider\n"); + pr_info("top clk init over, nr:%d\n", TOP_NR_CLKS); + + return 0; +} + +static struct clk_div_table common_even_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 3, .div = 4, }, + { .val = 5, .div = 6, }, + { .val = 7, .div = 8, }, + { .val = 9, .div = 10, }, + { .val = 11, .div = 12, }, + { .val = 13, .div = 14, }, + { .val = 15, .div = 16, }, +}; + +static struct clk_div_table common_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 3, }, + { .val = 3, .div = 4, }, + { .val = 4, .div = 5, }, + { .val = 5, .div = 6, }, + { .val = 6, .div = 7, }, + { .val = 7, .div = 8, }, + { .val = 8, .div = 9, }, + { .val = 9, .div = 10, }, + { .val = 10, .div = 11, }, + { .val = 11, .div = 12, }, + { .val = 12, .div = 13, }, + { .val = 13, .div = 14, }, + { .val = 14, .div = 15, }, + { .val = 15, .div = 16, }, +}; + +PNAME(lsp0_wclk_common_p) = { + "lsp0_24m", + "lsp0_99m", +}; + +PNAME(lsp0_wclk_timer3_p) = { + "timer3_div", + "lsp0_32k" +}; + +PNAME(lsp0_wclk_timer4_p) = { + "timer4_div", + "lsp0_32k" +}; + +PNAME(lsp0_wclk_timer5_p) = { + "timer5_div", + "lsp0_32k" +}; + +PNAME(lsp0_wclk_spifc0_p) = { + "lsp0_148m5", + "lsp0_24m", + "lsp0_99m", + "lsp0_74m25" +}; + +PNAME(lsp0_wclk_ssp_p) = { + "lsp0_148m5", + "lsp0_99m", + "lsp0_24m", +}; + +static struct zx_clk_mux lsp0_mux_clk[] = { + MUX(0, "timer3_wclk_mux", lsp0_wclk_timer3_p, LSP0_TIMER3_CLK, 4, 1), + MUX(0, "timer4_wclk_mux", lsp0_wclk_timer4_p, LSP0_TIMER4_CLK, 4, 1), + MUX(0, "timer5_wclk_mux", lsp0_wclk_timer5_p, LSP0_TIMER5_CLK, 4, 1), + MUX(0, "uart3_wclk_mux", lsp0_wclk_common_p, LSP0_UART3_CLK, 4, 1), + MUX(0, "uart1_wclk_mux", lsp0_wclk_common_p, LSP0_UART1_CLK, 4, 1), + MUX(0, "uart2_wclk_mux", lsp0_wclk_common_p, LSP0_UART2_CLK, 4, 1), + MUX(0, "spifc0_wclk_mux", lsp0_wclk_spifc0_p, LSP0_SPIFC0_CLK, 4, 2), + MUX(0, "i2c4_wclk_mux", lsp0_wclk_common_p, LSP0_I2C4_CLK, 4, 1), + MUX(0, "i2c5_wclk_mux", lsp0_wclk_common_p, LSP0_I2C5_CLK, 4, 1), + MUX(0, "ssp0_wclk_mux", lsp0_wclk_ssp_p, LSP0_SSP0_CLK, 4, 1), + MUX(0, "ssp1_wclk_mux", lsp0_wclk_ssp_p, LSP0_SSP1_CLK, 4, 1), + MUX(0, "i2c3_wclk_mux", lsp0_wclk_common_p, LSP0_I2C3_CLK, 4, 1), +}; + +static struct zx_clk_gate lsp0_gate_clk[] = { + GATE(LSP0_TIMER3_WCLK, "timer3_wclk", "timer3_wclk_mux", LSP0_TIMER3_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_TIMER4_WCLK, "timer4_wclk", "timer4_wclk_mux", LSP0_TIMER4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_TIMER5_WCLK, "timer5_wclk", "timer5_wclk_mux", LSP0_TIMER5_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_UART3_WCLK, "uart3_wclk", "uart3_wclk_mux", LSP0_UART3_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_UART1_WCLK, "uart1_wclk", "uart1_wclk_mux", LSP0_UART1_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_UART2_WCLK, "uart2_wclk", "uart2_wclk_mux", LSP0_UART2_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_SPIFC0_WCLK, "spifc0_wclk", "spifc0_wclk_mux", LSP0_SPIFC0_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_I2C4_WCLK, "i2c4_wclk", "i2c4_wclk_mux", LSP0_I2C4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_I2C5_WCLK, "i2c5_wclk", "i2c5_wclk_mux", LSP0_I2C5_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_SSP0_WCLK, "ssp0_wclk", "ssp0_div", LSP0_SSP0_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_SSP1_WCLK, "ssp1_wclk", "ssp1_div", LSP0_SSP1_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP0_I2C3_WCLK, "i2c3_wclk", "i2c3_wclk_mux", LSP0_I2C3_CLK, 1, CLK_SET_RATE_PARENT, 0), +}; + +static struct zx_clk_div lsp0_div_clk[] = { + DIV_T(0, "timer3_div", "lsp0_24m", LSP0_TIMER3_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "timer4_div", "lsp0_24m", LSP0_TIMER4_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "timer5_div", "lsp0_24m", LSP0_TIMER5_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "ssp0_div", "ssp0_wclk_mux", LSP0_SSP0_CLK, 12, 4, 0, common_even_div_table), + DIV_T(0, "ssp1_div", "ssp1_wclk_mux", LSP0_SSP1_CLK, 12, 4, 0, common_even_div_table), +}; + +static struct clk_hw_onecell_data lsp0_hw_onecell_data = { + .num = LSP0_NR_CLKS, + .hws = { + [LSP0_NR_CLKS - 1] = NULL, + }, +}; + +static int __init lsp0_clocks_init(struct device_node *np) +{ + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(lsp0_mux_clk); i++) { + if (lsp0_mux_clk[i].id) + lsp0_hw_onecell_data.hws[lsp0_mux_clk[i].id] = + &lsp0_mux_clk[i].mux.hw; + + lsp0_mux_clk[i].mux.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp0_mux_clk[i].mux.hw); + if (ret) { + pr_warn("lsp0 clk %s init error!\n", + lsp0_mux_clk[i].mux.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp0_gate_clk); i++) { + if (lsp0_gate_clk[i].id) + lsp0_hw_onecell_data.hws[lsp0_gate_clk[i].id] = + &lsp0_gate_clk[i].gate.hw; + + lsp0_gate_clk[i].gate.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp0_gate_clk[i].gate.hw); + if (ret) { + pr_warn("lsp0 clk %s init error!\n", + lsp0_gate_clk[i].gate.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp0_div_clk); i++) { + if (lsp0_div_clk[i].id) + lsp0_hw_onecell_data.hws[lsp0_div_clk[i].id] = + &lsp0_div_clk[i].div.hw; + + lsp0_div_clk[i].div.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp0_div_clk[i].div.hw); + if (ret) { + pr_warn("lsp0 clk %s init error!\n", + lsp0_div_clk[i].div.hw.init->name); + } + } + + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp0_hw_onecell_data)) + panic("could not register clk provider\n"); + pr_info("lsp0-clk init over:%d\n", LSP0_NR_CLKS); + + return 0; +} + +PNAME(lsp1_wclk_common_p) = { + "lsp1_24m", + "lsp1_99m", +}; + +PNAME(lsp1_wclk_ssp_p) = { + "lsp1_148m5", + "lsp1_99m", + "lsp1_24m", +}; + +static struct zx_clk_mux lsp1_mux_clk[] = { + MUX(0, "uart4_wclk_mux", lsp1_wclk_common_p, LSP1_UART4_CLK, 4, 1), + MUX(0, "uart5_wclk_mux", lsp1_wclk_common_p, LSP1_UART5_CLK, 4, 1), + MUX(0, "pwm_wclk_mux", lsp1_wclk_common_p, LSP1_PWM_CLK, 4, 1), + MUX(0, "i2c2_wclk_mux", lsp1_wclk_common_p, LSP1_I2C2_CLK, 4, 1), + MUX(0, "ssp2_wclk_mux", lsp1_wclk_ssp_p, LSP1_SSP2_CLK, 4, 2), + MUX(0, "ssp3_wclk_mux", lsp1_wclk_ssp_p, LSP1_SSP3_CLK, 4, 2), + MUX(0, "ssp4_wclk_mux", lsp1_wclk_ssp_p, LSP1_SSP4_CLK, 4, 2), + MUX(0, "usim1_wclk_mux", lsp1_wclk_common_p, LSP1_USIM1_CLK, 4, 1), +}; + +static struct zx_clk_div lsp1_div_clk[] = { + DIV_T(0, "pwm_div", "pwm_wclk_mux", LSP1_PWM_CLK, 12, 4, CLK_SET_RATE_PARENT, common_div_table), + DIV_T(0, "ssp2_div", "ssp2_wclk_mux", LSP1_SSP2_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table), + DIV_T(0, "ssp3_div", "ssp3_wclk_mux", LSP1_SSP3_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table), + DIV_T(0, "ssp4_div", "ssp4_wclk_mux", LSP1_SSP4_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table), +}; + +static struct zx_clk_gate lsp1_gate_clk[] = { + GATE(LSP1_UART4_WCLK, "lsp1_uart4_wclk", "uart4_wclk_mux", LSP1_UART4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_UART5_WCLK, "lsp1_uart5_wclk", "uart5_wclk_mux", LSP1_UART5_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_PWM_WCLK, "lsp1_pwm_wclk", "pwm_div", LSP1_PWM_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_PWM_PCLK, "lsp1_pwm_pclk", "lsp1_pclk", LSP1_PWM_CLK, 0, 0, 0), + GATE(LSP1_I2C2_WCLK, "lsp1_i2c2_wclk", "i2c2_wclk_mux", LSP1_I2C2_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_SSP2_WCLK, "lsp1_ssp2_wclk", "ssp2_div", LSP1_SSP2_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_SSP3_WCLK, "lsp1_ssp3_wclk", "ssp3_div", LSP1_SSP3_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_SSP4_WCLK, "lsp1_ssp4_wclk", "ssp4_div", LSP1_SSP4_CLK, 1, CLK_SET_RATE_PARENT, 0), + GATE(LSP1_USIM1_WCLK, "lsp1_usim1_wclk", "usim1_wclk_mux", LSP1_USIM1_CLK, 1, CLK_SET_RATE_PARENT, 0), +}; + +static struct clk_hw_onecell_data lsp1_hw_onecell_data = { + .num = LSP1_NR_CLKS, + .hws = { + [LSP1_NR_CLKS - 1] = NULL, + }, +}; + +static int __init lsp1_clocks_init(struct device_node *np) +{ + void __iomem *reg_base; + int i, ret; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(lsp1_mux_clk); i++) { + if (lsp1_mux_clk[i].id) + lsp1_hw_onecell_data.hws[lsp1_mux_clk[i].id] = + &lsp0_mux_clk[i].mux.hw; + + lsp1_mux_clk[i].mux.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp1_mux_clk[i].mux.hw); + if (ret) { + pr_warn("lsp1 clk %s init error!\n", + lsp1_mux_clk[i].mux.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp1_gate_clk); i++) { + if (lsp1_gate_clk[i].id) + lsp1_hw_onecell_data.hws[lsp1_gate_clk[i].id] = + &lsp1_gate_clk[i].gate.hw; + + lsp1_gate_clk[i].gate.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp1_gate_clk[i].gate.hw); + if (ret) { + pr_warn("lsp1 clk %s init error!\n", + lsp1_gate_clk[i].gate.hw.init->name); + } + } + + for (i = 0; i < ARRAY_SIZE(lsp1_div_clk); i++) { + if (lsp1_div_clk[i].id) + lsp1_hw_onecell_data.hws[lsp1_div_clk[i].id] = + &lsp1_div_clk[i].div.hw; + + lsp1_div_clk[i].div.reg += (u64)reg_base; + ret = clk_hw_register(NULL, &lsp1_div_clk[i].div.hw); + if (ret) { + pr_warn("lsp1 clk %s init error!\n", + lsp1_div_clk[i].div.hw.init->name); + } + } + + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp1_hw_onecell_data)) + panic("could not register clk provider\n"); + pr_info("lsp1-clk init over, nr:%d\n", LSP1_NR_CLKS); + + return 0; +} + +static const struct of_device_id zx_clkc_match_table[] = { + { .compatible = "zte,zx296718-topcrm", .data = &top_clocks_init }, + { .compatible = "zte,zx296718-lsp0crm", .data = &lsp0_clocks_init }, + { .compatible = "zte,zx296718-lsp1crm", .data = &lsp1_clocks_init }, + { } +}; + +static int zx_clkc_probe(struct platform_device *pdev) +{ + int (*init_fn)(struct device_node *np); + struct device_node *np = pdev->dev.of_node; + + init_fn = of_device_get_match_data(&pdev->dev); + if (!init_fn) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + + return init_fn(np); +} + +static struct platform_driver zx_clk_driver = { + .probe = zx_clkc_probe, + .driver = { + .name = "zx296718-clkc", + .of_match_table = zx_clkc_match_table, + }, +}; + +static int __init zx_clkc_init(void) +{ + return platform_driver_register(&zx_clk_driver); +} +device_initcall(zx_clkc_init); diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index 8f6b5f0..0df3474 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -12,6 +12,26 @@ #include #include +#define PNAME(x) static const char *x[] + +#define CLK_HW_INIT(_name, _parent, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = (const char *[]) { _parent }, \ + .num_parents = 1, \ + .ops = _ops, \ + } + +#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \ + &(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .ops = _ops, \ + } + struct zx_pll_config { unsigned long rate; u32 cfg0; @@ -28,6 +48,111 @@ struct clk_zx_pll { u8 lock_bit; /* pll lock flag bit */ }; +#define PLL_RATE(_rate, _cfg0, _cfg1) \ +{ \ + .rate = _rate, \ + .cfg0 = _cfg0, \ + .cfg1 = _cfg1, \ +} + +#define ZX_PLL(_name, _parent, _reg, _table, _pd, _lock) \ +{ \ + .reg_base = (void __iomem *) _reg, \ + .lookup_table = _table, \ + .count = ARRAY_SIZE(_table), \ + .pd_bit = _pd, \ + .lock_bit = _lock, \ + .hw.init = CLK_HW_INIT(_name, _parent, &zx_pll_ops, \ + CLK_GET_RATE_NOCACHE), \ +} + +#define ZX296718_PLL(_name, _parent, _reg, _table) \ +ZX_PLL(_name, _parent, _reg, _table, 0, 30) + +struct zx_clk_gate { + struct clk_gate gate; + u16 id; +}; + +#define GATE(_id, _name, _parent, _reg, _bit, _flag, _gflags) \ +{ \ + .gate = { \ + .reg = (void __iomem *) _reg, \ + .bit_idx = (_bit), \ + .flags = _gflags, \ + .lock = &clk_lock, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &clk_gate_ops, \ + _flag | CLK_IGNORE_UNUSED), \ + }, \ + .id = _id, \ +} + +struct zx_clk_fixed_factor { + struct clk_fixed_factor factor; + u16 id; +}; + +#define FFACTOR(_id, _name, _parent, _mult, _div, _flag) \ +{ \ + .factor = { \ + .div = _div, \ + .mult = _mult, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &clk_fixed_factor_ops, \ + _flag), \ + }, \ + .id = _id, \ +} + +struct zx_clk_mux { + struct clk_mux mux; + u16 id; +}; + +#define MUX_F(_id, _name, _parent, _reg, _shift, _width, _flag, _mflag) \ +{ \ + .mux = { \ + .reg = (void __iomem *) _reg, \ + .mask = BIT(_width) - 1, \ + .shift = _shift, \ + .flags = _mflag, \ + .lock = &clk_lock, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parent, \ + &clk_mux_ops, \ + _flag), \ + }, \ + .id = _id, \ +} + +#define MUX(_id, _name, _parent, _reg, _shift, _width) \ +MUX_F(_id, _name, _parent, _reg, _shift, _width, 0, 0) + +struct zx_clk_div { + struct clk_divider div; + u16 id; +}; + +#define DIV_T(_id, _name, _parent, _reg, _shift, _width, _flag, _table) \ +{ \ + .div = { \ + .reg = (void __iomem *) _reg, \ + .shift = _shift, \ + .width = _width, \ + .flags = 0, \ + .table = _table, \ + .lock = &clk_lock, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &clk_divider_ops, \ + _flag), \ + }, \ + .id = _id, \ +} + struct clk *clk_register_zx_pll(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg_base, const struct zx_pll_config *lookup_table, int count, spinlock_t *lock); diff --git a/include/dt-bindings/clock/zx296718-clock.h b/include/dt-bindings/clock/zx296718-clock.h new file mode 100644 index 0000000..822d523 --- /dev/null +++ b/include/dt-bindings/clock/zx296718-clock.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2015 - 2016 ZTE Corporation. + * + * 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. + */ +#ifndef __DT_BINDINGS_CLOCK_ZX296718_H +#define __DT_BINDINGS_CLOCK_ZX296718_H + +/* PLL */ +#define ZX296718_PLL_CPU 1 +#define ZX296718_PLL_MAC 2 +#define ZX296718_PLL_MM0 3 +#define ZX296718_PLL_MM1 4 +#define ZX296718_PLL_VGA 5 +#define ZX296718_PLL_DDR 6 +#define ZX296718_PLL_AUDIO 7 +#define ZX296718_PLL_HSIC 8 +#define CPU_DBG_GATE 9 +#define A72_GATE 10 +#define CPU_PERI_GATE 11 +#define A53_GATE 12 +#define DDR1_GATE 13 +#define DDR0_GATE 14 +#define SD1_WCLK 15 +#define SD1_AHB 16 +#define SD0_WCLK 17 +#define SD0_AHB 18 +#define EMMC_WCLK 19 +#define EMMC_NAND_AXI 20 +#define NAND_WCLK 21 +#define EMMC_NAND_AHB 22 +#define LSP1_148M5 23 +#define LSP1_99M 24 +#define LSP1_24M 25 +#define LSP0_74M25 26 +#define LSP0_32K 27 +#define LSP0_148M5 28 +#define LSP0_99M 29 +#define LSP0_24M 30 +#define DEMUX_AXI 31 +#define DEMUX_APB 32 +#define DEMUX_148M5 33 +#define DEMUX_108M 34 +#define AUDIO_APB 35 +#define AUDIO_99M 36 +#define AUDIO_24M 37 +#define AUDIO_16M384 38 +#define AUDIO_32K 39 +#define WDT_WCLK 40 +#define TIMER_WCLK 41 +#define VDE_ACLK 42 +#define VCE_ACLK 43 +#define HDE_ACLK 44 +#define GPU_ACLK 45 +#define SAPPU_ACLK 46 +#define SAPPU_WCLK 47 +#define VOU_ACLK 48 +#define VOU_MAIN_WCLK 49 +#define VOU_AUX_WCLK 50 +#define VOU_PPU_WCLK 51 +#define MIPI_CFG_CLK 52 +#define VGA_I2C_WCLK 53 +#define MIPI_REF_CLK 54 +#define HDMI_OSC_CEC 55 +#define HDMI_OSC_CLK 56 +#define HDMI_XCLK 57 +#define VIU_M0_ACLK 58 +#define VIU_M1_ACLK 59 +#define VIU_WCLK 60 +#define VIU_JPEG_WCLK 61 +#define VIU_CFG_CLK 62 +#define TS_SYS_WCLK 63 +#define TS_SYS_108M 64 +#define USB20_HCLK 65 +#define USB20_PHY_CLK 66 +#define USB21_HCLK 67 +#define USB21_PHY_CLK 68 +#define GMAC_RMIICLK 69 +#define GMAC_PCLK 70 +#define GMAC_ACLK 71 +#define GMAC_RFCLK 72 +#define TEMPSENSOR_GATE 73 + +#define TOP_NR_CLKS 74 + + +#define LSP0_TIMER3_PCLK 1 +#define LSP0_TIMER3_WCLK 2 +#define LSP0_TIMER4_PCLK 3 +#define LSP0_TIMER4_WCLK 4 +#define LSP0_TIMER5_PCLK 5 +#define LSP0_TIMER5_WCLK 6 +#define LSP0_UART3_PCLK 7 +#define LSP0_UART3_WCLK 8 +#define LSP0_UART1_PCLK 9 +#define LSP0_UART1_WCLK 10 +#define LSP0_UART2_PCLK 11 +#define LSP0_UART2_WCLK 12 +#define LSP0_SPIFC0_PCLK 13 +#define LSP0_SPIFC0_WCLK 14 +#define LSP0_I2C4_PCLK 15 +#define LSP0_I2C4_WCLK 16 +#define LSP0_I2C5_PCLK 17 +#define LSP0_I2C5_WCLK 18 +#define LSP0_SSP0_PCLK 19 +#define LSP0_SSP0_WCLK 20 +#define LSP0_SSP1_PCLK 21 +#define LSP0_SSP1_WCLK 22 +#define LSP0_USIM_PCLK 23 +#define LSP0_USIM_WCLK 24 +#define LSP0_GPIO_PCLK 25 +#define LSP0_GPIO_WCLK 26 +#define LSP0_I2C3_PCLK 27 +#define LSP0_I2C3_WCLK 28 + +#define LSP0_NR_CLKS 29 + + +#define LSP1_UART4_PCLK 1 +#define LSP1_UART4_WCLK 2 +#define LSP1_UART5_PCLK 3 +#define LSP1_UART5_WCLK 4 +#define LSP1_PWM_PCLK 5 +#define LSP1_PWM_WCLK 6 +#define LSP1_I2C2_PCLK 7 +#define LSP1_I2C2_WCLK 8 +#define LSP1_SSP2_PCLK 9 +#define LSP1_SSP2_WCLK 10 +#define LSP1_SSP3_PCLK 11 +#define LSP1_SSP3_WCLK 12 +#define LSP1_SSP4_PCLK 13 +#define LSP1_SSP4_WCLK 14 +#define LSP1_USIM1_PCLK 15 +#define LSP1_USIM1_WCLK 16 + +#define LSP1_NR_CLKS 17 + + +#define AUDIO_I2S0_WCLK 1 +#define AUDIO_I2S0_PCLK 2 +#define AUDIO_I2S1_WCLK 3 +#define AUDIO_I2S1_PCLK 4 +#define AUDIO_I2S2_WCLK 5 +#define AUDIO_I2S2_PCLK 6 +#define AUDIO_I2S3_WCLK 7 +#define AUDIO_I2S3_PCLK 8 +#define AUDIO_I2C0_WCLK 9 +#define AUDIO_I2C0_PCLK 10 +#define AUDIO_SPDIF0_WCLK 11 +#define AUDIO_SPDIF0_PCLK 12 +#define AUDIO_SPDIF1_WCLK 13 +#define AUDIO_SPDIF1_PCLK 14 +#define AUDIO_TIMER_WCLK 15 +#define AUDIO_TIMER_PCLK 16 +#define AUDIO_TDM_WCLK 17 +#define AUDIO_TDM_PCLK 18 +#define AUDIO_TS_PCLK 19 + +#define AUDIO_NR_CLKS 20 + +#endif -- cgit v0.10.2 From 405f27be6182362e343c25ae6ec2b2933919ef30 Mon Sep 17 00:00:00 2001 From: Hoan Tran Date: Mon, 12 Sep 2016 11:23:23 -0700 Subject: Documentation: dt: xgene: Add PMD clock binding Add APM X-Gene clock binding documentation for PMD clock. Signed-off-by: Hoan Tran Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/xgene.txt b/Documentation/devicetree/bindings/clock/xgene.txt index 82f9638..8233e77 100644 --- a/Documentation/devicetree/bindings/clock/xgene.txt +++ b/Documentation/devicetree/bindings/clock/xgene.txt @@ -8,6 +8,7 @@ Required properties: - compatible : shall be one of the following: "apm,xgene-socpll-clock" - for a X-Gene SoC PLL clock "apm,xgene-pcppll-clock" - for a X-Gene PCP PLL clock + "apm,xgene-pmd-clock" - for a X-Gene PMD clock "apm,xgene-device-clock" - for a X-Gene device clock "apm,xgene-socpll-v2-clock" - for a X-Gene SoC PLL v2 clock "apm,xgene-pcppll-v2-clock" - for a X-Gene PCP PLL v2 clock @@ -22,6 +23,15 @@ Required properties for SoC or PCP PLL clocks: Optional properties for PLL clocks: - clock-names : shall be the name of the PLL. If missing, use the device name. +Required properties for PMD clocks: +- reg : shall be the physical register address for the pmd clock. +- clocks : shall be the input parent clock phandle for the clock. +- #clock-cells : shall be set to 1. +- clock-output-names : shall be the name of the clock referenced by derive + clock. +Optional properties for PLL clocks: +- clock-names : shall be the name of the clock. If missing, use the device name. + Required properties for device clocks: - reg : shall be a list of address and length pairs describing the CSR reset and/or the divider. Either may be omitted, but at least @@ -59,6 +69,14 @@ For example: type = <0>; }; + pmd0clk: pmd0clk@7e200200 { + compatible = "apm,xgene-pmd-clock"; + #clock-cells = <1>; + clocks = <&pmdpll 0>; + reg = <0x0 0x7e200200 0x0 0x10>; + clock-output-names = "pmd0clk"; + }; + socpll: socpll@17000120 { compatible = "apm,xgene-socpll-clock"; #clock-cells = <1>; -- cgit v0.10.2 From 1a85b50bef13b44016c206272785a746adae7833 Mon Sep 17 00:00:00 2001 From: Hoan Tran Date: Mon, 12 Sep 2016 11:23:24 -0700 Subject: clk: xgene: Add PMD clock Add X-Gene PMD clock support. PMD clock is implemented for a single register field. Output rate = parent_rate * (denominator - scale) / denominator with - denominator = bitmask of register field + 1 - scale = values of register field For example, for bitmask is 0x7, denominator will be 8 and scale will be computed and programmed accordingly. Signed-off-by: Hoan Tran Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index 3433132..5daddf5 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -217,6 +217,226 @@ static void xgene_pcppllclk_init(struct device_node *np) xgene_pllclk_init(np, PLL_TYPE_PCP); } +/** + * struct xgene_clk_pmd - PMD clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing the fractional scale multiplier (scaler) + * @shift: shift to the unit bit field + * @denom: 1/denominator unit + * @lock: register lock + * Flags: + * XGENE_CLK_PMD_SCALE_INVERTED - By default the scaler is the value read + * from the register plus one. For example, + * 0 for (0 + 1) / denom, + * 1 for (1 + 1) / denom and etc. + * If this flag is set, it is + * 0 for (denom - 0) / denom, + * 1 for (denom - 1) / denom and etc. + * + */ +struct xgene_clk_pmd { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + u32 mask; + u64 denom; + u32 flags; + spinlock_t *lock; +}; + +#define to_xgene_clk_pmd(_hw) container_of(_hw, struct xgene_clk_pmd, hw) + +#define XGENE_CLK_PMD_SCALE_INVERTED BIT(0) +#define XGENE_CLK_PMD_SHIFT 8 +#define XGENE_CLK_PMD_WIDTH 3 + +static unsigned long xgene_clk_pmd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw); + unsigned long flags = 0; + u64 ret, scale; + u32 val; + + if (fd->lock) + spin_lock_irqsave(fd->lock, flags); + else + __acquire(fd->lock); + + val = clk_readl(fd->reg); + + if (fd->lock) + spin_unlock_irqrestore(fd->lock, flags); + else + __release(fd->lock); + + ret = (u64)parent_rate; + + scale = (val & fd->mask) >> fd->shift; + if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED) + scale = fd->denom - scale; + else + scale++; + + /* freq = parent_rate * scaler / denom */ + do_div(ret, fd->denom); + ret *= scale; + if (ret == 0) + ret = (u64)parent_rate; + + return ret; +} + +static long xgene_clk_pmd_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw); + u64 ret, scale; + + if (!rate || rate >= *parent_rate) + return *parent_rate; + + /* freq = parent_rate * scaler / denom */ + ret = rate * fd->denom; + scale = DIV_ROUND_UP_ULL(ret, *parent_rate); + + ret = (u64)*parent_rate * scale; + do_div(ret, fd->denom); + + return ret; +} + +static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw); + unsigned long flags = 0; + u64 scale, ret; + u32 val; + + /* + * Compute the scaler: + * + * freq = parent_rate * scaler / denom, or + * scaler = freq * denom / parent_rate + */ + ret = rate * fd->denom; + scale = DIV_ROUND_UP_ULL(ret, (u64)parent_rate); + + /* Check if inverted */ + if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED) + scale = fd->denom - scale; + else + scale--; + + if (fd->lock) + spin_lock_irqsave(fd->lock, flags); + else + __acquire(fd->lock); + + val = clk_readl(fd->reg); + val &= ~fd->mask; + val |= (scale << fd->shift); + clk_writel(val, fd->reg); + + if (fd->lock) + spin_unlock_irqrestore(fd->lock, flags); + else + __release(fd->lock); + + return 0; +} + +static const struct clk_ops xgene_clk_pmd_ops = { + .recalc_rate = xgene_clk_pmd_recalc_rate, + .round_rate = xgene_clk_pmd_round_rate, + .set_rate = xgene_clk_pmd_set_rate, +}; + +static struct clk * +xgene_register_clk_pmd(struct device *dev, + const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg, u8 shift, + u8 width, u64 denom, u32 clk_flags, spinlock_t *lock) +{ + struct xgene_clk_pmd *fd; + struct clk_init_data init; + struct clk *clk; + + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &xgene_clk_pmd_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + fd->reg = reg; + fd->shift = shift; + fd->mask = (BIT(width) - 1) << shift; + fd->denom = denom; + fd->flags = clk_flags; + fd->lock = lock; + fd->hw.init = &init; + + clk = clk_register(dev, &fd->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register clk %s\n", __func__, name); + kfree(fd); + return NULL; + } + + return clk; +} + +static void xgene_pmdclk_init(struct device_node *np) +{ + const char *clk_name = np->full_name; + void __iomem *csr_reg; + struct resource res; + struct clk *clk; + u64 denom; + u32 flags = 0; + int rc; + + /* Check if the entry is disabled */ + if (!of_device_is_available(np)) + return; + + /* Parse the DTS register for resource */ + rc = of_address_to_resource(np, 0, &res); + if (rc != 0) { + pr_err("no DTS register for %s\n", np->full_name); + return; + } + csr_reg = of_iomap(np, 0); + if (!csr_reg) { + pr_err("Unable to map resource for %s\n", np->full_name); + return; + } + of_property_read_string(np, "clock-output-names", &clk_name); + + denom = BIT(XGENE_CLK_PMD_WIDTH); + flags |= XGENE_CLK_PMD_SCALE_INVERTED; + + clk = xgene_register_clk_pmd(NULL, clk_name, + of_clk_get_parent_name(np, 0), 0, + csr_reg, XGENE_CLK_PMD_SHIFT, + XGENE_CLK_PMD_WIDTH, denom, + flags, &clk_lock); + if (!IS_ERR(clk)) { + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock\n", clk_name); + } else { + if (csr_reg) + iounmap(csr_reg); + } +} + /* IP Clock */ struct xgene_dev_parameters { void __iomem *csr_reg; /* CSR for IP clock */ @@ -543,6 +763,7 @@ err: CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init); +CLK_OF_DECLARE(xgene_pmd_clock, "apm,xgene-pmd-clock", xgene_pmdclk_init); CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock", xgene_socpllclk_init); CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock", -- cgit v0.10.2 From f4e871509959b77debcac8f0dcbad85d6dbde06e Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 29 Oct 2015 16:44:10 -0400 Subject: clk: iproc: Make clocks visible options Make the clocks visible options that can be selected by anyone. This avoids the problems of: 1) Select is a reverse dependency and is hard for people to understand and can sometimes be a pain to track down 2) Build coverage goes down because configs are hidden 3) Code bloat Patch suggested by Stephen Boyd Signed-off-by: Jon Mason Signed-off-by: Stephen Boyd diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 34f0fca..7bf3ae7 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -15,7 +15,6 @@ config ARCH_BCM_IPROC select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select ARM_GLOBAL_TIMER - select COMMON_CLK_IPROC select CLKSRC_MMIO select GPIOLIB select ARM_AMBA diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig index f287845..f21e9b7 100644 --- a/drivers/clk/bcm/Kconfig +++ b/drivers/clk/bcm/Kconfig @@ -19,8 +19,36 @@ config CLK_BCM_KONA in the BCM281xx and BCM21664 families. config COMMON_CLK_IPROC - bool + bool "Broadcom iProc clock support" + depends on ARCH_BCM_IPROC || COMPILE_TEST depends on COMMON_CLK + default ARCH_BCM_IPROC help Enable common clock framework support for Broadcom SoCs based on the iProc architecture + +if COMMON_CLK_IPROC + +config CLK_BCM_CYGNUS + bool "Broadcom Cygnus clock support" + depends on ARCH_BCM_CYGNUS || COMPILE_TEST + default ARCH_BCM_CYGNUS + help + Enable common clock framework support for the Broadcom Cygnus SoC + +config CLK_BCM_NSP + bool "Broadcom Northstar/Northstar Plus clock support" + depends on ARCH_BCM_5301X || ARCH_BCM_NSP || COMPILE_TEST + default ARCH_BCM_5301X || ARCH_BCM_NSP + help + Enable common clock framework support for the Broadcom Northstar and + Northstar Plus SoCs + +config CLK_BCM_NS2 + bool "Broadcom Northstar 2 clock support" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + Enable common clock framework support for the Broadcom Northstar 2 SoC + +endif diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index 1d79bd2..123f377 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o -obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o -obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o -obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o -obj-$(CONFIG_ARCH_BCM_5301X) += clk-nsp.o +obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o +obj-$(CONFIG_CLK_BCM_NSP) += clk-nsp.o +obj-$(CONFIG_CLK_BCM_NS2) += clk-ns2.o -- cgit v0.10.2 From b19f009d451060ee820deffa1afba029797fa654 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 16:15:03 -0700 Subject: clk: bcm2835: Migrate to clk_hw based registration and OF APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers while registering clks in these drivers, allowing us to move closer to a clear split of consumer and provider clk APIs. Cc: Eric Anholt Cc: Martin Sperl Signed-off-by: Stephen Boyd diff --git a/drivers/clk/bcm/clk-bcm2835-aux.c b/drivers/clk/bcm/clk-bcm2835-aux.c index 3a177ad..bd750cf 100644 --- a/drivers/clk/bcm/clk-bcm2835-aux.c +++ b/drivers/clk/bcm/clk-bcm2835-aux.c @@ -25,7 +25,7 @@ static int bcm2835_aux_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct clk_onecell_data *onecell; + struct clk_hw_onecell_data *onecell; const char *parent; struct clk *parent_clk; struct resource *res; @@ -41,28 +41,24 @@ static int bcm2835_aux_clk_probe(struct platform_device *pdev) if (IS_ERR(reg)) return PTR_ERR(reg); - onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL); + onecell = devm_kmalloc(dev, sizeof(*onecell) + sizeof(*onecell->hws) * + BCM2835_AUX_CLOCK_COUNT, GFP_KERNEL); if (!onecell) return -ENOMEM; - onecell->clk_num = BCM2835_AUX_CLOCK_COUNT; - onecell->clks = devm_kcalloc(dev, BCM2835_AUX_CLOCK_COUNT, - sizeof(*onecell->clks), GFP_KERNEL); - if (!onecell->clks) - return -ENOMEM; + onecell->num = BCM2835_AUX_CLOCK_COUNT; gate = reg + BCM2835_AUXENB; - onecell->clks[BCM2835_AUX_CLOCK_UART] = - clk_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL); - - onecell->clks[BCM2835_AUX_CLOCK_SPI1] = - clk_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL); + onecell->hws[BCM2835_AUX_CLOCK_UART] = + clk_hw_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL); - onecell->clks[BCM2835_AUX_CLOCK_SPI2] = - clk_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL); + onecell->hws[BCM2835_AUX_CLOCK_SPI1] = + clk_hw_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL); - of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, onecell); + onecell->hws[BCM2835_AUX_CLOCK_SPI2] = + clk_hw_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL); - return 0; + return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, + onecell); } static const struct of_device_id bcm2835_aux_clk_of_match[] = { diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index e8a9646a..b68bf57 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -303,8 +303,8 @@ struct bcm2835_cprman { spinlock_t regs_lock; /* spinlock for all clocks */ const char *osc_name; - struct clk_onecell_data onecell; - struct clk *clks[]; + /* Must be last */ + struct clk_hw_onecell_data onecell; }; static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val) @@ -345,24 +345,24 @@ static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base, */ void __init bcm2835_init_clocks(void) { - struct clk *clk; + struct clk_hw *hw; int ret; - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 126000000); - if (IS_ERR(clk)) + hw = clk_hw_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 126000000); + if (IS_ERR(hw)) pr_err("apb_pclk not registered\n"); - clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, 0, 3000000); - if (IS_ERR(clk)) + hw = clk_hw_register_fixed_rate(NULL, "uart0_pclk", NULL, 0, 3000000); + if (IS_ERR(hw)) pr_err("uart0_pclk not registered\n"); - ret = clk_register_clkdev(clk, NULL, "20201000.uart"); + ret = clk_hw_register_clkdev(hw, NULL, "20201000.uart"); if (ret) pr_err("uart0_pclk alias not registered\n"); - clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, 0, 125000000); - if (IS_ERR(clk)) + hw = clk_hw_register_fixed_rate(NULL, "uart1_pclk", NULL, 0, 125000000); + if (IS_ERR(hw)) pr_err("uart1_pclk not registered\n"); - ret = clk_register_clkdev(clk, NULL, "20215000.uart"); + ret = clk_hw_register_clkdev(hw, NULL, "20215000.uart"); if (ret) pr_err("uart1_pclk alias not registered\n"); } @@ -1147,11 +1147,12 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { .debug_init = bcm2835_clock_debug_init, }; -static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman, - const struct bcm2835_pll_data *data) +static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, + const struct bcm2835_pll_data *data) { struct bcm2835_pll *pll; struct clk_init_data init; + int ret; memset(&init, 0, sizeof(init)); @@ -1170,17 +1171,20 @@ static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman, pll->data = data; pll->hw.init = &init; - return devm_clk_register(cprman->dev, &pll->hw); + ret = devm_clk_hw_register(cprman->dev, &pll->hw); + if (ret) + return NULL; + return &pll->hw; } -static struct clk * +static struct clk_hw * bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, const struct bcm2835_pll_divider_data *data) { struct bcm2835_pll_divider *divider; struct clk_init_data init; - struct clk *clk; const char *divider_name; + int ret; if (data->fixed_divider != 1) { divider_name = devm_kasprintf(cprman->dev, GFP_KERNEL, @@ -1214,32 +1218,33 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, divider->cprman = cprman; divider->data = data; - clk = devm_clk_register(cprman->dev, ÷r->div.hw); - if (IS_ERR(clk)) - return clk; + ret = devm_clk_hw_register(cprman->dev, ÷r->div.hw); + if (ret) + return ERR_PTR(ret); /* * PLLH's channels have a fixed divide by 10 afterwards, which * is what our consumers are actually using. */ if (data->fixed_divider != 1) { - return clk_register_fixed_factor(cprman->dev, data->name, - divider_name, - CLK_SET_RATE_PARENT, - 1, - data->fixed_divider); + return clk_hw_register_fixed_factor(cprman->dev, data->name, + divider_name, + CLK_SET_RATE_PARENT, + 1, + data->fixed_divider); } - return clk; + return ÷r->div.hw; } -static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, +static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, const struct bcm2835_clock_data *data) { struct bcm2835_clock *clock; struct clk_init_data init; const char *parents[1 << CM_SRC_BITS]; size_t i; + int ret; /* * Replace our "xosc" references with the oscillator's @@ -1279,7 +1284,10 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, clock->data = data; clock->hw.init = &init; - return devm_clk_register(cprman->dev, &clock->hw); + ret = devm_clk_hw_register(cprman->dev, &clock->hw); + if (ret) + return ERR_PTR(ret); + return &clock->hw; } static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman, @@ -1291,8 +1299,8 @@ static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman, CM_GATE_BIT, 0, &cprman->regs_lock); } -typedef struct clk *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman, - const void *data); +typedef struct clk_hw *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman, + const void *data); struct bcm2835_clk_desc { bcm2835_clk_register clk_register; const void *data; @@ -1847,7 +1855,7 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) static int bcm2835_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct clk **clks; + struct clk_hw **hws; struct bcm2835_cprman *cprman; struct resource *res; const struct bcm2835_clk_desc *desc; @@ -1855,8 +1863,8 @@ static int bcm2835_clk_probe(struct platform_device *pdev) size_t i; int ret; - cprman = devm_kzalloc(dev, - sizeof(*cprman) + asize * sizeof(*clks), + cprman = devm_kzalloc(dev, sizeof(*cprman) + + sizeof(*cprman->onecell.hws) * asize, GFP_KERNEL); if (!cprman) return -ENOMEM; @@ -1874,22 +1882,21 @@ static int bcm2835_clk_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cprman); - cprman->onecell.clk_num = asize; - cprman->onecell.clks = cprman->clks; - clks = cprman->clks; + cprman->onecell.num = asize; + hws = cprman->onecell.hws; for (i = 0; i < asize; i++) { desc = &clk_desc_array[i]; if (desc->clk_register && desc->data) - clks[i] = desc->clk_register(cprman, desc->data); + hws[i] = desc->clk_register(cprman, desc->data); } - ret = bcm2835_mark_sdc_parent_critical(clks[BCM2835_CLOCK_SDRAM]); + ret = bcm2835_mark_sdc_parent_critical(hws[BCM2835_CLOCK_SDRAM]->clk); if (ret) return ret; - return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, - &cprman->onecell); + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + &cprman->onecell); } static const struct of_device_id bcm2835_clk_of_match[] = { -- cgit v0.10.2 From f5644f10dcfbab90ffd27da1d8d51ffc13e1bc84 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 1 Jun 2016 14:31:22 -0700 Subject: clk: at91: Migrate to clk_hw based registration and OF APIs Now that we have clk_hw based provider APIs to register clks, we can get rid of struct clk pointers in this driver, allowing us to move closer to a clear split of consumer and provider clk APIs. Signed-off-by: Stephen Boyd Acked-by: Alexandre Belloni Tested-by: Alexandre Belloni Acked-by: Boris Brezillon Signed-off-by: Stephen Boyd diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 7f6bec8..4e1cd5a 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -233,14 +233,16 @@ static void clk_generated_startup(struct clk_generated *gck) >> AT91_PMC_PCR_GCKDIV_OFFSET; } -static struct clk * __init -at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char - *name, const char **parent_names, u8 num_parents, - u8 id, const struct clk_range *range) +static struct clk_hw * __init +at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const char *name, const char **parent_names, + u8 num_parents, u8 id, + const struct clk_range *range) { struct clk_generated *gck; - struct clk *clk = NULL; struct clk_init_data init; + struct clk_hw *hw; + int ret; gck = kzalloc(sizeof(*gck), GFP_KERNEL); if (!gck) @@ -258,13 +260,15 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char gck->lock = lock; gck->range = *range; - clk = clk_register(NULL, &gck->hw); - if (IS_ERR(clk)) + hw = &gck->hw; + ret = clk_hw_register(NULL, &gck->hw); + if (ret) { kfree(gck); - else + hw = ERR_PTR(ret); + } else clk_generated_startup(gck); - return clk; + return hw; } static void __init of_sama5d2_clk_generated_setup(struct device_node *np) @@ -272,7 +276,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) int num; u32 id; const char *name; - struct clk *clk; + struct clk_hw *hw; unsigned int num_parents; const char *parent_names[GENERATED_SOURCE_MAX]; struct device_node *gcknp; @@ -306,13 +310,13 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) of_at91_get_clk_range(gcknp, "atmel,clk-output-range", &range); - clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, parent_names, num_parents, id, &range); - if (IS_ERR(clk)) + if (IS_ERR(hw)) continue; - of_clk_add_provider(gcknp, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw); } } CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated", diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 8e20c8a..e0daa4a 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -92,7 +92,7 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) struct clk_init_data init; const char *parent_name; struct regmap *regmap; - struct clk *clk; + int ret; regmap = syscon_node_to_regmap(of_get_parent(np)); if (IS_ERR(regmap)) @@ -113,13 +113,13 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) h32mxclk->hw.init = &init; h32mxclk->regmap = regmap; - clk = clk_register(NULL, &h32mxclk->hw); - if (IS_ERR(clk)) { + ret = clk_hw_register(NULL, &h32mxclk->hw); + if (ret) { kfree(h32mxclk); return; } - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, &h32mxclk->hw); } CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx", of_sama5d4_clk_h32mx_setup); diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index 58b5bac..c813c27 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c @@ -128,15 +128,16 @@ static const struct clk_ops main_osc_ops = { .is_prepared = clk_main_osc_is_prepared, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_main_osc(struct regmap *regmap, const char *name, const char *parent_name, bool bypass) { struct clk_main_osc *osc; - struct clk *clk = NULL; struct clk_init_data init; + struct clk_hw *hw; + int ret; if (!name || !parent_name) return ERR_PTR(-EINVAL); @@ -160,16 +161,19 @@ at91_clk_register_main_osc(struct regmap *regmap, AT91_PMC_MOSCEN, AT91_PMC_OSCBYPASS | AT91_PMC_KEY); - clk = clk_register(NULL, &osc->hw); - if (IS_ERR(clk)) + hw = &osc->hw; + ret = clk_hw_register(NULL, &osc->hw); + if (ret) { kfree(osc); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *name = np->name; const char *parent_name; struct regmap *regmap; @@ -183,11 +187,11 @@ static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91_clk_register_main_osc(regmap, name, parent_name, bypass); - if (IS_ERR(clk)) + hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc", of_at91rm9200_clk_main_osc_setup); @@ -271,14 +275,15 @@ static const struct clk_ops main_rc_osc_ops = { .recalc_accuracy = clk_main_rc_osc_recalc_accuracy, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_main_rc_osc(struct regmap *regmap, const char *name, u32 frequency, u32 accuracy) { struct clk_main_rc_osc *osc; - struct clk *clk = NULL; struct clk_init_data init; + struct clk_hw *hw; + int ret; if (!name || !frequency) return ERR_PTR(-EINVAL); @@ -298,16 +303,19 @@ at91_clk_register_main_rc_osc(struct regmap *regmap, osc->frequency = frequency; osc->accuracy = accuracy; - clk = clk_register(NULL, &osc->hw); - if (IS_ERR(clk)) + hw = &osc->hw; + ret = clk_hw_register(NULL, hw); + if (ret) { kfree(osc); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; u32 frequency = 0; u32 accuracy = 0; const char *name = np->name; @@ -321,11 +329,11 @@ static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy); - if (IS_ERR(clk)) + hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc", of_at91sam9x5_clk_main_rc_osc_setup); @@ -395,14 +403,15 @@ static const struct clk_ops rm9200_main_ops = { .recalc_rate = clk_rm9200_main_recalc_rate, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_rm9200_main(struct regmap *regmap, const char *name, const char *parent_name) { struct clk_rm9200_main *clkmain; - struct clk *clk = NULL; struct clk_init_data init; + struct clk_hw *hw; + int ret; if (!name) return ERR_PTR(-EINVAL); @@ -423,16 +432,19 @@ at91_clk_register_rm9200_main(struct regmap *regmap, clkmain->hw.init = &init; clkmain->regmap = regmap; - clk = clk_register(NULL, &clkmain->hw); - if (IS_ERR(clk)) + hw = &clkmain->hw; + ret = clk_hw_register(NULL, &clkmain->hw); + if (ret) { kfree(clkmain); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91rm9200_clk_main_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *parent_name; const char *name = np->name; struct regmap *regmap; @@ -444,11 +456,11 @@ static void __init of_at91rm9200_clk_main_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91_clk_register_rm9200_main(regmap, name, parent_name); - if (IS_ERR(clk)) + hw = at91_clk_register_rm9200_main(regmap, name, parent_name); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main", of_at91rm9200_clk_main_setup); @@ -529,16 +541,17 @@ static const struct clk_ops sam9x5_main_ops = { .get_parent = clk_sam9x5_main_get_parent, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name, const char **parent_names, int num_parents) { struct clk_sam9x5_main *clkmain; - struct clk *clk = NULL; struct clk_init_data init; unsigned int status; + struct clk_hw *hw; + int ret; if (!name) return ERR_PTR(-EINVAL); @@ -561,16 +574,19 @@ at91_clk_register_sam9x5_main(struct regmap *regmap, regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status); clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0; - clk = clk_register(NULL, &clkmain->hw); - if (IS_ERR(clk)) + hw = &clkmain->hw; + ret = clk_hw_register(NULL, &clkmain->hw); + if (ret) { kfree(clkmain); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91sam9x5_clk_main_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *parent_names[2]; unsigned int num_parents; const char *name = np->name; @@ -587,12 +603,12 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np) of_property_read_string(np, "clock-output-names", &name); - clk = at91_clk_register_sam9x5_main(regmap, name, parent_names, + hw = at91_clk_register_sam9x5_main(regmap, name, parent_names, num_parents); - if (IS_ERR(clk)) + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main", of_at91sam9x5_clk_main_setup); diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index d1021e1..e9cba9f 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -120,7 +120,7 @@ static const struct clk_ops master_ops = { .get_parent = clk_master_get_parent, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_master(struct regmap *regmap, const char *name, int num_parents, const char **parent_names, @@ -128,8 +128,9 @@ at91_clk_register_master(struct regmap *regmap, const struct clk_master_characteristics *characteristics) { struct clk_master *master; - struct clk *clk = NULL; struct clk_init_data init; + struct clk_hw *hw; + int ret; if (!name || !num_parents || !parent_names) return ERR_PTR(-EINVAL); @@ -149,12 +150,14 @@ at91_clk_register_master(struct regmap *regmap, master->characteristics = characteristics; master->regmap = regmap; - clk = clk_register(NULL, &master->hw); - if (IS_ERR(clk)) { + hw = &master->hw; + ret = clk_hw_register(NULL, &master->hw); + if (ret) { kfree(master); + hw = ERR_PTR(ret); } - return clk; + return hw; } @@ -198,7 +201,7 @@ static void __init of_at91_clk_master_setup(struct device_node *np, const struct clk_master_layout *layout) { - struct clk *clk; + struct clk_hw *hw; unsigned int num_parents; const char *parent_names[MASTER_SOURCE_MAX]; const char *name = np->name; @@ -221,13 +224,13 @@ of_at91_clk_master_setup(struct device_node *np, if (IS_ERR(regmap)) return; - clk = at91_clk_register_master(regmap, name, num_parents, + hw = at91_clk_register_master(regmap, name, num_parents, parent_names, layout, characteristics); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto out_free_characteristics; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); return; out_free_characteristics: diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index fd16072..dc29fd9 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -104,13 +104,14 @@ static const struct clk_ops peripheral_ops = { .is_enabled = clk_peripheral_is_enabled, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_peripheral(struct regmap *regmap, const char *name, const char *parent_name, u32 id) { struct clk_peripheral *periph; - struct clk *clk = NULL; struct clk_init_data init; + struct clk_hw *hw; + int ret; if (!name || !parent_name || id > PERIPHERAL_ID_MAX) return ERR_PTR(-EINVAL); @@ -129,11 +130,14 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name, periph->hw.init = &init; periph->regmap = regmap; - clk = clk_register(NULL, &periph->hw); - if (IS_ERR(clk)) + hw = &periph->hw; + ret = clk_hw_register(NULL, &periph->hw); + if (ret) { kfree(periph); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph) @@ -327,14 +331,15 @@ static const struct clk_ops sam9x5_peripheral_ops = { .set_rate = clk_sam9x5_peripheral_set_rate, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, const char *name, const char *parent_name, u32 id, const struct clk_range *range) { struct clk_sam9x5_peripheral *periph; - struct clk *clk = NULL; struct clk_init_data init; + struct clk_hw *hw; + int ret; if (!name || !parent_name) return ERR_PTR(-EINVAL); @@ -357,13 +362,15 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, periph->auto_div = true; periph->range = *range; - clk = clk_register(NULL, &periph->hw); - if (IS_ERR(clk)) + hw = &periph->hw; + ret = clk_hw_register(NULL, &periph->hw); + if (ret) { kfree(periph); - else + hw = ERR_PTR(ret); + } else clk_sam9x5_peripheral_autodiv(periph); - return clk; + return hw; } static void __init @@ -371,7 +378,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) { int num; u32 id; - struct clk *clk; + struct clk_hw *hw; const char *parent_name; const char *name; struct device_node *periphclknp; @@ -400,7 +407,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) name = periphclknp->name; if (type == PERIPHERAL_AT91RM9200) { - clk = at91_clk_register_peripheral(regmap, name, + hw = at91_clk_register_peripheral(regmap, name, parent_name, id); } else { struct clk_range range = CLK_RANGE(0, 0); @@ -409,17 +416,17 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) "atmel,clk-output-range", &range); - clk = at91_clk_register_sam9x5_peripheral(regmap, + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, name, parent_name, id, &range); } - if (IS_ERR(clk)) + if (IS_ERR(hw)) continue; - of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw); } } diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index fb2e0b5..45ad168 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -296,17 +296,18 @@ static const struct clk_ops pll_ops = { .set_rate = clk_pll_set_rate, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_pll(struct regmap *regmap, const char *name, const char *parent_name, u8 id, const struct clk_pll_layout *layout, const struct clk_pll_characteristics *characteristics) { struct clk_pll *pll; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; int offset = PLL_REG(id); unsigned int pllr; + int ret; if (id > PLL_MAX_ID) return ERR_PTR(-EINVAL); @@ -330,12 +331,14 @@ at91_clk_register_pll(struct regmap *regmap, const char *name, pll->div = PLL_DIV(pllr); pll->mul = PLL_MUL(pllr, layout); - clk = clk_register(NULL, &pll->hw); - if (IS_ERR(clk)) { + hw = &pll->hw; + ret = clk_hw_register(NULL, &pll->hw); + if (ret) { kfree(pll); + hw = ERR_PTR(ret); } - return clk; + return hw; } @@ -465,7 +468,7 @@ of_at91_clk_pll_setup(struct device_node *np, const struct clk_pll_layout *layout) { u32 id; - struct clk *clk; + struct clk_hw *hw; struct regmap *regmap; const char *parent_name; const char *name = np->name; @@ -486,12 +489,12 @@ of_at91_clk_pll_setup(struct device_node *np, if (!characteristics) return; - clk = at91_clk_register_pll(regmap, name, parent_name, id, layout, + hw = at91_clk_register_pll(regmap, name, parent_name, id, layout, characteristics); - if (IS_ERR(clk)) + if (IS_ERR(hw)) goto out_free_characteristics; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); return; out_free_characteristics: diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c index 2bed264..b4afaf2 100644 --- a/drivers/clk/at91/clk-plldiv.c +++ b/drivers/clk/at91/clk-plldiv.c @@ -75,13 +75,14 @@ static const struct clk_ops plldiv_ops = { .set_rate = clk_plldiv_set_rate, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_plldiv(struct regmap *regmap, const char *name, const char *parent_name) { struct clk_plldiv *plldiv; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL); if (!plldiv) @@ -96,18 +97,20 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name, plldiv->hw.init = &init; plldiv->regmap = regmap; - clk = clk_register(NULL, &plldiv->hw); - - if (IS_ERR(clk)) + hw = &plldiv->hw; + ret = clk_hw_register(NULL, &plldiv->hw); + if (ret) { kfree(plldiv); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *parent_name; const char *name = np->name; struct regmap *regmap; @@ -120,12 +123,11 @@ of_at91sam9x5_clk_plldiv_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91_clk_register_plldiv(regmap, name, parent_name); - if (IS_ERR(clk)) + hw = at91_clk_register_plldiv(regmap, name, parent_name); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); - return; + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv", of_at91sam9x5_clk_plldiv_setup); diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 25d5906..190122e64 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -170,15 +170,16 @@ static const struct clk_ops programmable_ops = { .set_rate = clk_programmable_set_rate, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_programmable(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents, u8 id, const struct clk_programmable_layout *layout) { struct clk_programmable *prog; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (id > PROG_ID_MAX) return ERR_PTR(-EINVAL); @@ -198,11 +199,14 @@ at91_clk_register_programmable(struct regmap *regmap, prog->hw.init = &init; prog->regmap = regmap; - clk = clk_register(NULL, &prog->hw); - if (IS_ERR(clk)) + hw = &prog->hw; + ret = clk_hw_register(NULL, &prog->hw); + if (ret) { kfree(prog); + hw = &prog->hw; + } - return clk; + return hw; } static const struct clk_programmable_layout at91rm9200_programmable_layout = { @@ -229,7 +233,7 @@ of_at91_clk_prog_setup(struct device_node *np, { int num; u32 id; - struct clk *clk; + struct clk_hw *hw; unsigned int num_parents; const char *parent_names[PROG_SOURCE_MAX]; const char *name; @@ -257,13 +261,13 @@ of_at91_clk_prog_setup(struct device_node *np, if (of_property_read_string(np, "clock-output-names", &name)) name = progclknp->name; - clk = at91_clk_register_programmable(regmap, name, + hw = at91_clk_register_programmable(regmap, name, parent_names, num_parents, id, layout); - if (IS_ERR(clk)) + if (IS_ERR(hw)) continue; - of_clk_add_provider(progclknp, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw); } } diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index 61090b1..cd831e1 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c @@ -111,7 +111,7 @@ static const struct clk_ops slow_osc_ops = { .is_prepared = clk_slow_osc_is_prepared, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_slow_osc(void __iomem *sckcr, const char *name, const char *parent_name, @@ -119,8 +119,9 @@ at91_clk_register_slow_osc(void __iomem *sckcr, bool bypass) { struct clk_slow_osc *osc; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (!sckcr || !name || !parent_name) return ERR_PTR(-EINVAL); @@ -143,17 +144,20 @@ at91_clk_register_slow_osc(void __iomem *sckcr, writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, sckcr); - clk = clk_register(NULL, &osc->hw); - if (IS_ERR(clk)) + hw = &osc->hw; + ret = clk_hw_register(NULL, &osc->hw); + if (ret) { kfree(osc); + hw = ERR_PTR(ret); + } - return clk; + return hw; } void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr) { - struct clk *clk; + struct clk_hw *hw; const char *parent_name; const char *name = np->name; u32 startup; @@ -164,12 +168,12 @@ void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, of_property_read_u32(np, "atmel,startup-time-usec", &startup); bypass = of_property_read_bool(np, "atmel,osc-bypass"); - clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, + hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, bypass); - if (IS_ERR(clk)) + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, @@ -223,7 +227,7 @@ static const struct clk_ops slow_rc_osc_ops = { .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_slow_rc_osc(void __iomem *sckcr, const char *name, unsigned long frequency, @@ -231,8 +235,9 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, unsigned long startup) { struct clk_slow_rc_osc *osc; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (!sckcr || !name) return ERR_PTR(-EINVAL); @@ -253,17 +258,20 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, osc->accuracy = accuracy; osc->startup_usec = startup; - clk = clk_register(NULL, &osc->hw); - if (IS_ERR(clk)) + hw = &osc->hw; + ret = clk_hw_register(NULL, &osc->hw); + if (ret) { kfree(osc); + hw = ERR_PTR(ret); + } - return clk; + return hw; } void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr) { - struct clk *clk; + struct clk_hw *hw; u32 frequency = 0; u32 accuracy = 0; u32 startup = 0; @@ -274,12 +282,12 @@ void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, of_property_read_u32(np, "clock-accuracy", &accuracy); of_property_read_u32(np, "atmel,startup-time-usec", &startup); - clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, + hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, startup); - if (IS_ERR(clk)) + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) @@ -321,15 +329,16 @@ static const struct clk_ops sam9x5_slow_ops = { .get_parent = clk_sam9x5_slow_get_parent, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_sam9x5_slow(void __iomem *sckcr, const char *name, const char **parent_names, int num_parents) { struct clk_sam9x5_slow *slowck; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (!sckcr || !name || !parent_names || !num_parents) return ERR_PTR(-EINVAL); @@ -348,17 +357,20 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, slowck->sckcr = sckcr; slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); - clk = clk_register(NULL, &slowck->hw); - if (IS_ERR(clk)) + hw = &slowck->hw; + ret = clk_hw_register(NULL, &slowck->hw); + if (ret) { kfree(slowck); + hw = ERR_PTR(ret); + } - return clk; + return hw; } void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr) { - struct clk *clk; + struct clk_hw *hw; const char *parent_names[2]; unsigned int num_parents; const char *name = np->name; @@ -371,12 +383,12 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, of_property_read_string(np, "clock-output-names", &name); - clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, + hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, num_parents); - if (IS_ERR(clk)) + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw) @@ -393,15 +405,16 @@ static const struct clk_ops sam9260_slow_ops = { .get_parent = clk_sam9260_slow_get_parent, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_sam9260_slow(struct regmap *regmap, const char *name, const char **parent_names, int num_parents) { struct clk_sam9260_slow *slowck; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (!name) return ERR_PTR(-EINVAL); @@ -422,16 +435,19 @@ at91_clk_register_sam9260_slow(struct regmap *regmap, slowck->hw.init = &init; slowck->regmap = regmap; - clk = clk_register(NULL, &slowck->hw); - if (IS_ERR(clk)) + hw = &slowck->hw; + ret = clk_hw_register(NULL, &slowck->hw); + if (ret) { kfree(slowck); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *parent_names[2]; unsigned int num_parents; const char *name = np->name; @@ -448,12 +464,12 @@ static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) of_property_read_string(np, "clock-output-names", &name); - clk = at91_clk_register_sam9260_slow(regmap, name, parent_names, + hw = at91_clk_register_sam9260_slow(regmap, name, parent_names, num_parents); - if (IS_ERR(clk)) + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow", diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c index 3c04b06..965c662 100644 --- a/drivers/clk/at91/clk-smd.c +++ b/drivers/clk/at91/clk-smd.c @@ -111,13 +111,14 @@ static const struct clk_ops at91sam9x5_smd_ops = { .set_rate = at91sam9x5_clk_smd_set_rate, }; -static struct clk * __init +static struct clk_hw * __init at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents) { struct at91sam9x5_clk_smd *smd; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; smd = kzalloc(sizeof(*smd), GFP_KERNEL); if (!smd) @@ -132,16 +133,19 @@ at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name, smd->hw.init = &init; smd->regmap = regmap; - clk = clk_register(NULL, &smd->hw); - if (IS_ERR(clk)) + hw = &smd->hw; + ret = clk_hw_register(NULL, &smd->hw); + if (ret) { kfree(smd); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; unsigned int num_parents; const char *parent_names[SMD_SOURCE_MAX]; const char *name = np->name; @@ -159,12 +163,12 @@ static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91sam9x5_clk_register_smd(regmap, name, parent_names, + hw = at91sam9x5_clk_register_smd(regmap, name, parent_names, num_parents); - if (IS_ERR(clk)) + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd", of_at91sam9x5_clk_smd_setup); diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index 8f35d81..86a3680 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c @@ -88,13 +88,14 @@ static const struct clk_ops system_ops = { .is_prepared = clk_system_is_prepared, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_system(struct regmap *regmap, const char *name, const char *parent_name, u8 id) { struct clk_system *sys; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; if (!parent_name || id > SYSTEM_MAX_ID) return ERR_PTR(-EINVAL); @@ -113,18 +114,21 @@ at91_clk_register_system(struct regmap *regmap, const char *name, sys->hw.init = &init; sys->regmap = regmap; - clk = clk_register(NULL, &sys->hw); - if (IS_ERR(clk)) + hw = &sys->hw; + ret = clk_hw_register(NULL, &sys->hw); + if (ret) { kfree(sys); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) { int num; u32 id; - struct clk *clk; + struct clk_hw *hw; const char *name; struct device_node *sysclknp; const char *parent_name; @@ -147,11 +151,11 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) parent_name = of_clk_get_parent_name(sysclknp, 0); - clk = at91_clk_register_system(regmap, name, parent_name, id); - if (IS_ERR(clk)) + hw = at91_clk_register_system(regmap, name, parent_name, id); + if (IS_ERR(hw)) continue; - of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw); } } CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system", diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index d80bdb0..791770a 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -192,13 +192,14 @@ static const struct clk_ops at91sam9n12_usb_ops = { .set_rate = at91sam9x5_clk_usb_set_rate, }; -static struct clk * __init +static struct clk_hw * __init at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents) { struct at91sam9x5_clk_usb *usb; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; usb = kzalloc(sizeof(*usb), GFP_KERNEL); if (!usb) @@ -214,20 +215,24 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; - clk = clk_register(NULL, &usb->hw); - if (IS_ERR(clk)) + hw = &usb->hw; + ret = clk_hw_register(NULL, &usb->hw); + if (ret) { kfree(usb); + hw = ERR_PTR(ret); + } - return clk; + return hw; } -static struct clk * __init +static struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name) { struct at91sam9x5_clk_usb *usb; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; usb = kzalloc(sizeof(*usb), GFP_KERNEL); if (!usb) @@ -242,11 +247,14 @@ at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; - clk = clk_register(NULL, &usb->hw); - if (IS_ERR(clk)) + hw = &usb->hw; + ret = clk_hw_register(NULL, &usb->hw); + if (ret) { kfree(usb); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw, @@ -334,13 +342,14 @@ static const struct clk_ops at91rm9200_usb_ops = { .set_rate = at91rm9200_clk_usb_set_rate, }; -static struct clk * __init +static struct clk_hw * __init at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name, const u32 *divisors) { struct at91rm9200_clk_usb *usb; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; usb = kzalloc(sizeof(*usb), GFP_KERNEL); if (!usb) @@ -356,16 +365,19 @@ at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, usb->regmap = regmap; memcpy(usb->divisors, divisors, sizeof(usb->divisors)); - clk = clk_register(NULL, &usb->hw); - if (IS_ERR(clk)) + hw = &usb->hw; + ret = clk_hw_register(NULL, &usb->hw); + if (ret) { kfree(usb); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; unsigned int num_parents; const char *parent_names[USB_SOURCE_MAX]; const char *name = np->name; @@ -383,19 +395,19 @@ static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91sam9x5_clk_register_usb(regmap, name, parent_names, - num_parents); - if (IS_ERR(clk)) + hw = at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb", of_at91sam9x5_clk_usb_setup); static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *parent_name; const char *name = np->name; struct regmap *regmap; @@ -410,18 +422,18 @@ static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91sam9n12_clk_register_usb(regmap, name, parent_name); - if (IS_ERR(clk)) + hw = at91sam9n12_clk_register_usb(regmap, name, parent_name); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb", of_at91sam9n12_clk_usb_setup); static void __init of_at91rm9200_clk_usb_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *parent_name; const char *name = np->name; u32 divisors[4] = {0, 0, 0, 0}; @@ -440,12 +452,11 @@ static void __init of_at91rm9200_clk_usb_setup(struct device_node *np) regmap = syscon_node_to_regmap(of_get_parent(np)); if (IS_ERR(regmap)) return; - - clk = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors); - if (IS_ERR(clk)) + hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); } CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb", of_at91rm9200_clk_usb_setup); diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index 61fcf39..aadabd9 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -77,13 +77,14 @@ static const struct clk_ops utmi_ops = { .recalc_rate = clk_utmi_recalc_rate, }; -static struct clk * __init +static struct clk_hw * __init at91_clk_register_utmi(struct regmap *regmap, const char *name, const char *parent_name) { struct clk_utmi *utmi; - struct clk *clk = NULL; + struct clk_hw *hw; struct clk_init_data init; + int ret; utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); if (!utmi) @@ -98,16 +99,19 @@ at91_clk_register_utmi(struct regmap *regmap, utmi->hw.init = &init; utmi->regmap = regmap; - clk = clk_register(NULL, &utmi->hw); - if (IS_ERR(clk)) + hw = &utmi->hw; + ret = clk_hw_register(NULL, &utmi->hw); + if (ret) { kfree(utmi); + hw = ERR_PTR(ret); + } - return clk; + return hw; } static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) { - struct clk *clk; + struct clk_hw *hw; const char *parent_name; const char *name = np->name; struct regmap *regmap; @@ -120,11 +124,11 @@ static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) if (IS_ERR(regmap)) return; - clk = at91_clk_register_utmi(regmap, name, parent_name); - if (IS_ERR(clk)) + hw = at91_clk_register_utmi(regmap, name, parent_name); + if (IS_ERR(hw)) return; - of_clk_add_provider(np, of_clk_src_simple_get, clk); + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); return; } CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi", -- cgit v0.10.2 From 7df404c9856deec4cea1538ef4786116e3fbf2e5 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Mon, 29 Aug 2016 14:26:53 +0200 Subject: drivers: clk: st: Remove stih415-416 clock support STiH415 and STiH416 platforms are no longer used. these platforms will be deprecated for the next kernel. Signed-off-by: Gabriel Fernandez Acked-by: Rob Herring Acked-by: Peter Griffin Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-divmux.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-divmux.txt deleted file mode 100644 index 6247652..0000000 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-divmux.txt +++ /dev/null @@ -1,49 +0,0 @@ -Binding for a ST divider and multiplexer clock driver. - -This binding uses the common clock binding[1]. -Base address is located to the parent node. See clock binding[2] - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt - -Required properties: - -- compatible : shall be: - "st,clkgena-divmux-c65-hs", "st,clkgena-divmux" - "st,clkgena-divmux-c65-ls", "st,clkgena-divmux" - "st,clkgena-divmux-c32-odf0", "st,clkgena-divmux" - "st,clkgena-divmux-c32-odf1", "st,clkgena-divmux" - "st,clkgena-divmux-c32-odf2", "st,clkgena-divmux" - "st,clkgena-divmux-c32-odf3", "st,clkgena-divmux" - -- #clock-cells : From common clock binding; shall be set to 1. - -- clocks : From common clock binding - -- clock-output-names : From common clock binding. - -Example: - - clockgen-a@fd345000 { - reg = <0xfd345000 0xb50>; - - clk_m_a1_div1: clk-m-a1-div1 { - #clock-cells = <1>; - compatible = "st,clkgena-divmux-c32-odf1", - "st,clkgena-divmux"; - - clocks = <&clk_m_a1_osc_prediv>, - <&clk_m_a1_pll0 1>, /* PLL0 PHI1 */ - <&clk_m_a1_pll1 1>; /* PLL1 PHI1 */ - - clock-output-names = "clk-m-rx-icn-ts", - "clk-m-rx-icn-vdp-0", - "", /* unused */ - "clk-m-prv-t1-bus", - "clk-m-icn-reg-12", - "clk-m-icn-reg-10", - "", /* unused */ - "clk-m-icn-st231"; - }; - }; - diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt index f1fa91c..4d277d6 100644 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt +++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt @@ -10,13 +10,6 @@ This binding uses the common clock binding[1]. Required properties: - compatible : shall be: - "st,stih416-clkgenc-vcc-hd", "st,clkgen-mux" - "st,stih416-clkgenf-vcc-fvdp", "st,clkgen-mux" - "st,stih416-clkgenf-vcc-hva", "st,clkgen-mux" - "st,stih416-clkgenf-vcc-hd", "st,clkgen-mux" - "st,stih416-clkgenf-vcc-sd", "st,clkgen-mux" - "st,stih415-clkgen-a9-mux", "st,clkgen-mux" - "st,stih416-clkgen-a9-mux", "st,clkgen-mux" "st,stih407-clkgen-a9-mux", "st,clkgen-mux" - #clock-cells : from common clock binding; shall be set to 0. @@ -27,10 +20,13 @@ Required properties: Example: - clk_m_hva: clk-m-hva@fd690868 { + clk_m_a9: clk-m-a9@92b0000 { #clock-cells = <0>; - compatible = "st,stih416-clkgenf-vcc-hva", "st,clkgen-mux"; - reg = <0xfd690868 4>; + compatible = "st,stih407-clkgen-a9-mux"; + reg = <0x92b0000 0x10000>; - clocks = <&clockgen_f 1>, <&clk_m_a1_div0 3>; + clocks = <&clockgen_a9_pll 0>, + <&clockgen_a9_pll 0>, + <&clk_s_c0_flexgen 13>, + <&clk_m_a9_ext2f_div2>; }; diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt index 844b3a0..c9fd674 100644 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt +++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt @@ -9,25 +9,12 @@ Base address is located to the parent node. See clock binding[2] Required properties: - compatible : shall be: - "st,clkgena-prediv-c65", "st,clkgena-prediv" - "st,clkgena-prediv-c32", "st,clkgena-prediv" - - "st,clkgena-plls-c65" - "st,plls-c32-a1x-0", "st,clkgen-plls-c32" - "st,plls-c32-a1x-1", "st,clkgen-plls-c32" - "st,stih415-plls-c32-a9", "st,clkgen-plls-c32" - "st,stih415-plls-c32-ddr", "st,clkgen-plls-c32" - "st,stih416-plls-c32-a9", "st,clkgen-plls-c32" - "st,stih416-plls-c32-ddr", "st,clkgen-plls-c32" "st,stih407-plls-c32-a0", "st,clkgen-plls-c32" "st,stih407-plls-c32-a9", "st,clkgen-plls-c32" "sst,plls-c32-cx_0", "st,clkgen-plls-c32" "sst,plls-c32-cx_1", "st,clkgen-plls-c32" "st,stih418-plls-c28-a9", "st,clkgen-plls-c32" - "st,stih415-gpu-pll-c32", "st,clkgengpu-pll-c32" - "st,stih416-gpu-pll-c32", "st,clkgengpu-pll-c32" - - #clock-cells : From common clock binding; shall be set to 1. - clocks : From common clock binding @@ -36,17 +23,16 @@ Required properties: Example: - clockgen-a@fee62000 { - reg = <0xfee62000 0xb48>; + clockgen-a9@92b0000 { + compatible = "st,clkgen-c32"; + reg = <0x92b0000 0xffff>; - clk_s_a0_pll: clk-s-a0-pll { + clockgen_a9_pll: clockgen-a9-pll { #clock-cells = <1>; - compatible = "st,clkgena-plls-c65"; + compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; - clock-output-names = "clk-s-a0-pll0-hs", - "clk-s-a0-pll0-ls", - "clk-s-a0-pll1"; + clock-output-names = "clockgen-a9-pll-odf"; }; }; diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-prediv.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-prediv.txt deleted file mode 100644 index 604766c..0000000 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-prediv.txt +++ /dev/null @@ -1,36 +0,0 @@ -Binding for a ST pre-divider clock driver. - -This binding uses the common clock binding[1]. -Base address is located to the parent node. See clock binding[2] - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt - -Required properties: - -- compatible : shall be: - "st,clkgena-prediv-c65", "st,clkgena-prediv" - "st,clkgena-prediv-c32", "st,clkgena-prediv" - -- #clock-cells : From common clock binding; shall be set to 0. - -- clocks : From common clock binding - -- clock-output-names : From common clock binding. - -Example: - - clockgen-a@fd345000 { - reg = <0xfd345000 0xb50>; - - clk_m_a2_osc_prediv: clk-m-a2-osc-prediv { - #clock-cells = <0>; - compatible = "st,clkgena-prediv-c32", - "st,clkgena-prediv"; - - clocks = <&clk_sysin>; - - clock-output-names = "clk-m-a2-osc-prediv"; - }; - }; - diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-vcc.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-vcc.txt deleted file mode 100644 index 109b3ed..0000000 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-vcc.txt +++ /dev/null @@ -1,61 +0,0 @@ -Binding for a type of STMicroelectronics clock crossbar (VCC). - -The crossbar can take up to 4 input clocks and control up to 16 -output clocks. Not all inputs or outputs have to be in use in a -particular instantiation. Each output can be individually enabled, -select any of the input clocks and apply a divide (by 1,2,4 or 8) to -that selected clock. - -This binding uses the common clock binding[1]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: - -- compatible : shall be: - "st,stih416-clkgenc", "st,vcc" - "st,stih416-clkgenf", "st,vcc" - -- #clock-cells : from common clock binding; shall be set to 1. - -- reg : A Base address and length of the register set. - -- clocks : from common clock binding - -- clock-output-names : From common clock binding. The block has 16 - clock outputs but not all of them in a specific instance - have to be used in the SoC. If a clock name is left as - an empty string then no clock will be created for the - output associated with that string index. If fewer than - 16 strings are provided then no clocks will be created - for the remaining outputs. - -Example: - - clockgen_c_vcc: clockgen-c-vcc@0xfe8308ac { - #clock-cells = <1>; - compatible = "st,stih416-clkgenc", "st,clkgen-vcc"; - reg = <0xfe8308ac 12>; - - clocks = <&clk_s_vcc_hd>, - <&clockgen_c 1>, - <&clk_s_tmds_fromphy>, - <&clockgen_c 2>; - - clock-output-names = "clk-s-pix-hdmi", - "clk-s-pix-dvo", - "clk-s-out-dvo", - "clk-s-pix-hd", - "clk-s-hddac", - "clk-s-denc", - "clk-s-sddac", - "clk-s-pix-main", - "clk-s-pix-aux", - "clk-s-stfe-frc-0", - "clk-s-ref-mcru", - "clk-s-slave-mcru", - "clk-s-tmds-hdmi", - "clk-s-hdmi-reject-pll", - "clk-s-thsens"; - }; - diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen.txt index b18bf86..c764d6b 100644 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen.txt +++ b/Documentation/devicetree/bindings/clock/st/st,clkgen.txt @@ -13,14 +13,6 @@ address is common of all subnode. ... }; - prediv_node { - ... - }; - - divmux_node { - ... - }; - quadfs_node { ... }; @@ -29,10 +21,6 @@ address is common of all subnode. ... }; - vcc_node { - ... - }; - flexgen_node { ... }; @@ -43,11 +31,8 @@ This binding uses the common clock binding[1]. Each subnode should use the binding described in [2]..[7] [1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Documentation/devicetree/bindings/clock/st,clkgen-divmux.txt [3] Documentation/devicetree/bindings/clock/st,clkgen-mux.txt [4] Documentation/devicetree/bindings/clock/st,clkgen-pll.txt -[5] Documentation/devicetree/bindings/clock/st,clkgen-prediv.txt -[6] Documentation/devicetree/bindings/clock/st,vcc.txt [7] Documentation/devicetree/bindings/clock/st,quadfs.txt [8] Documentation/devicetree/bindings/clock/st,flexgen.txt @@ -57,44 +42,27 @@ Required properties: Example: - clockgen-a@fee62000 { - - reg = <0xfee62000 0xb48>; + clockgen-a@090ff000 { + compatible = "st,clkgen-c32"; + reg = <0x90ff000 0x1000>; clk_s_a0_pll: clk-s-a0-pll { #clock-cells = <1>; - compatible = "st,clkgena-plls-c65"; - - clocks = <&clk-sysin>; - - clock-output-names = "clk-s-a0-pll0-hs", - "clk-s-a0-pll0-ls", - "clk-s-a0-pll1"; - }; - - clk_s_a0_osc_prediv: clk-s-a0-osc-prediv { - #clock-cells = <0>; - compatible = "st,clkgena-prediv-c65", - "st,clkgena-prediv"; + compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32"; clocks = <&clk_sysin>; - clock-output-names = "clk-s-a0-osc-prediv"; + clock-output-names = "clk-s-a0-pll-ofd-0"; }; - clk_s_a0_hs: clk-s-a0-hs { + clk_s_a0_flexgen: clk-s-a0-flexgen { + compatible = "st,flexgen"; + #clock-cells = <1>; - compatible = "st,clkgena-divmux-c65-hs", - "st,clkgena-divmux"; - clocks = <&clk-s_a0_osc_prediv>, - <&clk-s_a0_pll 0>, /* pll0 hs */ - <&clk-s_a0_pll 2>; /* pll1 */ + clocks = <&clk_s_a0_pll 0>, + <&clk_sysin>; - clock-output-names = "clk-s-fdma-0", - "clk-s-fdma-1", - ""; /* clk-s-jit-sense */ - /* fourth output unused */ + clock-output-names = "clk-ic-lmi0"; }; }; - diff --git a/Documentation/devicetree/bindings/clock/st/st,quadfs.txt b/Documentation/devicetree/bindings/clock/st/st,quadfs.txt index cedeb9c..6d81b11 100644 --- a/Documentation/devicetree/bindings/clock/st/st,quadfs.txt +++ b/Documentation/devicetree/bindings/clock/st/st,quadfs.txt @@ -11,10 +11,6 @@ This binding uses the common clock binding[1]. Required properties: - compatible : shall be: - "st,stih416-quadfs216", "st,quadfs" - "st,stih416-quadfs432", "st,quadfs" - "st,stih416-quadfs660-E", "st,quadfs" - "st,stih416-quadfs660-F", "st,quadfs" "st,stih407-quadfs660-C", "st,quadfs" "st,stih407-quadfs660-D", "st,quadfs" @@ -35,14 +31,15 @@ Required properties: Example: - clockgen_e: clockgen-e@fd3208bc { - #clock-cells = <1>; - compatible = "st,stih416-quadfs660-E", "st,quadfs"; - reg = <0xfd3208bc 0xB0>; - - clocks = <&clk_sysin>; - clock-output-names = "clk-m-pix-mdtp-0", - "clk-m-pix-mdtp-1", - "clk-m-pix-mdtp-2", - "clk-m-mpelpc"; - }; + clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 { + #clock-cells = <1>; + compatible = "st,stih407-quadfs660-C", "st,quadfs"; + reg = <0x9103000 0x1000>; + + clocks = <&clk_sysin>; + + clock-output-names = "clk-s-c0-fs0-ch0", + "clk-s-c0-fs0-ch1", + "clk-s-c0-fs0-ch2", + "clk-s-c0-fs0-ch3"; + }; diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 09afeb8..942c187 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -42,45 +42,6 @@ struct stm_fs { unsigned long nsdiv; }; -static const struct stm_fs fs216c65_rtbl[] = { - { .mdiv = 0x1f, .pe = 0x0, .sdiv = 0x7, .nsdiv = 0 }, /* 312.5 Khz */ - { .mdiv = 0x17, .pe = 0x25ed, .sdiv = 0x1, .nsdiv = 0 }, /* 27 MHz */ - { .mdiv = 0x1a, .pe = 0x7b36, .sdiv = 0x2, .nsdiv = 1 }, /* 36.87 MHz */ - { .mdiv = 0x13, .pe = 0x0, .sdiv = 0x2, .nsdiv = 1 }, /* 48 MHz */ - { .mdiv = 0x11, .pe = 0x1c72, .sdiv = 0x1, .nsdiv = 1 }, /* 108 MHz */ -}; - -static const struct stm_fs fs432c65_rtbl[] = { - { .mdiv = 0x1f, .pe = 0x0, .sdiv = 0x7, .nsdiv = 0 }, /* 625 Khz */ - { .mdiv = 0x13, .pe = 0x777c, .sdiv = 0x4, .nsdiv = 1 }, /* 25.175 MHz */ - { .mdiv = 0x19, .pe = 0x4d35, .sdiv = 0x2, .nsdiv = 0 }, /* 25.200 MHz */ - { .mdiv = 0x11, .pe = 0x1c72, .sdiv = 0x4, .nsdiv = 1 }, /* 27.000 MHz */ - { .mdiv = 0x17, .pe = 0x28f5, .sdiv = 0x2, .nsdiv = 0 }, /* 27.027 MHz */ - { .mdiv = 0x16, .pe = 0x3359, .sdiv = 0x2, .nsdiv = 0 }, /* 28.320 MHz */ - { .mdiv = 0x1f, .pe = 0x2083, .sdiv = 0x3, .nsdiv = 1 }, /* 30.240 MHz */ - { .mdiv = 0x1e, .pe = 0x430d, .sdiv = 0x3, .nsdiv = 1 }, /* 31.500 MHz */ - { .mdiv = 0x17, .pe = 0x0, .sdiv = 0x3, .nsdiv = 1 }, /* 40.000 MHz */ - { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x1, .nsdiv = 0 }, /* 49.500 MHz */ - { .mdiv = 0x13, .pe = 0x6667, .sdiv = 0x3, .nsdiv = 1 }, /* 50.000 MHz */ - { .mdiv = 0x10, .pe = 0x1ee6, .sdiv = 0x3, .nsdiv = 1 }, /* 57.284 MHz */ - { .mdiv = 0x1d, .pe = 0x3b14, .sdiv = 0x2, .nsdiv = 1 }, /* 65.000 MHz */ - { .mdiv = 0x12, .pe = 0x7c65, .sdiv = 0x1, .nsdiv = 0 }, /* 71.000 MHz */ - { .mdiv = 0x19, .pe = 0xecd, .sdiv = 0x2, .nsdiv = 1 }, /* 74.176 MHz */ - { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x2, .nsdiv = 1 }, /* 74.250 MHz */ - { .mdiv = 0x19, .pe = 0x3334, .sdiv = 0x2, .nsdiv = 1 }, /* 75.000 MHz */ - { .mdiv = 0x18, .pe = 0x5138, .sdiv = 0x2, .nsdiv = 1 }, /* 78.800 MHz */ - { .mdiv = 0x1d, .pe = 0x77d, .sdiv = 0x0, .nsdiv = 0 }, /* 85.500 MHz */ - { .mdiv = 0x1c, .pe = 0x13d5, .sdiv = 0x0, .nsdiv = 0 }, /* 88.750 MHz */ - { .mdiv = 0x11, .pe = 0x1c72, .sdiv = 0x2, .nsdiv = 1 }, /* 108.000 MHz */ - { .mdiv = 0x17, .pe = 0x28f5, .sdiv = 0x0, .nsdiv = 0 }, /* 108.108 MHz */ - { .mdiv = 0x10, .pe = 0x6e26, .sdiv = 0x2, .nsdiv = 1 }, /* 118.963 MHz */ - { .mdiv = 0x15, .pe = 0x3e63, .sdiv = 0x0, .nsdiv = 0 }, /* 119.000 MHz */ - { .mdiv = 0x1c, .pe = 0x471d, .sdiv = 0x1, .nsdiv = 1 }, /* 135.000 MHz */ - { .mdiv = 0x19, .pe = 0xecd, .sdiv = 0x1, .nsdiv = 1 }, /* 148.352 MHz */ - { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x1, .nsdiv = 1 }, /* 148.500 MHz */ - { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x0, .nsdiv = 1 }, /* 297 MHz */ -}; - static const struct stm_fs fs660c32_rtbl[] = { { .mdiv = 0x14, .pe = 0x376b, .sdiv = 0x4, .nsdiv = 1 }, /* 25.175 MHz */ { .mdiv = 0x14, .pe = 0x30c3, .sdiv = 0x4, .nsdiv = 1 }, /* 25.200 MHz */ @@ -144,168 +105,11 @@ struct clkgen_quadfs_data { unsigned long *); }; -static const struct clk_ops st_quadfs_pll_c65_ops; static const struct clk_ops st_quadfs_pll_c32_ops; -static const struct clk_ops st_quadfs_fs216c65_ops; -static const struct clk_ops st_quadfs_fs432c65_ops; static const struct clk_ops st_quadfs_fs660c32_ops; -static int clk_fs216c65_get_rate(unsigned long, const struct stm_fs *, - unsigned long *); -static int clk_fs432c65_get_rate(unsigned long, const struct stm_fs *, - unsigned long *); static int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *, unsigned long *); -/* - * Values for all of the standalone instances of this clock - * generator found in STiH415 and STiH416 SYSCFG register banks. Note - * that the individual channel standby control bits (nsb) are in the - * first register along with the PLL control bits. - */ -static const struct clkgen_quadfs_data st_fs216c65_416 = { - /* 416 specific */ - .npda = CLKGEN_FIELD(0x0, 0x1, 14), - .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), - CLKGEN_FIELD(0x0, 0x1, 11), - CLKGEN_FIELD(0x0, 0x1, 12), - CLKGEN_FIELD(0x0, 0x1, 13) }, - .nsdiv_present = true, - .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), - CLKGEN_FIELD(0x0, 0x1, 19), - CLKGEN_FIELD(0x0, 0x1, 20), - CLKGEN_FIELD(0x0, 0x1, 21) }, - .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), - CLKGEN_FIELD(0x14, 0x1f, 0), - CLKGEN_FIELD(0x24, 0x1f, 0), - CLKGEN_FIELD(0x34, 0x1f, 0) }, - .en = { CLKGEN_FIELD(0x10, 0x1, 0), - CLKGEN_FIELD(0x20, 0x1, 0), - CLKGEN_FIELD(0x30, 0x1, 0), - CLKGEN_FIELD(0x40, 0x1, 0) }, - .ndiv = CLKGEN_FIELD(0x0, 0x1, 15), - .bwfilter_present = true, - .ref_bw = CLKGEN_FIELD(0x0, 0x3, 16), - .pe = { CLKGEN_FIELD(0x8, 0xffff, 0), - CLKGEN_FIELD(0x18, 0xffff, 0), - CLKGEN_FIELD(0x28, 0xffff, 0), - CLKGEN_FIELD(0x38, 0xffff, 0) }, - .sdiv = { CLKGEN_FIELD(0xC, 0x7, 0), - CLKGEN_FIELD(0x1C, 0x7, 0), - CLKGEN_FIELD(0x2C, 0x7, 0), - CLKGEN_FIELD(0x3C, 0x7, 0) }, - .pll_ops = &st_quadfs_pll_c65_ops, - .rtbl = fs216c65_rtbl, - .rtbl_cnt = ARRAY_SIZE(fs216c65_rtbl), - .get_rate = clk_fs216c65_get_rate, -}; - -static const struct clkgen_quadfs_data st_fs432c65_416 = { - .npda = CLKGEN_FIELD(0x0, 0x1, 14), - .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), - CLKGEN_FIELD(0x0, 0x1, 11), - CLKGEN_FIELD(0x0, 0x1, 12), - CLKGEN_FIELD(0x0, 0x1, 13) }, - .nsdiv_present = true, - .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), - CLKGEN_FIELD(0x0, 0x1, 19), - CLKGEN_FIELD(0x0, 0x1, 20), - CLKGEN_FIELD(0x0, 0x1, 21) }, - .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), - CLKGEN_FIELD(0x14, 0x1f, 0), - CLKGEN_FIELD(0x24, 0x1f, 0), - CLKGEN_FIELD(0x34, 0x1f, 0) }, - .en = { CLKGEN_FIELD(0x10, 0x1, 0), - CLKGEN_FIELD(0x20, 0x1, 0), - CLKGEN_FIELD(0x30, 0x1, 0), - CLKGEN_FIELD(0x40, 0x1, 0) }, - .ndiv = CLKGEN_FIELD(0x0, 0x1, 15), - .bwfilter_present = true, - .ref_bw = CLKGEN_FIELD(0x0, 0x3, 16), - .pe = { CLKGEN_FIELD(0x8, 0xffff, 0), - CLKGEN_FIELD(0x18, 0xffff, 0), - CLKGEN_FIELD(0x28, 0xffff, 0), - CLKGEN_FIELD(0x38, 0xffff, 0) }, - .sdiv = { CLKGEN_FIELD(0xC, 0x7, 0), - CLKGEN_FIELD(0x1C, 0x7, 0), - CLKGEN_FIELD(0x2C, 0x7, 0), - CLKGEN_FIELD(0x3C, 0x7, 0) }, - .pll_ops = &st_quadfs_pll_c65_ops, - .rtbl = fs432c65_rtbl, - .rtbl_cnt = ARRAY_SIZE(fs432c65_rtbl), - .get_rate = clk_fs432c65_get_rate, -}; - -static const struct clkgen_quadfs_data st_fs660c32_E_416 = { - .npda = CLKGEN_FIELD(0x0, 0x1, 14), - .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), - CLKGEN_FIELD(0x0, 0x1, 11), - CLKGEN_FIELD(0x0, 0x1, 12), - CLKGEN_FIELD(0x0, 0x1, 13) }, - .nsdiv_present = true, - .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), - CLKGEN_FIELD(0x0, 0x1, 19), - CLKGEN_FIELD(0x0, 0x1, 20), - CLKGEN_FIELD(0x0, 0x1, 21) }, - .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), - CLKGEN_FIELD(0x14, 0x1f, 0), - CLKGEN_FIELD(0x24, 0x1f, 0), - CLKGEN_FIELD(0x34, 0x1f, 0) }, - .en = { CLKGEN_FIELD(0x10, 0x1, 0), - CLKGEN_FIELD(0x20, 0x1, 0), - CLKGEN_FIELD(0x30, 0x1, 0), - CLKGEN_FIELD(0x40, 0x1, 0) }, - .ndiv = CLKGEN_FIELD(0x0, 0x7, 15), - .pe = { CLKGEN_FIELD(0x8, 0x7fff, 0), - CLKGEN_FIELD(0x18, 0x7fff, 0), - CLKGEN_FIELD(0x28, 0x7fff, 0), - CLKGEN_FIELD(0x38, 0x7fff, 0) }, - .sdiv = { CLKGEN_FIELD(0xC, 0xf, 0), - CLKGEN_FIELD(0x1C, 0xf, 0), - CLKGEN_FIELD(0x2C, 0xf, 0), - CLKGEN_FIELD(0x3C, 0xf, 0) }, - .lockstatus_present = true, - .lock_status = CLKGEN_FIELD(0xAC, 0x1, 0), - .pll_ops = &st_quadfs_pll_c32_ops, - .rtbl = fs660c32_rtbl, - .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), - .get_rate = clk_fs660c32_dig_get_rate, -}; - -static const struct clkgen_quadfs_data st_fs660c32_F_416 = { - .npda = CLKGEN_FIELD(0x0, 0x1, 14), - .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), - CLKGEN_FIELD(0x0, 0x1, 11), - CLKGEN_FIELD(0x0, 0x1, 12), - CLKGEN_FIELD(0x0, 0x1, 13) }, - .nsdiv_present = true, - .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), - CLKGEN_FIELD(0x0, 0x1, 19), - CLKGEN_FIELD(0x0, 0x1, 20), - CLKGEN_FIELD(0x0, 0x1, 21) }, - .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), - CLKGEN_FIELD(0x14, 0x1f, 0), - CLKGEN_FIELD(0x24, 0x1f, 0), - CLKGEN_FIELD(0x34, 0x1f, 0) }, - .en = { CLKGEN_FIELD(0x10, 0x1, 0), - CLKGEN_FIELD(0x20, 0x1, 0), - CLKGEN_FIELD(0x30, 0x1, 0), - CLKGEN_FIELD(0x40, 0x1, 0) }, - .ndiv = CLKGEN_FIELD(0x0, 0x7, 15), - .pe = { CLKGEN_FIELD(0x8, 0x7fff, 0), - CLKGEN_FIELD(0x18, 0x7fff, 0), - CLKGEN_FIELD(0x28, 0x7fff, 0), - CLKGEN_FIELD(0x38, 0x7fff, 0) }, - .sdiv = { CLKGEN_FIELD(0xC, 0xf, 0), - CLKGEN_FIELD(0x1C, 0xf, 0), - CLKGEN_FIELD(0x2C, 0xf, 0), - CLKGEN_FIELD(0x3C, 0xf, 0) }, - .lockstatus_present = true, - .lock_status = CLKGEN_FIELD(0xEC, 0x1, 0), - .pll_ops = &st_quadfs_pll_c32_ops, - .rtbl = fs660c32_rtbl, - .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), - .get_rate = clk_fs660c32_dig_get_rate, -}; static const struct clkgen_quadfs_data st_fs660c32_C = { .nrst_present = true, @@ -605,12 +409,6 @@ static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static const struct clk_ops st_quadfs_pll_c65_ops = { - .enable = quadfs_pll_enable, - .disable = quadfs_pll_disable, - .is_enabled = quadfs_pll_is_enabled, -}; - static const struct clk_ops st_quadfs_pll_c32_ops = { .enable = quadfs_pll_enable, .disable = quadfs_pll_disable, @@ -797,48 +595,6 @@ static int quadfs_fsynth_is_enabled(struct clk_hw *hw) return fs->data->standby_polarity ? !nsb : !!nsb; } -#define P15 (uint64_t)(1 << 15) - -static int clk_fs216c65_get_rate(unsigned long input, const struct stm_fs *fs, - unsigned long *rate) -{ - uint64_t res; - unsigned long ns; - unsigned long nd = 8; /* ndiv stuck at 0 => val = 8 */ - unsigned long s; - long m; - - m = fs->mdiv - 32; - s = 1 << (fs->sdiv + 1); - ns = (fs->nsdiv ? 1 : 3); - - res = (uint64_t)(s * ns * P15 * (uint64_t)(m + 33)); - res = res - (s * ns * fs->pe); - *rate = div64_u64(P15 * nd * input * 32, res); - - return 0; -} - -static int clk_fs432c65_get_rate(unsigned long input, const struct stm_fs *fs, - unsigned long *rate) -{ - uint64_t res; - unsigned long nd = 16; /* ndiv value; stuck at 0 (30Mhz input) */ - long m; - unsigned long sd; - unsigned long ns; - - m = fs->mdiv - 32; - sd = 1 << (fs->sdiv + 1); - ns = (fs->nsdiv ? 1 : 3); - - res = (uint64_t)(sd * ns * P15 * (uint64_t)(m + 33)); - res = res - (sd * ns * fs->pe); - *rate = div64_u64(P15 * nd * input * 32, res); - - return 0; -} - #define P20 (uint64_t)(1 << 20) static int clk_fs660c32_dig_get_rate(unsigned long input, @@ -1065,22 +821,6 @@ static struct clk * __init st_clk_register_quadfs_fsynth( static const struct of_device_id quadfs_of_match[] = { { - .compatible = "st,stih416-quadfs216", - .data = &st_fs216c65_416 - }, - { - .compatible = "st,stih416-quadfs432", - .data = &st_fs432c65_416 - }, - { - .compatible = "st,stih416-quadfs660-E", - .data = &st_fs660c32_E_416 - }, - { - .compatible = "st,stih416-quadfs660-F", - .data = &st_fs660c32_F_416 - }, - { .compatible = "st,stih407-quadfs660-C", .data = &st_fs660c32_C }, diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index b1e10ff..6fdb1ab 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -19,9 +19,6 @@ #include #include "clkgen.h" -static DEFINE_SPINLOCK(clkgena_divmux_lock); -static DEFINE_SPINLOCK(clkgenf_lock); - static const char ** __init clkgen_mux_get_parents(struct device_node *np, int *num_parents) { @@ -40,498 +37,6 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np, return parents; } -/** - * DOC: Clock mux with a programmable divider on each of its three inputs. - * The mux has an input setting which effectively gates its output. - * - * Traits of this clock: - * prepare - clk_(un)prepare only ensures parent is (un)prepared - * enable - clk_enable and clk_disable are functional & control gating - * rate - set rate is supported - * parent - set/get parent - */ - -#define NUM_INPUTS 3 - -struct clkgena_divmux { - struct clk_hw hw; - /* Subclassed mux and divider structures */ - struct clk_mux mux; - struct clk_divider div[NUM_INPUTS]; - /* Enable/running feedback register bits for each input */ - void __iomem *feedback_reg[NUM_INPUTS]; - int feedback_bit_idx; - - u8 muxsel; -}; - -#define to_clkgena_divmux(_hw) container_of(_hw, struct clkgena_divmux, hw) - -struct clkgena_divmux_data { - int num_outputs; - int mux_offset; - int mux_offset2; - int mux_start_bit; - int div_offsets[NUM_INPUTS]; - int fb_offsets[NUM_INPUTS]; - int fb_start_bit_idx; -}; - -#define CKGAX_CLKOPSRC_SWITCH_OFF 0x3 - -static int clkgena_divmux_is_running(struct clkgena_divmux *mux) -{ - u32 regval = readl(mux->feedback_reg[mux->muxsel]); - u32 running = regval & BIT(mux->feedback_bit_idx); - return !!running; -} - -static int clkgena_divmux_enable(struct clk_hw *hw) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - struct clk_hw *mux_hw = &genamux->mux.hw; - unsigned long timeout; - int ret = 0; - - __clk_hw_set_clk(mux_hw, hw); - - ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel); - if (ret) - return ret; - - timeout = jiffies + msecs_to_jiffies(10); - - while (!clkgena_divmux_is_running(genamux)) { - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - cpu_relax(); - } - - return 0; -} - -static void clkgena_divmux_disable(struct clk_hw *hw) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - struct clk_hw *mux_hw = &genamux->mux.hw; - - __clk_hw_set_clk(mux_hw, hw); - - clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF); -} - -static int clkgena_divmux_is_enabled(struct clk_hw *hw) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - struct clk_hw *mux_hw = &genamux->mux.hw; - - __clk_hw_set_clk(mux_hw, hw); - - return (s8)clk_mux_ops.get_parent(mux_hw) > 0; -} - -static u8 clkgena_divmux_get_parent(struct clk_hw *hw) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - struct clk_hw *mux_hw = &genamux->mux.hw; - - __clk_hw_set_clk(mux_hw, hw); - - genamux->muxsel = clk_mux_ops.get_parent(mux_hw); - if ((s8)genamux->muxsel < 0) { - pr_debug("%s: %s: Invalid parent, setting to default.\n", - __func__, clk_hw_get_name(hw)); - genamux->muxsel = 0; - } - - return genamux->muxsel; -} - -static int clkgena_divmux_set_parent(struct clk_hw *hw, u8 index) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - - if (index >= CKGAX_CLKOPSRC_SWITCH_OFF) - return -EINVAL; - - genamux->muxsel = index; - - /* - * If the mux is already enabled, call enable directly to set the - * new mux position and wait for it to start running again. Otherwise - * do nothing. - */ - if (clkgena_divmux_is_enabled(hw)) - clkgena_divmux_enable(hw); - - return 0; -} - -static unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; - - __clk_hw_set_clk(div_hw, hw); - - return clk_divider_ops.recalc_rate(div_hw, parent_rate); -} - -static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; - - __clk_hw_set_clk(div_hw, hw); - - return clk_divider_ops.set_rate(div_hw, rate, parent_rate); -} - -static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clkgena_divmux *genamux = to_clkgena_divmux(hw); - struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; - - __clk_hw_set_clk(div_hw, hw); - - return clk_divider_ops.round_rate(div_hw, rate, prate); -} - -static const struct clk_ops clkgena_divmux_ops = { - .enable = clkgena_divmux_enable, - .disable = clkgena_divmux_disable, - .is_enabled = clkgena_divmux_is_enabled, - .get_parent = clkgena_divmux_get_parent, - .set_parent = clkgena_divmux_set_parent, - .round_rate = clkgena_divmux_round_rate, - .recalc_rate = clkgena_divmux_recalc_rate, - .set_rate = clkgena_divmux_set_rate, -}; - -/** - * clk_register_genamux - register a genamux clock with the clock framework - */ -static struct clk * __init clk_register_genamux(const char *name, - const char **parent_names, u8 num_parents, - void __iomem *reg, - const struct clkgena_divmux_data *muxdata, - u32 idx) -{ - /* - * Fixed constants across all ClockgenA variants - */ - const int mux_width = 2; - const int divider_width = 5; - struct clkgena_divmux *genamux; - struct clk *clk; - struct clk_init_data init; - int i; - - genamux = kzalloc(sizeof(*genamux), GFP_KERNEL); - if (!genamux) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &clkgena_divmux_ops; - init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; - init.parent_names = parent_names; - init.num_parents = num_parents; - - genamux->mux.lock = &clkgena_divmux_lock; - genamux->mux.mask = BIT(mux_width) - 1; - genamux->mux.shift = muxdata->mux_start_bit + (idx * mux_width); - if (genamux->mux.shift > 31) { - /* - * We have spilled into the second mux register so - * adjust the register address and the bit shift accordingly - */ - genamux->mux.reg = reg + muxdata->mux_offset2; - genamux->mux.shift -= 32; - } else { - genamux->mux.reg = reg + muxdata->mux_offset; - } - - for (i = 0; i < NUM_INPUTS; i++) { - /* - * Divider config for each input - */ - void __iomem *divbase = reg + muxdata->div_offsets[i]; - genamux->div[i].width = divider_width; - genamux->div[i].reg = divbase + (idx * sizeof(u32)); - - /* - * Mux enabled/running feedback register for each input. - */ - genamux->feedback_reg[i] = reg + muxdata->fb_offsets[i]; - } - - genamux->feedback_bit_idx = muxdata->fb_start_bit_idx + idx; - genamux->hw.init = &init; - - clk = clk_register(NULL, &genamux->hw); - if (IS_ERR(clk)) { - kfree(genamux); - goto err; - } - - pr_debug("%s: parent %s rate %lu\n", - __clk_get_name(clk), - __clk_get_name(clk_get_parent(clk)), - clk_get_rate(clk)); -err: - return clk; -} - -static struct clkgena_divmux_data st_divmux_c65hs = { - .num_outputs = 4, - .mux_offset = 0x14, - .mux_start_bit = 0, - .div_offsets = { 0x800, 0x900, 0xb00 }, - .fb_offsets = { 0x18, 0x1c, 0x20 }, - .fb_start_bit_idx = 0, -}; - -static struct clkgena_divmux_data st_divmux_c65ls = { - .num_outputs = 14, - .mux_offset = 0x14, - .mux_offset2 = 0x24, - .mux_start_bit = 8, - .div_offsets = { 0x810, 0xa10, 0xb10 }, - .fb_offsets = { 0x18, 0x1c, 0x20 }, - .fb_start_bit_idx = 4, -}; - -static struct clkgena_divmux_data st_divmux_c32odf0 = { - .num_outputs = 8, - .mux_offset = 0x1c, - .mux_start_bit = 0, - .div_offsets = { 0x800, 0x900, 0xa60 }, - .fb_offsets = { 0x2c, 0x24, 0x28 }, - .fb_start_bit_idx = 0, -}; - -static struct clkgena_divmux_data st_divmux_c32odf1 = { - .num_outputs = 8, - .mux_offset = 0x1c, - .mux_start_bit = 16, - .div_offsets = { 0x820, 0x980, 0xa80 }, - .fb_offsets = { 0x2c, 0x24, 0x28 }, - .fb_start_bit_idx = 8, -}; - -static struct clkgena_divmux_data st_divmux_c32odf2 = { - .num_outputs = 8, - .mux_offset = 0x20, - .mux_start_bit = 0, - .div_offsets = { 0x840, 0xa20, 0xb10 }, - .fb_offsets = { 0x2c, 0x24, 0x28 }, - .fb_start_bit_idx = 16, -}; - -static struct clkgena_divmux_data st_divmux_c32odf3 = { - .num_outputs = 8, - .mux_offset = 0x20, - .mux_start_bit = 16, - .div_offsets = { 0x860, 0xa40, 0xb30 }, - .fb_offsets = { 0x2c, 0x24, 0x28 }, - .fb_start_bit_idx = 24, -}; - -static const struct of_device_id clkgena_divmux_of_match[] = { - { - .compatible = "st,clkgena-divmux-c65-hs", - .data = &st_divmux_c65hs, - }, - { - .compatible = "st,clkgena-divmux-c65-ls", - .data = &st_divmux_c65ls, - }, - { - .compatible = "st,clkgena-divmux-c32-odf0", - .data = &st_divmux_c32odf0, - }, - { - .compatible = "st,clkgena-divmux-c32-odf1", - .data = &st_divmux_c32odf1, - }, - { - .compatible = "st,clkgena-divmux-c32-odf2", - .data = &st_divmux_c32odf2, - }, - { - .compatible = "st,clkgena-divmux-c32-odf3", - .data = &st_divmux_c32odf3, - }, - {} -}; - -static void __iomem * __init clkgen_get_register_base(struct device_node *np) -{ - struct device_node *pnode; - void __iomem *reg; - - pnode = of_get_parent(np); - if (!pnode) - return NULL; - - reg = of_iomap(pnode, 0); - - of_node_put(pnode); - return reg; -} - -static void __init st_of_clkgena_divmux_setup(struct device_node *np) -{ - const struct of_device_id *match; - const struct clkgena_divmux_data *data; - struct clk_onecell_data *clk_data; - void __iomem *reg; - const char **parents; - int num_parents = 0, i; - - match = of_match_node(clkgena_divmux_of_match, np); - if (WARN_ON(!match)) - return; - - data = match->data; - - reg = clkgen_get_register_base(np); - if (!reg) - return; - - parents = clkgen_mux_get_parents(np, &num_parents); - if (IS_ERR(parents)) - goto err_parents; - - clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); - if (!clk_data) - goto err_alloc; - - clk_data->clk_num = data->num_outputs; - clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *), - GFP_KERNEL); - - if (!clk_data->clks) - goto err_alloc_clks; - - for (i = 0; i < clk_data->clk_num; i++) { - struct clk *clk; - const char *clk_name; - - if (of_property_read_string_index(np, "clock-output-names", - i, &clk_name)) - break; - - /* - * If we read an empty clock name then the output is unused - */ - if (*clk_name == '\0') - continue; - - clk = clk_register_genamux(clk_name, parents, num_parents, - reg, data, i); - - if (IS_ERR(clk)) - goto err; - - clk_data->clks[i] = clk; - } - - kfree(parents); - - of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); - return; -err: - kfree(clk_data->clks); -err_alloc_clks: - kfree(clk_data); -err_alloc: - kfree(parents); -err_parents: - iounmap(reg); -} -CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup); - -struct clkgena_prediv_data { - u32 offset; - u8 shift; - struct clk_div_table *table; -}; - -static struct clk_div_table prediv_table16[] = { - { .val = 0, .div = 1 }, - { .val = 1, .div = 16 }, - { .div = 0 }, -}; - -static struct clkgena_prediv_data prediv_c65_data = { - .offset = 0x4c, - .shift = 31, - .table = prediv_table16, -}; - -static struct clkgena_prediv_data prediv_c32_data = { - .offset = 0x50, - .shift = 1, - .table = prediv_table16, -}; - -static const struct of_device_id clkgena_prediv_of_match[] = { - { .compatible = "st,clkgena-prediv-c65", .data = &prediv_c65_data }, - { .compatible = "st,clkgena-prediv-c32", .data = &prediv_c32_data }, - {} -}; - -static void __init st_of_clkgena_prediv_setup(struct device_node *np) -{ - const struct of_device_id *match; - void __iomem *reg; - const char *parent_name, *clk_name; - struct clk *clk; - const struct clkgena_prediv_data *data; - - match = of_match_node(clkgena_prediv_of_match, np); - if (!match) { - pr_err("%s: No matching data\n", __func__); - return; - } - - data = match->data; - - reg = clkgen_get_register_base(np); - if (!reg) - return; - - parent_name = of_clk_get_parent_name(np, 0); - if (!parent_name) - goto err; - - if (of_property_read_string_index(np, "clock-output-names", - 0, &clk_name)) - goto err; - - clk = clk_register_divider_table(NULL, clk_name, parent_name, - CLK_GET_RATE_NOCACHE, - reg + data->offset, data->shift, 1, - 0, data->table, NULL); - if (IS_ERR(clk)) - goto err; - - of_clk_add_provider(np, of_clk_src_simple_get, clk); - pr_debug("%s: parent %s rate %u\n", - __clk_get_name(clk), - __clk_get_name(clk_get_parent(clk)), - (unsigned int)clk_get_rate(clk)); - - return; -err: - iounmap(reg); -} -CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup); - struct clkgen_mux_data { u32 offset; u8 shift; @@ -541,49 +46,6 @@ struct clkgen_mux_data { u8 mux_flags; }; -static struct clkgen_mux_data clkgen_mux_c_vcc_hd_416 = { - .offset = 0, - .shift = 0, - .width = 1, -}; - -static struct clkgen_mux_data clkgen_mux_f_vcc_fvdp_416 = { - .offset = 0, - .shift = 0, - .width = 1, -}; - -static struct clkgen_mux_data clkgen_mux_f_vcc_hva_416 = { - .offset = 0, - .shift = 0, - .width = 1, -}; - -static struct clkgen_mux_data clkgen_mux_f_vcc_hd_416 = { - .offset = 0, - .shift = 16, - .width = 1, - .lock = &clkgenf_lock, -}; - -static struct clkgen_mux_data clkgen_mux_c_vcc_sd_416 = { - .offset = 0, - .shift = 17, - .width = 1, - .lock = &clkgenf_lock, -}; - -static struct clkgen_mux_data stih415_a9_mux_data = { - .offset = 0, - .shift = 1, - .width = 2, - .lock = &clkgen_a9_lock, -}; -static struct clkgen_mux_data stih416_a9_mux_data = { - .offset = 0, - .shift = 0, - .width = 2, -}; static struct clkgen_mux_data stih407_a9_mux_data = { .offset = 0x1a4, .shift = 0, @@ -593,47 +55,18 @@ static struct clkgen_mux_data stih407_a9_mux_data = { static const struct of_device_id mux_of_match[] = { { - .compatible = "st,stih416-clkgenc-vcc-hd", - .data = &clkgen_mux_c_vcc_hd_416, - }, - { - .compatible = "st,stih416-clkgenf-vcc-fvdp", - .data = &clkgen_mux_f_vcc_fvdp_416, - }, - { - .compatible = "st,stih416-clkgenf-vcc-hva", - .data = &clkgen_mux_f_vcc_hva_416, - }, - { - .compatible = "st,stih416-clkgenf-vcc-hd", - .data = &clkgen_mux_f_vcc_hd_416, - }, - { - .compatible = "st,stih416-clkgenf-vcc-sd", - .data = &clkgen_mux_c_vcc_sd_416, - }, - { - .compatible = "st,stih415-clkgen-a9-mux", - .data = &stih415_a9_mux_data, - }, - { - .compatible = "st,stih416-clkgen-a9-mux", - .data = &stih416_a9_mux_data, - }, - { .compatible = "st,stih407-clkgen-a9-mux", .data = &stih407_a9_mux_data, }, {} }; - static void __init st_of_clkgen_mux_setup(struct device_node *np) { const struct of_device_id *match; struct clk *clk; void __iomem *reg; const char **parents; - int num_parents; + int num_parents = 0; const struct clkgen_mux_data *data; match = of_match_node(mux_of_match, np); @@ -680,160 +113,3 @@ err_parents: iounmap(reg); } CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup); - -#define VCC_MAX_CHANNELS 16 - -#define VCC_GATE_OFFSET 0x0 -#define VCC_MUX_OFFSET 0x4 -#define VCC_DIV_OFFSET 0x8 - -struct clkgen_vcc_data { - spinlock_t *lock; - unsigned long clk_flags; -}; - -static struct clkgen_vcc_data st_clkgenc_vcc_416 = { - .clk_flags = CLK_SET_RATE_PARENT, -}; - -static struct clkgen_vcc_data st_clkgenf_vcc_416 = { - .lock = &clkgenf_lock, -}; - -static const struct of_device_id vcc_of_match[] = { - { .compatible = "st,stih416-clkgenc", .data = &st_clkgenc_vcc_416 }, - { .compatible = "st,stih416-clkgenf", .data = &st_clkgenf_vcc_416 }, - {} -}; - -static void __init st_of_clkgen_vcc_setup(struct device_node *np) -{ - const struct of_device_id *match; - void __iomem *reg; - const char **parents; - int num_parents, i; - struct clk_onecell_data *clk_data; - const struct clkgen_vcc_data *data; - - match = of_match_node(vcc_of_match, np); - if (WARN_ON(!match)) - return; - data = match->data; - - reg = of_iomap(np, 0); - if (!reg) - return; - - parents = clkgen_mux_get_parents(np, &num_parents); - if (IS_ERR(parents)) - goto err_parents; - - clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); - if (!clk_data) - goto err_alloc; - - clk_data->clk_num = VCC_MAX_CHANNELS; - clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *), - GFP_KERNEL); - - if (!clk_data->clks) - goto err_alloc_clks; - - for (i = 0; i < clk_data->clk_num; i++) { - struct clk *clk; - const char *clk_name; - struct clk_gate *gate; - struct clk_divider *div; - struct clk_mux *mux; - - if (of_property_read_string_index(np, "clock-output-names", - i, &clk_name)) - break; - - /* - * If we read an empty clock name then the output is unused - */ - if (*clk_name == '\0') - continue; - - gate = kzalloc(sizeof(*gate), GFP_KERNEL); - if (!gate) - goto err; - - div = kzalloc(sizeof(*div), GFP_KERNEL); - if (!div) { - kfree(gate); - goto err; - } - - mux = kzalloc(sizeof(*mux), GFP_KERNEL); - if (!mux) { - kfree(gate); - kfree(div); - goto err; - } - - gate->reg = reg + VCC_GATE_OFFSET; - gate->bit_idx = i; - gate->flags = CLK_GATE_SET_TO_DISABLE; - gate->lock = data->lock; - - div->reg = reg + VCC_DIV_OFFSET; - div->shift = 2 * i; - div->width = 2; - div->flags = CLK_DIVIDER_POWER_OF_TWO | - CLK_DIVIDER_ROUND_CLOSEST; - - mux->reg = reg + VCC_MUX_OFFSET; - mux->shift = 2 * i; - mux->mask = 0x3; - - clk = clk_register_composite(NULL, clk_name, parents, - num_parents, - &mux->hw, &clk_mux_ops, - &div->hw, &clk_divider_ops, - &gate->hw, &clk_gate_ops, - data->clk_flags | - CLK_GET_RATE_NOCACHE); - if (IS_ERR(clk)) { - kfree(gate); - kfree(div); - kfree(mux); - goto err; - } - - pr_debug("%s: parent %s rate %u\n", - __clk_get_name(clk), - __clk_get_name(clk_get_parent(clk)), - (unsigned int)clk_get_rate(clk)); - - clk_data->clks[i] = clk; - } - - kfree(parents); - - of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); - return; - -err: - for (i = 0; i < clk_data->clk_num; i++) { - struct clk_composite *composite; - - if (!clk_data->clks[i]) - continue; - - composite = to_clk_composite(__clk_get_hw(clk_data->clks[i])); - kfree(to_clk_gate(composite->gate_hw)); - kfree(to_clk_divider(composite->rate_hw)); - kfree(to_clk_mux(composite->mux_hw)); - } - - kfree(clk_data->clks); -err_alloc_clks: - kfree(clk_data); -err_alloc: - kfree(parents); -err_parents: - iounmap(reg); -} -CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup); diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index 0b5990e..8a1b1cf 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -26,14 +26,6 @@ static DEFINE_SPINLOCK(clkgena_c32_odf_lock); DEFINE_SPINLOCK(clkgen_a9_lock); /* - * Common PLL configuration register bits for PLL800 and PLL1600 C65 - */ -#define C65_MDIV_PLL800_MASK (0xff) -#define C65_MDIV_PLL1600_MASK (0x7) -#define C65_NDIV_MASK (0xff) -#define C65_PDIV_MASK (0x7) - -/* * PLL configuration register bits for PLL3200 C32 */ #define C32_NDIV_MASK (0xff) @@ -70,144 +62,10 @@ struct clkgen_pll_data { const struct clk_ops *ops; }; -static const struct clk_ops st_pll1600c65_ops; -static const struct clk_ops st_pll800c65_ops; static const struct clk_ops stm_pll3200c32_ops; static const struct clk_ops stm_pll3200c32_a9_ops; -static const struct clk_ops st_pll1200c32_ops; static const struct clk_ops stm_pll4600c28_ops; -static const struct clkgen_pll_data st_pll1600c65_ax = { - .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), - .pdn_ctrl = CLKGEN_FIELD(0x10, 0x1, 0), - .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), - .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL1600_MASK, 0), - .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), - .ops = &st_pll1600c65_ops -}; - -static const struct clkgen_pll_data st_pll800c65_ax = { - .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), - .pdn_ctrl = CLKGEN_FIELD(0xC, 0x1, 1), - .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), - .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL800_MASK, 0), - .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), - .pdiv = CLKGEN_FIELD(0x0, C65_PDIV_MASK, 16), - .ops = &st_pll800c65_ops -}; - -static const struct clkgen_pll_data st_pll3200c32_a1x_0 = { - .pdn_status = CLKGEN_FIELD(0x0, 0x1, 31), - .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 0), - .locked_status = CLKGEN_FIELD(0x4, 0x1, 31), - .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 0x0), - .idf = CLKGEN_FIELD(0x4, C32_IDF_MASK, 0x0), - .num_odfs = 4, - .odf = { CLKGEN_FIELD(0x54, C32_ODF_MASK, 4), - CLKGEN_FIELD(0x54, C32_ODF_MASK, 10), - CLKGEN_FIELD(0x54, C32_ODF_MASK, 16), - CLKGEN_FIELD(0x54, C32_ODF_MASK, 22) }, - .odf_gate = { CLKGEN_FIELD(0x54, 0x1, 0), - CLKGEN_FIELD(0x54, 0x1, 1), - CLKGEN_FIELD(0x54, 0x1, 2), - CLKGEN_FIELD(0x54, 0x1, 3) }, - .ops = &stm_pll3200c32_ops, -}; - -static const struct clkgen_pll_data st_pll3200c32_a1x_1 = { - .pdn_status = CLKGEN_FIELD(0xC, 0x1, 31), - .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 1), - .locked_status = CLKGEN_FIELD(0x10, 0x1, 31), - .ndiv = CLKGEN_FIELD(0xC, C32_NDIV_MASK, 0x0), - .idf = CLKGEN_FIELD(0x10, C32_IDF_MASK, 0x0), - .num_odfs = 4, - .odf = { CLKGEN_FIELD(0x58, C32_ODF_MASK, 4), - CLKGEN_FIELD(0x58, C32_ODF_MASK, 10), - CLKGEN_FIELD(0x58, C32_ODF_MASK, 16), - CLKGEN_FIELD(0x58, C32_ODF_MASK, 22) }, - .odf_gate = { CLKGEN_FIELD(0x58, 0x1, 0), - CLKGEN_FIELD(0x58, 0x1, 1), - CLKGEN_FIELD(0x58, 0x1, 2), - CLKGEN_FIELD(0x58, 0x1, 3) }, - .ops = &stm_pll3200c32_ops, -}; - -/* 415 specific */ -static const struct clkgen_pll_data st_pll3200c32_a9_415 = { - .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), - .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), - .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), - .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 9), - .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 22), - .num_odfs = 1, - .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 3) }, - .odf_gate = { CLKGEN_FIELD(0x0, 0x1, 28) }, - .ops = &stm_pll3200c32_ops, -}; - -static const struct clkgen_pll_data st_pll3200c32_ddr_415 = { - .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), - .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), - .locked_status = CLKGEN_FIELD(0x100, 0x1, 0), - .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), - .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), - .num_odfs = 2, - .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), - CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, - .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), - CLKGEN_FIELD(0x4, 0x1, 29) }, - .ops = &stm_pll3200c32_ops, -}; - -static const struct clkgen_pll_data st_pll1200c32_gpu_415 = { - .pdn_status = CLKGEN_FIELD(0x4, 0x1, 0), - .pdn_ctrl = CLKGEN_FIELD(0x4, 0x1, 0), - .locked_status = CLKGEN_FIELD(0x168, 0x1, 0), - .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), - .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), - .num_odfs = 0, - .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, - .ops = &st_pll1200c32_ops, -}; - -/* 416 specific */ -static const struct clkgen_pll_data st_pll3200c32_a9_416 = { - .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), - .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), - .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), - .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), - .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), - .num_odfs = 1, - .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8) }, - .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28) }, - .ops = &stm_pll3200c32_ops, -}; - -static const struct clkgen_pll_data st_pll3200c32_ddr_416 = { - .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), - .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), - .locked_status = CLKGEN_FIELD(0x10C, 0x1, 0), - .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), - .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), - .num_odfs = 2, - .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), - CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, - .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), - CLKGEN_FIELD(0x4, 0x1, 29) }, - .ops = &stm_pll3200c32_ops, -}; - -static const struct clkgen_pll_data st_pll1200c32_gpu_416 = { - .pdn_status = CLKGEN_FIELD(0x8E4, 0x1, 3), - .pdn_ctrl = CLKGEN_FIELD(0x8E4, 0x1, 3), - .locked_status = CLKGEN_FIELD(0x90C, 0x1, 0), - .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), - .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), - .num_odfs = 0, - .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, - .ops = &st_pll1200c32_ops, -}; - static const struct clkgen_pll_data st_pll3200c32_407_a0 = { /* 407 A0 */ .pdn_status = CLKGEN_FIELD(0x2a0, 0x1, 8), @@ -410,57 +268,6 @@ static void clkgen_pll_disable(struct clk_hw *hw) spin_unlock_irqrestore(pll->lock, flags); } -static unsigned long recalc_stm_pll800c65(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clkgen_pll *pll = to_clkgen_pll(hw); - unsigned long mdiv, ndiv, pdiv; - unsigned long rate; - uint64_t res; - - if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) - return 0; - - pdiv = CLKGEN_READ(pll, pdiv); - mdiv = CLKGEN_READ(pll, mdiv); - ndiv = CLKGEN_READ(pll, ndiv); - - if (!mdiv) - mdiv++; /* mdiv=0 or 1 => MDIV=1 */ - - res = (uint64_t)2 * (uint64_t)parent_rate * (uint64_t)ndiv; - rate = (unsigned long)div64_u64(res, mdiv * (1 << pdiv)); - - pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); - - return rate; - -} - -static unsigned long recalc_stm_pll1600c65(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clkgen_pll *pll = to_clkgen_pll(hw); - unsigned long mdiv, ndiv; - unsigned long rate; - - if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) - return 0; - - mdiv = CLKGEN_READ(pll, mdiv); - ndiv = CLKGEN_READ(pll, ndiv); - - if (!mdiv) - mdiv = 1; - - /* Note: input is divided by 1000 to avoid overflow */ - rate = ((2 * (parent_rate / 1000) * ndiv) / mdiv) * 1000; - - pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); - - return rate; -} - static int clk_pll3200c32_get_params(unsigned long input, unsigned long output, struct stm_pll *pll) { @@ -608,33 +415,6 @@ static int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, return 0; } -static unsigned long recalc_stm_pll1200c32(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clkgen_pll *pll = to_clkgen_pll(hw); - unsigned long odf, ldf, idf; - unsigned long rate; - - if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) - return 0; - - odf = CLKGEN_READ(pll, odf[0]); - ldf = CLKGEN_READ(pll, ldf); - idf = CLKGEN_READ(pll, idf); - - if (!idf) /* idf==0 means 1 */ - idf = 1; - if (!odf) /* odf==0 means 1 */ - odf = 1; - - /* Note: input is divided by 1000 to avoid overflow */ - rate = (((parent_rate / 1000) * ldf) / (odf * idf)) * 1000; - - pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); - - return rate; -} - /* PLL output structure * FVCO >> /2 >> FVCOBY2 (no output) * |> Divider (ODF) >> PHI @@ -792,20 +572,6 @@ static int set_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate, return 0; } -static const struct clk_ops st_pll1600c65_ops = { - .enable = clkgen_pll_enable, - .disable = clkgen_pll_disable, - .is_enabled = clkgen_pll_is_enabled, - .recalc_rate = recalc_stm_pll1600c65, -}; - -static const struct clk_ops st_pll800c65_ops = { - .enable = clkgen_pll_enable, - .disable = clkgen_pll_disable, - .is_enabled = clkgen_pll_is_enabled, - .recalc_rate = recalc_stm_pll800c65, -}; - static const struct clk_ops stm_pll3200c32_ops = { .enable = clkgen_pll_enable, .disable = clkgen_pll_disable, @@ -822,13 +588,6 @@ static const struct clk_ops stm_pll3200c32_a9_ops = { .set_rate = set_rate_stm_pll3200c32, }; -static const struct clk_ops st_pll1200c32_ops = { - .enable = clkgen_pll_enable, - .disable = clkgen_pll_disable, - .is_enabled = clkgen_pll_is_enabled, - .recalc_rate = recalc_stm_pll1200c32, -}; - static const struct clk_ops stm_pll4600c28_ops = { .enable = clkgen_pll_enable, .disable = clkgen_pll_disable, @@ -877,22 +636,6 @@ static struct clk * __init clkgen_pll_register(const char *parent_name, return clk; } -static struct clk * __init clkgen_c65_lsdiv_register(const char *parent_name, - const char *clk_name) -{ - struct clk *clk; - - clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, 1, 2); - if (IS_ERR(clk)) - return clk; - - pr_debug("%s: parent %s rate %lu\n", - __clk_get_name(clk), - __clk_get_name(clk_get_parent(clk)), - clk_get_rate(clk)); - return clk; -} - static void __iomem * __init clkgen_get_register_base( struct device_node *np) { @@ -909,89 +652,6 @@ static void __iomem * __init clkgen_get_register_base( return reg; } -#define CLKGENAx_PLL0_OFFSET 0x0 -#define CLKGENAx_PLL1_OFFSET 0x4 - -static void __init clkgena_c65_pll_setup(struct device_node *np) -{ - const int num_pll_outputs = 3; - struct clk_onecell_data *clk_data; - const char *parent_name; - void __iomem *reg; - const char *clk_name; - - parent_name = of_clk_get_parent_name(np, 0); - if (!parent_name) - return; - - reg = clkgen_get_register_base(np); - if (!reg) - return; - - clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); - if (!clk_data) - return; - - clk_data->clk_num = num_pll_outputs; - clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), - GFP_KERNEL); - - if (!clk_data->clks) - goto err; - - if (of_property_read_string_index(np, "clock-output-names", - 0, &clk_name)) - goto err; - - /* - * PLL0 HS (high speed) output - */ - clk_data->clks[0] = clkgen_pll_register(parent_name, - (struct clkgen_pll_data *) &st_pll1600c65_ax, - reg + CLKGENAx_PLL0_OFFSET, 0, clk_name, NULL); - - if (IS_ERR(clk_data->clks[0])) - goto err; - - if (of_property_read_string_index(np, "clock-output-names", - 1, &clk_name)) - goto err; - - /* - * PLL0 LS (low speed) output, which is a fixed divide by 2 of the - * high speed output. - */ - clk_data->clks[1] = clkgen_c65_lsdiv_register(__clk_get_name - (clk_data->clks[0]), - clk_name); - - if (IS_ERR(clk_data->clks[1])) - goto err; - - if (of_property_read_string_index(np, "clock-output-names", - 2, &clk_name)) - goto err; - - /* - * PLL1 output - */ - clk_data->clks[2] = clkgen_pll_register(parent_name, - (struct clkgen_pll_data *) &st_pll800c65_ax, - reg + CLKGENAx_PLL1_OFFSET, 0, clk_name, NULL); - - if (IS_ERR(clk_data->clks[2])) - goto err; - - of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); - return; - -err: - kfree(clk_data->clks); - kfree(clk_data); -} -CLK_OF_DECLARE(clkgena_c65_plls, - "st,clkgena-plls-c65", clkgena_c65_pll_setup); - static struct clk * __init clkgen_odf_register(const char *parent_name, void __iomem *reg, struct clkgen_pll_data *pll_data, @@ -1044,30 +704,6 @@ static struct clk * __init clkgen_odf_register(const char *parent_name, static const struct of_device_id c32_pll_of_match[] = { { - .compatible = "st,plls-c32-a1x-0", - .data = &st_pll3200c32_a1x_0, - }, - { - .compatible = "st,plls-c32-a1x-1", - .data = &st_pll3200c32_a1x_1, - }, - { - .compatible = "st,stih415-plls-c32-a9", - .data = &st_pll3200c32_a9_415, - }, - { - .compatible = "st,stih415-plls-c32-ddr", - .data = &st_pll3200c32_ddr_415, - }, - { - .compatible = "st,stih416-plls-c32-a9", - .data = &st_pll3200c32_a9_416, - }, - { - .compatible = "st,stih416-plls-c32-ddr", - .data = &st_pll3200c32_ddr_416, - }, - { .compatible = "st,stih407-plls-c32-a0", .data = &st_pll3200c32_407_a0, }, @@ -1167,58 +803,3 @@ err: kfree(clk_data); } CLK_OF_DECLARE(clkgen_c32_pll, "st,clkgen-plls-c32", clkgen_c32_pll_setup); - -static const struct of_device_id c32_gpu_pll_of_match[] = { - { - .compatible = "st,stih415-gpu-pll-c32", - .data = &st_pll1200c32_gpu_415, - }, - { - .compatible = "st,stih416-gpu-pll-c32", - .data = &st_pll1200c32_gpu_416, - }, - {} -}; - -static void __init clkgengpu_c32_pll_setup(struct device_node *np) -{ - const struct of_device_id *match; - struct clk *clk; - const char *parent_name; - void __iomem *reg; - const char *clk_name; - struct clkgen_pll_data *data; - - match = of_match_node(c32_gpu_pll_of_match, np); - if (!match) { - pr_err("%s: No matching data\n", __func__); - return; - } - - data = (struct clkgen_pll_data *)match->data; - - parent_name = of_clk_get_parent_name(np, 0); - if (!parent_name) - return; - - reg = clkgen_get_register_base(np); - if (!reg) - return; - - if (of_property_read_string_index(np, "clock-output-names", - 0, &clk_name)) - return; - - /* - * PLL 1200MHz output - */ - clk = clkgen_pll_register(parent_name, data, reg, - 0, clk_name, data->lock); - - if (!IS_ERR(clk)) - of_clk_add_provider(np, of_clk_src_simple_get, clk); - - return; -} -CLK_OF_DECLARE(clkgengpu_c32_pll, - "st,clkgengpu-pll-c32", clkgengpu_c32_pll_setup); -- cgit v0.10.2 From 880d54ff564181b4d9fff31f7f81807cf60cd85d Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Mon, 29 Aug 2016 14:26:54 +0200 Subject: drivers: clk: st: Simplify clock binding of STiH4xx platforms This patch reworks the clock binding to avoid too much detail in DT. Now we have only compatible string per type of clock (remark from Rob https://lkml.org/lkml/2016/5/25/492) Signed-off-by: Gabriel Fernandez Acked-by: Peter Griffin Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt index 4d277d6..9a46cb1 100644 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt +++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt @@ -10,7 +10,7 @@ This binding uses the common clock binding[1]. Required properties: - compatible : shall be: - "st,stih407-clkgen-a9-mux", "st,clkgen-mux" + "st,stih407-clkgen-a9-mux" - #clock-cells : from common clock binding; shall be set to 0. diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt index c9fd674..f207053 100644 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt +++ b/Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt @@ -9,11 +9,10 @@ Base address is located to the parent node. See clock binding[2] Required properties: - compatible : shall be: - "st,stih407-plls-c32-a0", "st,clkgen-plls-c32" - "st,stih407-plls-c32-a9", "st,clkgen-plls-c32" - "sst,plls-c32-cx_0", "st,clkgen-plls-c32" - "sst,plls-c32-cx_1", "st,clkgen-plls-c32" - "st,stih418-plls-c28-a9", "st,clkgen-plls-c32" + "st,clkgen-pll0" + "st,clkgen-pll1" + "st,stih407-clkgen-plla9" + "st,stih418-clkgen-plla9" - #clock-cells : From common clock binding; shall be set to 1. @@ -29,7 +28,7 @@ Example: clockgen_a9_pll: clockgen-a9-pll { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32"; + compatible = "st,stih407-clkgen-plla9"; clocks = <&clk_sysin>; diff --git a/Documentation/devicetree/bindings/clock/st/st,clkgen.txt b/Documentation/devicetree/bindings/clock/st/st,clkgen.txt index c764d6b..c35390f 100644 --- a/Documentation/devicetree/bindings/clock/st/st,clkgen.txt +++ b/Documentation/devicetree/bindings/clock/st/st,clkgen.txt @@ -48,7 +48,7 @@ Example: clk_s_a0_pll: clk-s-a0-pll { #clock-cells = <1>; - compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32"; + compatible = "st,clkgen-pll0"; clocks = <&clk_sysin>; diff --git a/Documentation/devicetree/bindings/clock/st/st,quadfs.txt b/Documentation/devicetree/bindings/clock/st/st,quadfs.txt index 6d81b11..d93d493 100644 --- a/Documentation/devicetree/bindings/clock/st/st,quadfs.txt +++ b/Documentation/devicetree/bindings/clock/st/st,quadfs.txt @@ -11,8 +11,8 @@ This binding uses the common clock binding[1]. Required properties: - compatible : shall be: - "st,stih407-quadfs660-C", "st,quadfs" - "st,stih407-quadfs660-D", "st,quadfs" + "st,quadfs" + "st,quadfs-pll" - #clock-cells : from common clock binding; shall be set to 1. @@ -33,7 +33,7 @@ Example: clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 { #clock-cells = <1>; - compatible = "st,stih407-quadfs660-C", "st,quadfs"; + compatible = "st,quadfs-pll"; reg = <0x9103000 0x1000>; clocks = <&clk_sysin>; diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 942c187..2f11bbd 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -819,18 +819,6 @@ static struct clk * __init st_clk_register_quadfs_fsynth( return clk; } -static const struct of_device_id quadfs_of_match[] = { - { - .compatible = "st,stih407-quadfs660-C", - .data = &st_fs660c32_C - }, - { - .compatible = "st,stih407-quadfs660-D", - .data = &st_fs660c32_D - }, - {} -}; - static void __init st_of_create_quadfs_fsynths( struct device_node *np, const char *pll_name, struct clkgen_quadfs_data *quadfs, void __iomem *reg, @@ -890,18 +878,14 @@ static void __init st_of_create_quadfs_fsynths( of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); } -static void __init st_of_quadfs_setup(struct device_node *np) +static void __init st_of_quadfs_setup(struct device_node *np, + struct clkgen_quadfs_data *data) { - const struct of_device_id *match; struct clk *clk; const char *pll_name, *clk_parent_name; void __iomem *reg; spinlock_t *lock; - match = of_match_node(quadfs_of_match, np); - if (WARN_ON(!match)) - return; - reg = of_iomap(np, 0); if (!reg) return; @@ -920,8 +904,8 @@ static void __init st_of_quadfs_setup(struct device_node *np) spin_lock_init(lock); - clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, - (struct clkgen_quadfs_data *) match->data, reg, lock); + clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, data, + reg, lock); if (IS_ERR(clk)) goto err_exit; else @@ -930,11 +914,20 @@ static void __init st_of_quadfs_setup(struct device_node *np) __clk_get_name(clk_get_parent(clk)), (unsigned int)clk_get_rate(clk)); - st_of_create_quadfs_fsynths(np, pll_name, - (struct clkgen_quadfs_data *)match->data, - reg, lock); + st_of_create_quadfs_fsynths(np, pll_name, data, reg, lock); err_exit: kfree(pll_name); /* No longer need local copy of the PLL name */ } -CLK_OF_DECLARE(quadfs, "st,quadfs", st_of_quadfs_setup); + +static void __init st_of_quadfs660C_setup(struct device_node *np) +{ + st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_C); +} +CLK_OF_DECLARE(quadfs660C, "st,quadfs-pll", st_of_quadfs660C_setup); + +static void __init st_of_quadfs660D_setup(struct device_node *np) +{ + st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_D); +} +CLK_OF_DECLARE(quadfs660D, "st,quadfs", st_of_quadfs660D_setup); diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index 6fdb1ab..c514d39 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -53,29 +53,13 @@ static struct clkgen_mux_data stih407_a9_mux_data = { .lock = &clkgen_a9_lock, }; -static const struct of_device_id mux_of_match[] = { - { - .compatible = "st,stih407-clkgen-a9-mux", - .data = &stih407_a9_mux_data, - }, - {} -}; -static void __init st_of_clkgen_mux_setup(struct device_node *np) +static void __init st_of_clkgen_mux_setup(struct device_node *np, + struct clkgen_mux_data *data) { - const struct of_device_id *match; struct clk *clk; void __iomem *reg; const char **parents; int num_parents = 0; - const struct clkgen_mux_data *data; - - match = of_match_node(mux_of_match, np); - if (!match) { - pr_err("%s: No matching data\n", __func__); - return; - } - - data = match->data; reg = of_iomap(np, 0); if (!reg) { @@ -112,4 +96,10 @@ err: err_parents: iounmap(reg); } -CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup); + +static void __init st_of_clkgen_a9_mux_setup(struct device_node *np) +{ + st_of_clkgen_mux_setup(np, &stih407_a9_mux_data); +} +CLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux", + st_of_clkgen_a9_mux_setup); diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index 8a1b1cf..25bda48 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -702,48 +702,17 @@ static struct clk * __init clkgen_odf_register(const char *parent_name, return clk; } -static const struct of_device_id c32_pll_of_match[] = { - { - .compatible = "st,stih407-plls-c32-a0", - .data = &st_pll3200c32_407_a0, - }, - { - .compatible = "st,plls-c32-cx_0", - .data = &st_pll3200c32_cx_0, - }, - { - .compatible = "st,plls-c32-cx_1", - .data = &st_pll3200c32_cx_1, - }, - { - .compatible = "st,stih407-plls-c32-a9", - .data = &st_pll3200c32_407_a9, - }, - { - .compatible = "st,stih418-plls-c28-a9", - .data = &st_pll4600c28_418_a9, - }, - {} -}; -static void __init clkgen_c32_pll_setup(struct device_node *np) +static void __init clkgen_c32_pll_setup(struct device_node *np, + struct clkgen_pll_data *data) { - const struct of_device_id *match; struct clk *clk; const char *parent_name, *pll_name; void __iomem *pll_base; int num_odfs, odf; struct clk_onecell_data *clk_data; - struct clkgen_pll_data *data; unsigned long pll_flags = 0; - match = of_match_node(c32_pll_of_match, np); - if (!match) { - pr_err("%s: No matching data\n", __func__); - return; - } - - data = (struct clkgen_pll_data *) match->data; parent_name = of_clk_get_parent_name(np, 0); if (!parent_name) @@ -802,4 +771,30 @@ err: kfree(clk_data->clks); kfree(clk_data); } -CLK_OF_DECLARE(clkgen_c32_pll, "st,clkgen-plls-c32", clkgen_c32_pll_setup); +static void __init clkgen_c32_pll0_setup(struct device_node *np) +{ + clkgen_c32_pll_setup(np, + (struct clkgen_pll_data *) &st_pll3200c32_cx_0); +} +CLK_OF_DECLARE(c32_pll0, "st,clkgen-pll0", clkgen_c32_pll0_setup); + +static void __init clkgen_c32_pll1_setup(struct device_node *np) +{ + clkgen_c32_pll_setup(np, + (struct clkgen_pll_data *) &st_pll3200c32_cx_1); +} +CLK_OF_DECLARE(c32_pll1, "st,clkgen-pll1", clkgen_c32_pll1_setup); + +static void __init clkgen_c32_plla9_setup(struct device_node *np) +{ + clkgen_c32_pll_setup(np, + (struct clkgen_pll_data *) &st_pll3200c32_407_a9); +} +CLK_OF_DECLARE(c32_plla9, "st,stih407-clkgen-plla9", clkgen_c32_plla9_setup); + +static void __init clkgen_c28_plla9_setup(struct device_node *np) +{ + clkgen_c32_pll_setup(np, + (struct clkgen_pll_data *) &st_pll4600c28_418_a9); +} +CLK_OF_DECLARE(c28_plla9, "st,stih418-clkgen-plla9", clkgen_c28_plla9_setup); -- cgit v0.10.2 From b699f3e3912f60119430e3af302a39eb992864d5 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Mon, 29 Aug 2016 14:26:56 +0200 Subject: drivers: clk: st: Add fs660c32 synthesizer algorithm Use an algorithm instead of a table to compute clocks for fs660c32 synthesizer. During a video playback we need to adjust audio & video frequencies. A table can't cover all HDMI resolutions and audio adjustment. Signed-off-by: Gabriel Fernandez Acked-by: Peter Griffin Signed-off-by: Stephen Boyd diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 2f11bbd..14819d9 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -42,40 +42,6 @@ struct stm_fs { unsigned long nsdiv; }; -static const struct stm_fs fs660c32_rtbl[] = { - { .mdiv = 0x14, .pe = 0x376b, .sdiv = 0x4, .nsdiv = 1 }, /* 25.175 MHz */ - { .mdiv = 0x14, .pe = 0x30c3, .sdiv = 0x4, .nsdiv = 1 }, /* 25.200 MHz */ - { .mdiv = 0x10, .pe = 0x71c7, .sdiv = 0x4, .nsdiv = 1 }, /* 27.000 MHz */ - { .mdiv = 0x00, .pe = 0x47af, .sdiv = 0x3, .nsdiv = 0 }, /* 27.027 MHz */ - { .mdiv = 0x0e, .pe = 0x4e1a, .sdiv = 0x4, .nsdiv = 1 }, /* 28.320 MHz */ - { .mdiv = 0x0b, .pe = 0x534d, .sdiv = 0x4, .nsdiv = 1 }, /* 30.240 MHz */ - { .mdiv = 0x17, .pe = 0x6fbf, .sdiv = 0x2, .nsdiv = 0 }, /* 31.500 MHz */ - { .mdiv = 0x01, .pe = 0x0, .sdiv = 0x4, .nsdiv = 1 }, /* 40.000 MHz */ - { .mdiv = 0x15, .pe = 0x2aab, .sdiv = 0x3, .nsdiv = 1 }, /* 49.500 MHz */ - { .mdiv = 0x14, .pe = 0x6666, .sdiv = 0x3, .nsdiv = 1 }, /* 50.000 MHz */ - { .mdiv = 0x1d, .pe = 0x395f, .sdiv = 0x1, .nsdiv = 0 }, /* 57.284 MHz */ - { .mdiv = 0x08, .pe = 0x4ec5, .sdiv = 0x3, .nsdiv = 1 }, /* 65.000 MHz */ - { .mdiv = 0x05, .pe = 0x1770, .sdiv = 0x3, .nsdiv = 1 }, /* 71.000 MHz */ - { .mdiv = 0x03, .pe = 0x4ba7, .sdiv = 0x3, .nsdiv = 1 }, /* 74.176 MHz */ - { .mdiv = 0x0f, .pe = 0x3426, .sdiv = 0x1, .nsdiv = 0 }, /* 74.250 MHz */ - { .mdiv = 0x0e, .pe = 0x7777, .sdiv = 0x1, .nsdiv = 0 }, /* 75.000 MHz */ - { .mdiv = 0x01, .pe = 0x4053, .sdiv = 0x3, .nsdiv = 1 }, /* 78.800 MHz */ - { .mdiv = 0x09, .pe = 0x15b5, .sdiv = 0x1, .nsdiv = 0 }, /* 85.500 MHz */ - { .mdiv = 0x1b, .pe = 0x3f19, .sdiv = 0x2, .nsdiv = 1 }, /* 88.750 MHz */ - { .mdiv = 0x10, .pe = 0x71c7, .sdiv = 0x2, .nsdiv = 1 }, /* 108.000 MHz */ - { .mdiv = 0x00, .pe = 0x47af, .sdiv = 0x1, .nsdiv = 0 }, /* 108.108 MHz */ - { .mdiv = 0x0c, .pe = 0x3118, .sdiv = 0x2, .nsdiv = 1 }, /* 118.963 MHz */ - { .mdiv = 0x0c, .pe = 0x2f54, .sdiv = 0x2, .nsdiv = 1 }, /* 119.000 MHz */ - { .mdiv = 0x07, .pe = 0xe39, .sdiv = 0x2, .nsdiv = 1 }, /* 135.000 MHz */ - { .mdiv = 0x03, .pe = 0x4ba7, .sdiv = 0x2, .nsdiv = 1 }, /* 148.352 MHz */ - { .mdiv = 0x0f, .pe = 0x3426, .sdiv = 0x0, .nsdiv = 0 }, /* 148.500 MHz */ - { .mdiv = 0x03, .pe = 0x4ba7, .sdiv = 0x1, .nsdiv = 1 }, /* 296.704 MHz */ - { .mdiv = 0x03, .pe = 0x471c, .sdiv = 0x1, .nsdiv = 1 }, /* 297.000 MHz */ - { .mdiv = 0x00, .pe = 0x295f, .sdiv = 0x1, .nsdiv = 1 }, /* 326.700 MHz */ - { .mdiv = 0x1f, .pe = 0x3633, .sdiv = 0x0, .nsdiv = 1 }, /* 333.000 MHz */ - { .mdiv = 0x1c, .pe = 0x0, .sdiv = 0x0, .nsdiv = 1 }, /* 352.000 Mhz */ -}; - struct clkgen_quadfs_data { bool reset_present; bool bwfilter_present; @@ -99,8 +65,7 @@ struct clkgen_quadfs_data { struct clkgen_field nsdiv[QUADFS_MAX_CHAN]; const struct clk_ops *pll_ops; - const struct stm_fs *rtbl; - u8 rtbl_cnt; + int (*get_params)(unsigned long, unsigned long, struct stm_fs *); int (*get_rate)(unsigned long , const struct stm_fs *, unsigned long *); }; @@ -108,6 +73,8 @@ struct clkgen_quadfs_data { static const struct clk_ops st_quadfs_pll_c32_ops; static const struct clk_ops st_quadfs_fs660c32_ops; +static int clk_fs660c32_dig_get_params(unsigned long input, + unsigned long output, struct stm_fs *fs); static int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *, unsigned long *); @@ -149,8 +116,7 @@ static const struct clkgen_quadfs_data st_fs660c32_C = { .powerup_polarity = 1, .standby_polarity = 1, .pll_ops = &st_quadfs_pll_c32_ops, - .rtbl = fs660c32_rtbl, - .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), + .get_params = clk_fs660c32_dig_get_params, .get_rate = clk_fs660c32_dig_get_rate, }; @@ -192,8 +158,7 @@ static const struct clkgen_quadfs_data st_fs660c32_D = { .powerup_polarity = 1, .standby_polarity = 1, .pll_ops = &st_quadfs_pll_c32_ops, - .rtbl = fs660c32_rtbl, - .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), + .get_params = clk_fs660c32_dig_get_params, .get_rate = clk_fs660c32_dig_get_rate,}; /** @@ -620,6 +585,107 @@ static int clk_fs660c32_dig_get_rate(unsigned long input, return 0; } + +static int clk_fs660c32_get_pe(int m, int si, unsigned long *deviation, + signed long input, unsigned long output, uint64_t *p, + struct stm_fs *fs) +{ + unsigned long new_freq, new_deviation; + struct stm_fs fs_tmp; + uint64_t val; + + val = (uint64_t)output << si; + + *p = (uint64_t)input * P20 - (32LL + (uint64_t)m) * val * (P20 / 32LL); + + *p = div64_u64(*p, val); + + if (*p > 32767LL) + return 1; + + fs_tmp.mdiv = (unsigned long) m; + fs_tmp.pe = (unsigned long)*p; + fs_tmp.sdiv = si; + fs_tmp.nsdiv = 1; + + clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq); + + new_deviation = abs(output - new_freq); + + if (new_deviation < *deviation) { + fs->mdiv = m; + fs->pe = (unsigned long)*p; + fs->sdiv = si; + fs->nsdiv = 1; + *deviation = new_deviation; + } + return 0; +} + +static int clk_fs660c32_dig_get_params(unsigned long input, + unsigned long output, struct stm_fs *fs) +{ + int si; /* sdiv_reg (8 downto 0) */ + int m; /* md value */ + unsigned long new_freq, new_deviation; + /* initial condition to say: "infinite deviation" */ + unsigned long deviation = ~0; + uint64_t p, p1, p2; /* pe value */ + int r1, r2; + + struct stm_fs fs_tmp; + + for (si = 0; (si <= 8) && deviation; si++) { + + /* Boundary test to avoid useless iteration */ + r1 = clk_fs660c32_get_pe(0, si, &deviation, + input, output, &p1, fs); + r2 = clk_fs660c32_get_pe(31, si, &deviation, + input, output, &p2, fs); + + /* No solution */ + if (r1 && r2 && (p1 > p2)) + continue; + + /* Try to find best deviation */ + for (m = 1; (m < 31) && deviation; m++) + clk_fs660c32_get_pe(m, si, &deviation, + input, output, &p, fs); + + } + + if (deviation == ~0) /* No solution found */ + return -1; + + /* pe fine tuning if deviation not 0: +/- 2 around computed pe value */ + if (deviation) { + fs_tmp.mdiv = fs->mdiv; + fs_tmp.sdiv = fs->sdiv; + fs_tmp.nsdiv = fs->nsdiv; + + if (fs->pe > 2) + p2 = fs->pe - 2; + else + p2 = 0; + + for (; p2 < 32768ll && (p2 <= (fs->pe + 2)); p2++) { + fs_tmp.pe = (unsigned long)p2; + + clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq); + + new_deviation = abs(output - new_freq); + + /* Check if this is a better solution */ + if (new_deviation < deviation) { + fs->pe = (unsigned long)p2; + deviation = new_deviation; + + } + } + } + return 0; +} + static int quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth *fs, struct stm_fs *params) { @@ -655,38 +721,14 @@ static long quadfs_find_best_rate(struct clk_hw *hw, unsigned long drate, struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); int (*clk_fs_get_rate)(unsigned long , const struct stm_fs *, unsigned long *); - struct stm_fs prev_params; - unsigned long prev_rate, rate = 0; - unsigned long diff_rate, prev_diff_rate = ~0; - int index; + int (*clk_fs_get_params)(unsigned long, unsigned long, struct stm_fs *); + unsigned long rate = 0; clk_fs_get_rate = fs->data->get_rate; + clk_fs_get_params = fs->data->get_params; - for (index = 0; index < fs->data->rtbl_cnt; index++) { - prev_rate = rate; - - *params = fs->data->rtbl[index]; - prev_params = *params; - - clk_fs_get_rate(prate, &fs->data->rtbl[index], &rate); - - diff_rate = abs(drate - rate); - - if (diff_rate > prev_diff_rate) { - rate = prev_rate; - *params = prev_params; - break; - } - - prev_diff_rate = diff_rate; - - if (drate == rate) - return rate; - } - - - if (index == fs->data->rtbl_cnt) - *params = prev_params; + if (!clk_fs_get_params(prate, drate, params)) + clk_fs_get_rate(prate, params, &rate); return rate; } -- cgit v0.10.2 From 26bd0a57755df51a34037d8151a443cec3688b80 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Mon, 29 Aug 2016 14:26:57 +0200 Subject: drivers: clk: st: Add clock propagation for audio clocks This patch allows fine tuning of the quads FS for audio clocks accuracy. Signed-off-by: Olivier Bideau Signed-off-by: Gabriel Fernandez Acked-by: Peter Griffin Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt index b7ee5c7..d68f6a5 100644 --- a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt +++ b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt @@ -60,6 +60,8 @@ This binding uses the common clock binding[2]. Required properties: - compatible : shall be: "st,flexgen" + "st,flexgen-audio", "st,flexgen" (enable clock propagation on parent for + audio use case) - #clock-cells : from common clock binding; shall be set to 1 (multiple clock outputs). diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 546bd79..7ed05f0 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -15,6 +15,10 @@ #include #include +struct clkgen_data { + unsigned long flags; +}; + struct flexgen { struct clk_hw hw; @@ -259,6 +263,18 @@ static const char ** __init flexgen_get_parents(struct device_node *np, return parents; } +static const struct clkgen_data clkgen_audio = { + .flags = CLK_SET_RATE_PARENT, +}; + +static const struct of_device_id flexgen_of_match[] = { + { + .compatible = "st,flexgen-audio", + .data = &clkgen_audio, + }, + {} +}; + static void __init st_of_flexgen_setup(struct device_node *np) { struct device_node *pnode; @@ -267,6 +283,9 @@ static void __init st_of_flexgen_setup(struct device_node *np) const char **parents; int num_parents, i; spinlock_t *rlock = NULL; + const struct of_device_id *match; + struct clkgen_data *data = NULL; + unsigned long flex_flags = 0; int ret; pnode = of_get_parent(np); @@ -281,6 +300,12 @@ static void __init st_of_flexgen_setup(struct device_node *np) if (!parents) return; + match = of_match_node(flexgen_of_match, np); + if (match) { + data = (struct clkgen_data *)match->data; + flex_flags = data->flags; + } + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); if (!clk_data) goto err; @@ -307,7 +332,6 @@ static void __init st_of_flexgen_setup(struct device_node *np) for (i = 0; i < clk_data->clk_num; i++) { struct clk *clk; const char *clk_name; - unsigned long flex_flags = 0; if (of_property_read_string_index(np, "clock-output-names", i, &clk_name)) { -- cgit v0.10.2 From cb80ec768a0db73743a6f8b5d94c0b52b97e3ca4 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Mon, 29 Aug 2016 14:26:58 +0200 Subject: drivers: clk: st: Handle clk synchronous mode for video clocks This patch configures the semi-synchronous mode of the video clocks of clkgenD2. Signed-off-by: Olivier Bideau Signed-off-by: Gabriel Fernandez Acked-by: Peter Griffin Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt index d68f6a5..7ff77fc 100644 --- a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt +++ b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt @@ -62,6 +62,8 @@ Required properties: "st,flexgen" "st,flexgen-audio", "st,flexgen" (enable clock propagation on parent for audio use case) + "st,flexgen-video", "st,flexgen" (enable clock propagation on parent + and activate synchronous mode) - #clock-cells : from common clock binding; shall be set to 1 (multiple clock outputs). diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 7ed05f0..a485f3b 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -17,6 +17,7 @@ struct clkgen_data { unsigned long flags; + bool mode; }; struct flexgen { @@ -32,9 +33,14 @@ struct flexgen { struct clk_gate fgate; /* Final divisor */ struct clk_divider fdiv; + /* Asynchronous mode control */ + struct clk_gate sync; + /* hw control flags */ + bool control_mode; }; #define to_flexgen(_hw) container_of(_hw, struct flexgen, hw) +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) static int flexgen_enable(struct clk_hw *hw) { @@ -143,12 +149,21 @@ static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate, struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *pdiv_hw = &flexgen->pdiv.hw; struct clk_hw *fdiv_hw = &flexgen->fdiv.hw; + struct clk_hw *sync_hw = &flexgen->sync.hw; + struct clk_gate *config = to_clk_gate(sync_hw); unsigned long div = 0; int ret = 0; + u32 reg; __clk_hw_set_clk(pdiv_hw, hw); __clk_hw_set_clk(fdiv_hw, hw); + if (flexgen->control_mode) { + reg = readl(config->reg); + reg &= ~BIT(config->bit_idx); + writel(reg, config->reg); + } + div = clk_best_div(parent_rate, rate); /* @@ -182,7 +197,7 @@ static const struct clk_ops flexgen_ops = { static struct clk *clk_register_flexgen(const char *name, const char **parent_names, u8 num_parents, void __iomem *reg, spinlock_t *lock, u32 idx, - unsigned long flexgen_flags) { + unsigned long flexgen_flags, bool mode) { struct flexgen *fgxbar; struct clk *clk; struct clk_init_data init; @@ -231,6 +246,13 @@ static struct clk *clk_register_flexgen(const char *name, fgxbar->fdiv.reg = fdiv_reg; fgxbar->fdiv.width = 6; + /* Final divider sync config */ + fgxbar->sync.lock = lock; + fgxbar->sync.reg = fdiv_reg; + fgxbar->sync.bit_idx = 7; + + fgxbar->control_mode = mode; + fgxbar->hw.init = &init; clk = clk_register(NULL, &fgxbar->hw); @@ -267,11 +289,20 @@ static const struct clkgen_data clkgen_audio = { .flags = CLK_SET_RATE_PARENT, }; +static const struct clkgen_data clkgen_video = { + .flags = CLK_SET_RATE_PARENT, + .mode = 1, +}; + static const struct of_device_id flexgen_of_match[] = { { .compatible = "st,flexgen-audio", .data = &clkgen_audio, }, + { + .compatible = "st,flexgen-video", + .data = &clkgen_video, + }, {} }; @@ -287,6 +318,7 @@ static void __init st_of_flexgen_setup(struct device_node *np) struct clkgen_data *data = NULL; unsigned long flex_flags = 0; int ret; + bool clk_mode = 0; pnode = of_get_parent(np); if (!pnode) @@ -304,6 +336,7 @@ static void __init st_of_flexgen_setup(struct device_node *np) if (match) { data = (struct clkgen_data *)match->data; flex_flags = data->flags; + clk_mode = data->mode; } clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); @@ -347,7 +380,7 @@ static void __init st_of_flexgen_setup(struct device_node *np) continue; clk = clk_register_flexgen(clk_name, parents, num_parents, - reg, rlock, i, flex_flags); + reg, rlock, i, flex_flags, clk_mode); if (IS_ERR(clk)) goto err; -- cgit v0.10.2 From d832fdd9b2d685b8166f37c03d53b9872d77ed54 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 15 Sep 2016 14:57:38 +0800 Subject: clk: sunxi-ng: sun6i-a31: Set CLK_SET_RATE_PARENT for display output clocks The LCD controller and HDMI controller use the LCDx-CHy and HDMI clocks to generate their dot clocks. To be able to generate a full range of possible clock rates, the parent PLL clock rates should also be changed. Fixes: c6e6c96d8fa6 ("clk: sunxi-ng: Add A31/A31s clocks") Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index f1d61fa..bb488e8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -543,17 +543,19 @@ static const char * const lcd_ch0_parents[] = { "pll-video0", "pll-video1", "pll-video0-2x", "pll-video1-2x", "pll-mipi" }; static SUNXI_CCU_MUX_WITH_GATE(lcd0_ch0_clk, "lcd0-ch0", lcd_ch0_parents, - 0x118, 24, 2, BIT(31), 0); + 0x118, 24, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_MUX_WITH_GATE(lcd1_ch0_clk, "lcd1-ch0", lcd_ch0_parents, - 0x11c, 24, 2, BIT(31), 0); + 0x11c, 24, 2, BIT(31), CLK_SET_RATE_PARENT); static const char * const lcd_ch1_parents[] = { "pll-video0", "pll-video1", "pll-video0-2x", "pll-video1-2x" }; static SUNXI_CCU_M_WITH_MUX_GATE(lcd0_ch1_clk, "lcd0-ch1", lcd_ch1_parents, - 0x12c, 0, 4, 24, 3, BIT(31), 0); + 0x12c, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(lcd1_ch1_clk, "lcd1-ch1", lcd_ch1_parents, - 0x12c, 0, 4, 24, 3, BIT(31), 0); + 0x12c, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static const char * const csi_sclk_parents[] = { "pll-video0", "pll-video1", "pll9", "pll10", "pll-mipi", @@ -601,7 +603,8 @@ static SUNXI_CCU_GATE(digital_mic_clk, "digital-mic", "pll-audio", 0x148, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", lcd_ch1_parents, - 0x150, 0, 4, 24, 2, BIT(31), 0); + 0x150, 0, 4, 24, 2, BIT(31), + CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(31), 0); @@ -624,10 +627,11 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(mbus1_clk, "mbus1", mbus_parents, 0x160, CLK_IS_CRITICAL); static SUNXI_CCU_M_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi", lcd_ch1_parents, - 0x168, 16, 3, 24, 2, BIT(31), 0); + 0x168, 16, 3, 24, 2, BIT(31), + CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(mipi_dsi_dphy_clk, "mipi-dsi-dphy", lcd_ch1_parents, 0x168, 0, 3, 8, 2, - BIT(15), 0); + BIT(15), CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(mipi_csi_dphy_clk, "mipi-csi-dphy", lcd_ch1_parents, 0x168, 0, 3, 8, 2, BIT(15), 0); @@ -956,9 +960,9 @@ static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x", "pll-periph", 1, 2, 0); static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x", - "pll-video0", 1, 2, 0); + "pll-video0", 1, 2, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x", - "pll-video1", 1, 2, 0); + "pll-video1", 1, 2, CLK_SET_RATE_PARENT); static struct clk_hw_onecell_data sun6i_a31_hw_clks = { .hws = { -- cgit v0.10.2 From d613782cb5f2a40ef6e074dd1fa33d0abbe07c81 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 15 Sep 2016 14:57:39 +0800 Subject: clk: sunxi-ng: sun6i-a31: set CLK_SET_RATE_UNGATE for all PLLs The PLLs have a "lock" bit in their configuration registers which indicate if the PLL has locked on to the requested clock rate. We check this bit in the .set_rate op. The PLL cannot lock on if it's not running, which might be a false positive (warning). Set the CLK_SET_RATE_UNGATE flag for all PLLs so whenever clk_set_rate is called on them, they get enabled and the "lock" check is really checking the PLL. Fixes: c6e6c96d8fa6 ("clk: sunxi-ng: Add A31/A31s clocks") Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index bb488e8..ff0d621 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -59,7 +59,7 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", 0, 5, /* M */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", "osc24M", 0x010, @@ -71,7 +71,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", "osc24M", 0x018, @@ -83,7 +83,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", "osc24M", 0x020, @@ -92,7 +92,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", 0, 2, /* M */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph_clk, "pll-periph", "osc24M", 0x028, @@ -101,7 +101,7 @@ static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph_clk, "pll-periph", BIT(31), /* gate */ BIT(28), /* lock */ 2, /* post-div */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", "osc24M", 0x030, @@ -113,7 +113,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", "osc24M", 0x038, @@ -125,7 +125,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); /* * The MIPI PLL has 2 modes: "MIPI" and "HDMI". @@ -145,7 +145,7 @@ static SUNXI_CCU_NKM_WITH_MUX_GATE_LOCK(pll_mipi_clk, "pll-mipi", 21, 0, /* mux */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll9_clk, "pll9", "osc24M", 0x044, @@ -157,7 +157,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll9_clk, "pll9", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll10_clk, "pll10", "osc24M", 0x048, @@ -169,7 +169,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll10_clk, "pll10", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static const char * const cpux_parents[] = { "osc32k", "osc24M", "pll-cpu", "pll-cpu" }; -- cgit v0.10.2 From 5254223a1216f120a84153dac1d0fde4da999a55 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 15 Sep 2016 14:57:40 +0800 Subject: clk: sunxi-ng: sun6i-a31: Fix register offset for mipi-csi clk The register offset for the mipi-csi clk is off by 4, a copy paste error from the mipi-dsi clk. Fixes: c6e6c96d8fa6 ("clk: sunxi-ng: Add A31/A31s clocks") Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index ff0d621..7959646 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -633,7 +633,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(mipi_dsi_dphy_clk, "mipi-dsi-dphy", lcd_ch1_parents, 0x168, 0, 3, 8, 2, BIT(15), CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(mipi_csi_dphy_clk, "mipi-csi-dphy", - lcd_ch1_parents, 0x168, 0, 3, 8, 2, + lcd_ch1_parents, 0x16c, 0, 3, 8, 2, BIT(15), 0); static SUNXI_CCU_M_WITH_MUX_GATE(iep_drc0_clk, "iep-drc0", de_parents, -- cgit v0.10.2 From faabbe50ad518ce493adb20a9bf430daa9d395a4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 16 Sep 2016 13:03:31 +0000 Subject: clk: zx296718: use builtin_platform_driver to simplify the code Use the builtin_platform_driver() macro to make the code simpler. Signed-off-by: Wei Yongjun Signed-off-by: Stephen Boyd diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c index 025e324..b4fe8dd 100644 --- a/drivers/clk/zte/clk-zx296718.c +++ b/drivers/clk/zte/clk-zx296718.c @@ -917,8 +917,4 @@ static struct platform_driver zx_clk_driver = { }, }; -static int __init zx_clkc_init(void) -{ - return platform_driver_register(&zx_clk_driver); -} -device_initcall(zx_clkc_init); +builtin_platform_driver(zx_clk_driver); -- cgit v0.10.2 From 0637a4c7810a6b09ec6b1bf3dc88830cb64ce08b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 14 Sep 2016 21:10:47 +0200 Subject: clk/Renesas-MSTP: Use kmalloc_array() in cpg_mstp_clocks_init() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 5093a25..9375777 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -167,7 +167,7 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) unsigned int i; group = kzalloc(sizeof(*group), GFP_KERNEL); - clks = kmalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL); + clks = kmalloc_array(MSTP_MAX_CLOCKS, sizeof(*clks), GFP_KERNEL); if (group == NULL || clks == NULL) { kfree(group); kfree(clks); -- cgit v0.10.2 From f00d2db7c4739af8a2496273175e0939e1047813 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 15 Sep 2016 17:45:57 +0200 Subject: clk: zx: fix pointer case warnings The zx296718 clock driver has a creative way of assigning the register values for each clock, by initializing an __iomem pointer to an offset and then later adding the base (from ioremap) on top with a cast to u64. This fail on all 32-bit architectures during compile testing: drivers/clk/zte/clk-zx296718.c: In function 'top_clocks_init': drivers/clk/zte/clk-zx296718.c:554:35: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] zx296718_pll_clk[i].reg_base += (u64)reg_base; drivers/clk/zte/clk-zx296718.c:579:29: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] drivers/clk/zte/clk-zx296718.c:592:31: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] It would be nice to avoid all the casts, but I decided to simply shut up the warnings by changing the type from u64 to uintptr_t, which does the right thing in practice. Signed-off-by: Arnd Bergmann Fixes: ca0233285a93 ("clk: zx: register ZX296718 clocks") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c index b4fe8dd..c7716c1 100644 --- a/drivers/clk/zte/clk-zx296718.c +++ b/drivers/clk/zte/clk-zx296718.c @@ -551,7 +551,7 @@ static int __init top_clocks_init(struct device_node *np) } for (i = 0; i < ARRAY_SIZE(zx296718_pll_clk); i++) { - zx296718_pll_clk[i].reg_base += (u64)reg_base; + zx296718_pll_clk[i].reg_base += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &zx296718_pll_clk[i].hw); if (ret) { pr_warn("top clk %s init error!\n", @@ -576,7 +576,7 @@ static int __init top_clocks_init(struct device_node *np) top_hw_onecell_data.hws[top_mux_clk[i].id] = &top_mux_clk[i].mux.hw; - top_mux_clk[i].mux.reg += (u64)reg_base; + top_mux_clk[i].mux.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &top_mux_clk[i].mux.hw); if (ret) { pr_warn("top clk %s init error!\n", @@ -589,7 +589,7 @@ static int __init top_clocks_init(struct device_node *np) top_hw_onecell_data.hws[top_gate_clk[i].id] = &top_gate_clk[i].gate.hw; - top_gate_clk[i].gate.reg += (u64)reg_base; + top_gate_clk[i].gate.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &top_gate_clk[i].gate.hw); if (ret) { pr_warn("top clk %s init error!\n", @@ -602,7 +602,7 @@ static int __init top_clocks_init(struct device_node *np) top_hw_onecell_data.hws[top_div_clk[i].id] = &top_div_clk[i].div.hw; - top_div_clk[i].div.reg += (u64)reg_base; + top_div_clk[i].div.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &top_div_clk[i].div.hw); if (ret) { pr_warn("top clk %s init error!\n", @@ -742,7 +742,7 @@ static int __init lsp0_clocks_init(struct device_node *np) lsp0_hw_onecell_data.hws[lsp0_mux_clk[i].id] = &lsp0_mux_clk[i].mux.hw; - lsp0_mux_clk[i].mux.reg += (u64)reg_base; + lsp0_mux_clk[i].mux.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &lsp0_mux_clk[i].mux.hw); if (ret) { pr_warn("lsp0 clk %s init error!\n", @@ -755,7 +755,7 @@ static int __init lsp0_clocks_init(struct device_node *np) lsp0_hw_onecell_data.hws[lsp0_gate_clk[i].id] = &lsp0_gate_clk[i].gate.hw; - lsp0_gate_clk[i].gate.reg += (u64)reg_base; + lsp0_gate_clk[i].gate.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &lsp0_gate_clk[i].gate.hw); if (ret) { pr_warn("lsp0 clk %s init error!\n", @@ -768,7 +768,7 @@ static int __init lsp0_clocks_init(struct device_node *np) lsp0_hw_onecell_data.hws[lsp0_div_clk[i].id] = &lsp0_div_clk[i].div.hw; - lsp0_div_clk[i].div.reg += (u64)reg_base; + lsp0_div_clk[i].div.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &lsp0_div_clk[i].div.hw); if (ret) { pr_warn("lsp0 clk %s init error!\n", @@ -847,7 +847,7 @@ static int __init lsp1_clocks_init(struct device_node *np) lsp1_hw_onecell_data.hws[lsp1_mux_clk[i].id] = &lsp0_mux_clk[i].mux.hw; - lsp1_mux_clk[i].mux.reg += (u64)reg_base; + lsp1_mux_clk[i].mux.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &lsp1_mux_clk[i].mux.hw); if (ret) { pr_warn("lsp1 clk %s init error!\n", @@ -860,7 +860,7 @@ static int __init lsp1_clocks_init(struct device_node *np) lsp1_hw_onecell_data.hws[lsp1_gate_clk[i].id] = &lsp1_gate_clk[i].gate.hw; - lsp1_gate_clk[i].gate.reg += (u64)reg_base; + lsp1_gate_clk[i].gate.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &lsp1_gate_clk[i].gate.hw); if (ret) { pr_warn("lsp1 clk %s init error!\n", @@ -873,7 +873,7 @@ static int __init lsp1_clocks_init(struct device_node *np) lsp1_hw_onecell_data.hws[lsp1_div_clk[i].id] = &lsp1_div_clk[i].div.hw; - lsp1_div_clk[i].div.reg += (u64)reg_base; + lsp1_div_clk[i].div.reg += (uintptr_t)reg_base; ret = clk_hw_register(NULL, &lsp1_div_clk[i].div.hw); if (ret) { pr_warn("lsp1 clk %s init error!\n", -- cgit v0.10.2 From dc19b6f5be5b6f82548981adc1c5019b7a82d7c7 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Thu, 15 Sep 2016 10:15:33 +0530 Subject: clk: Add USB3 PHY reset lines Adding missing reset lines for USB 3.0 PHY. Signed-off-by: Vivek Gautam Signed-off-by: Stephen Boyd diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index ebe5d18..fe03e6f 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -3329,6 +3329,8 @@ static const struct qcom_reset_map gcc_msm8996_resets[] = { [GCC_USB_20_BCR] = { 0x12000 }, [GCC_QUSB2PHY_PRIM_BCR] = { 0x12038 }, [GCC_QUSB2PHY_SEC_BCR] = { 0x1203c }, + [GCC_USB3_PHY_BCR] = { 0x50020 }, + [GCC_USB3PHY_PHY_BCR] = { 0x50024 }, [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, [GCC_SDCC1_BCR] = { 0x13000 }, [GCC_SDCC2_BCR] = { 0x14000 }, diff --git a/include/dt-bindings/clock/qcom,gcc-msm8996.h b/include/dt-bindings/clock/qcom,gcc-msm8996.h index b7ea1e8..1828723 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8996.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8996.h @@ -337,6 +337,8 @@ #define GCC_QREFS_VBG_CAL_BCR 100 #define GCC_PCIE_PHY_COM_BCR 101 #define GCC_PCIE_PHY_COM_NOCSR_BCR 102 +#define GCC_USB3_PHY_BCR 103 +#define GCC_USB3PHY_PHY_BCR 104 /* Indexes for GDSCs */ -- cgit v0.10.2 From bd8dd593f7d2211f2273e05741d157b0c8d020ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 13 Sep 2016 09:06:04 +0200 Subject: clk: bcm: Add driver for BCM53573 ILP clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This clock is present on BCM53573 devices (including BCM47189) that use Cortex-A7. ILP is a part of PMU (Power Management Unit) multi-function device so we use syscon (and regmap) for it. Signed-off-by: RafaÅ‚ MiÅ‚ecki Acked-by: Rob Herring [sboyd@codeaurora.org: Remove 0 from clk_init_data to silence sparse] Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm53573-ilp.txt b/Documentation/devicetree/bindings/clock/brcm,bcm53573-ilp.txt new file mode 100644 index 0000000..2ebb107 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/brcm,bcm53573-ilp.txt @@ -0,0 +1,36 @@ +Broadcom BCM53573 ILP clock +=========================== + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +This binding is used for ILP clock (sometimes referred as "slow clock") +on Broadcom BCM53573 devices using Cortex-A7 CPU. + +ILP's rate has to be calculated on runtime and it depends on ALP clock +which has to be referenced. + +This clock is part of PMU (Power Management Unit), a Broadcom's device +handing power-related aspects. Its node must be sub-node of the PMU +device. + +Required properties: +- compatible: "brcm,bcm53573-ilp" +- clocks: has to reference an ALP clock +- #clock-cells: should be <0> +- clock-output-names: from common clock bindings, should contain clock + name + +Example: + +pmu@18012000 { + compatible = "simple-mfd", "syscon"; + reg = <0x18012000 0x00001000>; + + ilp { + compatible = "brcm,bcm53573-ilp"; + clocks = <&alp>; + #clock-cells = <0>; + clock-output-names = "ilp"; + }; +}; diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index 123f377..d9dc848 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o +obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o obj-$(CONFIG_CLK_BCM_NSP) += clk-nsp.o obj-$(CONFIG_CLK_BCM_NS2) += clk-ns2.o diff --git a/drivers/clk/bcm/clk-bcm53573-ilp.c b/drivers/clk/bcm/clk-bcm53573-ilp.c new file mode 100644 index 0000000..36eb371 --- /dev/null +++ b/drivers/clk/bcm/clk-bcm53573-ilp.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 RafaÅ‚ MiÅ‚ecki + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PMU_XTAL_FREQ_RATIO 0x66c +#define XTAL_ALP_PER_4ILP 0x00001fff +#define XTAL_CTL_EN 0x80000000 +#define PMU_SLOW_CLK_PERIOD 0x6dc + +struct bcm53573_ilp { + struct clk_hw hw; + struct regmap *regmap; +}; + +static int bcm53573_ilp_enable(struct clk_hw *hw) +{ + struct bcm53573_ilp *ilp = container_of(hw, struct bcm53573_ilp, hw); + + regmap_write(ilp->regmap, PMU_SLOW_CLK_PERIOD, 0x10199); + regmap_write(ilp->regmap, 0x674, 0x10000); + + return 0; +} + +static void bcm53573_ilp_disable(struct clk_hw *hw) +{ + struct bcm53573_ilp *ilp = container_of(hw, struct bcm53573_ilp, hw); + + regmap_write(ilp->regmap, PMU_SLOW_CLK_PERIOD, 0); + regmap_write(ilp->regmap, 0x674, 0); +} + +static unsigned long bcm53573_ilp_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct bcm53573_ilp *ilp = container_of(hw, struct bcm53573_ilp, hw); + struct regmap *regmap = ilp->regmap; + u32 last_val, cur_val; + int sum = 0, num = 0, loop_num = 0; + int avg; + + /* Enable measurement */ + regmap_write(regmap, PMU_XTAL_FREQ_RATIO, XTAL_CTL_EN); + + /* Read initial value */ + regmap_read(regmap, PMU_XTAL_FREQ_RATIO, &last_val); + last_val &= XTAL_ALP_PER_4ILP; + + /* + * At minimum we should loop for a bit to let hardware do the + * measurement. This isn't very accurate however, so for a better + * precision lets try getting 20 different values for and use average. + */ + while (num < 20) { + regmap_read(regmap, PMU_XTAL_FREQ_RATIO, &cur_val); + cur_val &= XTAL_ALP_PER_4ILP; + + if (cur_val != last_val) { + /* Got different value, use it */ + sum += cur_val; + num++; + loop_num = 0; + last_val = cur_val; + } else if (++loop_num > 5000) { + /* Same value over and over, give up */ + sum += cur_val; + num++; + break; + } + + cpu_relax(); + } + + /* Disable measurement to save power */ + regmap_write(regmap, PMU_XTAL_FREQ_RATIO, 0x0); + + avg = sum / num; + + return parent_rate * 4 / avg; +} + +static const struct clk_ops bcm53573_ilp_clk_ops = { + .enable = bcm53573_ilp_enable, + .disable = bcm53573_ilp_disable, + .recalc_rate = bcm53573_ilp_recalc_rate, +}; + +static void bcm53573_ilp_init(struct device_node *np) +{ + struct bcm53573_ilp *ilp; + struct clk_init_data init = { }; + const char *parent_name; + int err; + + ilp = kzalloc(sizeof(*ilp), GFP_KERNEL); + if (!ilp) + return; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) { + err = -ENOENT; + goto err_free_ilp; + } + + ilp->regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(ilp->regmap)) { + err = PTR_ERR(ilp->regmap); + goto err_free_ilp; + } + + init.name = np->name; + init.ops = &bcm53573_ilp_clk_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + ilp->hw.init = &init; + err = clk_hw_register(NULL, &ilp->hw); + if (err) + goto err_free_ilp; + + err = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &ilp->hw); + if (err) + goto err_clk_hw_unregister; + + return; + +err_clk_hw_unregister: + clk_hw_unregister(&ilp->hw); +err_free_ilp: + kfree(ilp); + pr_err("Failed to init ILP clock: %d\n", err); +} + +/* We need it very early for arch code, before device model gets ready */ +CLK_OF_DECLARE(bcm53573_ilp_clk, "brcm,bcm53573-ilp", bcm53573_ilp_init); -- cgit v0.10.2 From 734d82f4a678e897a3197b3e61313e32c9e77f46 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 16 Sep 2016 16:40:03 +0900 Subject: clk: uniphier: add core support code for UniPhier clock driver This includes UniPhier clock driver code, except SoC-specific data arrays. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd diff --git a/MAINTAINERS b/MAINTAINERS index d695e65..42ec61c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1828,6 +1828,7 @@ F: arch/arm/mach-uniphier/ F: arch/arm/mm/cache-uniphier.c F: arch/arm64/boot/dts/socionext/ F: drivers/bus/uniphier-system-bus.c +F: drivers/clk/uniphier/ F: drivers/i2c/busses/i2c-uniphier* F: drivers/pinctrl/uniphier/ F: drivers/tty/serial/8250/8250_uniphier.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index bf7d540..6a8ac04 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -209,5 +209,6 @@ source "drivers/clk/samsung/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" source "drivers/clk/ti/Kconfig" +source "drivers/clk/uniphier/Kconfig" endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e775a83..8264d81 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ +obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_X86) += x86/ diff --git a/drivers/clk/uniphier/Kconfig b/drivers/clk/uniphier/Kconfig new file mode 100644 index 0000000..5512377 --- /dev/null +++ b/drivers/clk/uniphier/Kconfig @@ -0,0 +1,9 @@ +config CLK_UNIPHIER + bool "Clock driver for UniPhier SoCs" + depends on ARCH_UNIPHIER || COMPILE_TEST + depends on OF && MFD_SYSCON + default ARCH_UNIPHIER + help + Support for clock controllers on UniPhier SoCs. + Say Y if you want to control clocks provided by System Control + block, Media I/O block, Peripheral Block. diff --git a/drivers/clk/uniphier/Makefile b/drivers/clk/uniphier/Makefile new file mode 100644 index 0000000..88a28ca --- /dev/null +++ b/drivers/clk/uniphier/Makefile @@ -0,0 +1,5 @@ +obj-y += clk-uniphier-core.o +obj-y += clk-uniphier-fixed-factor.o +obj-y += clk-uniphier-fixed-rate.o +obj-y += clk-uniphier-gate.o +obj-y += clk-uniphier-mux.o diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c new file mode 100644 index 0000000..a6e2a94 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-uniphier.h" + +static struct clk_hw *uniphier_clk_register(struct device *dev, + struct regmap *regmap, + const struct uniphier_clk_data *data) +{ + switch (data->type) { + case UNIPHIER_CLK_TYPE_FIXED_FACTOR: + return uniphier_clk_register_fixed_factor(dev, data->name, + &data->data.factor); + case UNIPHIER_CLK_TYPE_FIXED_RATE: + return uniphier_clk_register_fixed_rate(dev, data->name, + &data->data.rate); + case UNIPHIER_CLK_TYPE_GATE: + return uniphier_clk_register_gate(dev, regmap, data->name, + &data->data.gate); + case UNIPHIER_CLK_TYPE_MUX: + return uniphier_clk_register_mux(dev, regmap, data->name, + &data->data.mux); + default: + dev_err(dev, "unsupported clock type\n"); + return ERR_PTR(-EINVAL); + } +} + +static int uniphier_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct clk_hw_onecell_data *hw_data; + const struct uniphier_clk_data *p, *data; + struct regmap *regmap; + struct device_node *parent; + int clk_num = 0; + + data = of_device_get_match_data(dev); + if (WARN_ON(!data)) + return -EINVAL; + + parent = of_get_parent(dev->of_node); /* parent should be syscon node */ + regmap = syscon_node_to_regmap(parent); + of_node_put(parent); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to get regmap (error %ld)\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + for (p = data; p->name; p++) + clk_num = max(clk_num, p->idx + 1); + + hw_data = devm_kzalloc(dev, + sizeof(*hw_data) + clk_num * sizeof(struct clk_hw *), + GFP_KERNEL); + if (!hw_data) + return -ENOMEM; + + hw_data->num = clk_num; + + /* avoid returning NULL for unused idx */ + for (; clk_num >= 0; clk_num--) + hw_data->hws[clk_num] = ERR_PTR(-EINVAL); + + for (p = data; p->name; p++) { + struct clk_hw *hw; + + dev_dbg(dev, "register %s (index=%d)\n", p->name, p->idx); + hw = uniphier_clk_register(dev, regmap, p); + if (IS_ERR(hw)) { + dev_err(dev, "failed to register %s (error %ld)\n", + p->name, PTR_ERR(hw)); + return PTR_ERR(hw); + } + + if (p->idx >= 0) + hw_data->hws[p->idx] = hw; + } + + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + hw_data); +} + +static int uniphier_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +static const struct of_device_id uniphier_clk_match[] = { + { /* sentinel */ } +}; + +static struct platform_driver uniphier_clk_driver = { + .probe = uniphier_clk_probe, + .remove = uniphier_clk_remove, + .driver = { + .name = "uniphier-clk", + .of_match_table = uniphier_clk_match, + }, +}; +builtin_platform_driver(uniphier_clk_driver); diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-factor.c b/drivers/clk/uniphier/clk-uniphier-fixed-factor.c new file mode 100644 index 0000000..da2d9f4 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-fixed-factor.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "clk-uniphier.h" + +struct clk_hw *uniphier_clk_register_fixed_factor(struct device *dev, + const char *name, + const struct uniphier_clk_fixed_factor_data *data) +{ + struct clk_fixed_factor *fix; + struct clk_init_data init; + int ret; + + fix = devm_kzalloc(dev, sizeof(*fix), GFP_KERNEL); + if (!fix) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_fixed_factor_ops; + init.flags = data->parent_name ? CLK_SET_RATE_PARENT : 0; + init.parent_names = data->parent_name ? &data->parent_name : NULL; + init.num_parents = data->parent_name ? 1 : 0; + + fix->mult = data->mult; + fix->div = data->div; + fix->hw.init = &init; + + ret = devm_clk_hw_register(dev, &fix->hw); + if (ret) + return ERR_PTR(ret); + + return &fix->hw; +} diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c new file mode 100644 index 0000000..0ad0d46 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "clk-uniphier.h" + +struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, + const char *name, + const struct uniphier_clk_fixed_rate_data *data) +{ + struct clk_fixed_rate *fixed; + struct clk_init_data init; + int ret; + + /* allocate fixed-rate clock */ + fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL); + if (!fixed) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_fixed_rate_ops; + init.parent_names = NULL; + init.num_parents = 0; + + fixed->fixed_rate = data->fixed_rate; + fixed->hw.init = &init; + + ret = devm_clk_hw_register(dev, &fixed->hw); + if (ret) + return ERR_PTR(ret); + + return &fixed->hw; +} diff --git a/drivers/clk/uniphier/clk-uniphier-gate.c b/drivers/clk/uniphier/clk-uniphier-gate.c new file mode 100644 index 0000000..49142d4 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-gate.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include "clk-uniphier.h" + +struct uniphier_clk_gate { + struct clk_hw hw; + struct regmap *regmap; + unsigned int reg; + unsigned int bit; +}; + +#define to_uniphier_clk_gate(_hw) \ + container_of(_hw, struct uniphier_clk_gate, hw) + +static int uniphier_clk_gate_endisable(struct clk_hw *hw, int enable) +{ + struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); + + return regmap_write_bits(gate->regmap, gate->reg, BIT(gate->bit), + enable ? BIT(gate->bit) : 0); +} + +static int uniphier_clk_gate_enable(struct clk_hw *hw) +{ + return uniphier_clk_gate_endisable(hw, 1); +} + +static void uniphier_clk_gate_disable(struct clk_hw *hw) +{ + if (uniphier_clk_gate_endisable(hw, 0) < 0) + pr_warn("failed to disable clk\n"); +} + +static int uniphier_clk_gate_is_enabled(struct clk_hw *hw) +{ + struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); + unsigned int val; + + if (regmap_read(gate->regmap, gate->reg, &val) < 0) + pr_warn("is_enabled() may return wrong result\n"); + + return !!(val & BIT(gate->bit)); +} + +static const struct clk_ops uniphier_clk_gate_ops = { + .enable = uniphier_clk_gate_enable, + .disable = uniphier_clk_gate_disable, + .is_enabled = uniphier_clk_gate_is_enabled, +}; + +struct clk_hw *uniphier_clk_register_gate(struct device *dev, + struct regmap *regmap, + const char *name, + const struct uniphier_clk_gate_data *data) +{ + struct uniphier_clk_gate *gate; + struct clk_init_data init; + int ret; + + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &uniphier_clk_gate_ops; + init.flags = data->parent_name ? CLK_SET_RATE_PARENT : 0; + init.parent_names = data->parent_name ? &data->parent_name : NULL; + init.num_parents = data->parent_name ? 1 : 0; + + gate->regmap = regmap; + gate->reg = data->reg; + gate->bit = data->bit; + gate->hw.init = &init; + + ret = devm_clk_hw_register(dev, &gate->hw); + if (ret) + return ERR_PTR(ret); + + return &gate->hw; +} diff --git a/drivers/clk/uniphier/clk-uniphier-mux.c b/drivers/clk/uniphier/clk-uniphier-mux.c new file mode 100644 index 0000000..15a2f2c --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-mux.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include "clk-uniphier.h" + +struct uniphier_clk_mux { + struct clk_hw hw; + struct regmap *regmap; + unsigned int reg; + const unsigned int *masks; + const unsigned int *vals; +}; + +#define to_uniphier_clk_mux(_hw) container_of(_hw, struct uniphier_clk_mux, hw) + +static int uniphier_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); + + return regmap_write_bits(mux->regmap, mux->reg, mux->masks[index], + mux->vals[index]); +} + +static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw) +{ + struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); + int num_parents = clk_hw_get_num_parents(hw); + int ret; + u32 val; + u8 i; + + ret = regmap_read(mux->regmap, mux->reg, &val); + if (ret) + return ret; + + for (i = 0; i < num_parents; i++) + if ((mux->masks[i] & val) == mux->vals[i]) + return i; + + return -EINVAL; +} + +static const struct clk_ops uniphier_clk_mux_ops = { + .determine_rate = __clk_mux_determine_rate, + .set_parent = uniphier_clk_mux_set_parent, + .get_parent = uniphier_clk_mux_get_parent, +}; + +struct clk_hw *uniphier_clk_register_mux(struct device *dev, + struct regmap *regmap, + const char *name, + const struct uniphier_clk_mux_data *data) +{ + struct uniphier_clk_mux *mux; + struct clk_init_data init; + int ret; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &uniphier_clk_mux_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = data->parent_names; + init.num_parents = data->num_parents, + + mux->regmap = regmap; + mux->reg = data->reg; + mux->masks = data->masks; + mux->vals = data->vals; + mux->hw.init = &init; + + ret = devm_clk_hw_register(dev, &mux->hw); + if (ret) + return ERR_PTR(ret); + + return &mux->hw; +} diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h new file mode 100644 index 0000000..3e354e9 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __CLK_UNIPHIER_H__ +#define __CLK_UNIPHIER_H__ + +struct clk_hw; +struct device; +struct regmap; + +#define UNIPHIER_CLK_MUX_MAX_PARENTS 8 + +enum uniphier_clk_type { + UNIPHIER_CLK_TYPE_FIXED_FACTOR, + UNIPHIER_CLK_TYPE_FIXED_RATE, + UNIPHIER_CLK_TYPE_GATE, + UNIPHIER_CLK_TYPE_MUX, +}; + +struct uniphier_clk_fixed_factor_data { + const char *parent_name; + unsigned int mult; + unsigned int div; +}; + +struct uniphier_clk_fixed_rate_data { + unsigned long fixed_rate; +}; + +struct uniphier_clk_gate_data { + const char *parent_name; + unsigned int reg; + unsigned int bit; +}; + +struct uniphier_clk_mux_data { + const char *parent_names[UNIPHIER_CLK_MUX_MAX_PARENTS]; + unsigned int num_parents; + unsigned int reg; + unsigned int masks[UNIPHIER_CLK_MUX_MAX_PARENTS]; + unsigned int vals[UNIPHIER_CLK_MUX_MAX_PARENTS]; +}; + +struct uniphier_clk_data { + const char *name; + enum uniphier_clk_type type; + int idx; + union { + struct uniphier_clk_fixed_factor_data factor; + struct uniphier_clk_fixed_rate_data rate; + struct uniphier_clk_gate_data gate; + struct uniphier_clk_mux_data mux; + } data; +}; + +#define UNIPHIER_CLK_FACTOR(_name, _idx, _parent, _mult, _div) \ + { \ + .name = (_name), \ + .type = UNIPHIER_CLK_TYPE_FIXED_FACTOR, \ + .idx = (_idx), \ + .data.factor = { \ + .parent_name = (_parent), \ + .mult = (_mult), \ + .div = (_div), \ + }, \ + } + + +#define UNIPHIER_CLK_GATE(_name, _idx, _parent, _reg, _bit) \ + { \ + .name = (_name), \ + .type = UNIPHIER_CLK_TYPE_GATE, \ + .idx = (_idx), \ + .data.gate = { \ + .parent_name = (_parent), \ + .reg = (_reg), \ + .bit = (_bit), \ + }, \ + } + + +struct clk_hw *uniphier_clk_register_fixed_factor(struct device *dev, + const char *name, + const struct uniphier_clk_fixed_factor_data *data); +struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, + const char *name, + const struct uniphier_clk_fixed_rate_data *data); +struct clk_hw *uniphier_clk_register_gate(struct device *dev, + struct regmap *regmap, + const char *name, + const struct uniphier_clk_gate_data *data); +struct clk_hw *uniphier_clk_register_mux(struct device *dev, + struct regmap *regmap, + const char *name, + const struct uniphier_clk_mux_data *data); + +#endif /* __CLK_UNIPHIER_H__ */ -- cgit v0.10.2 From 7f4d3b52b6b69f274006cc65984672bfa7fd8b92 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 16 Sep 2016 16:40:04 +0900 Subject: clk: uniphier: add clock data for UniPhier SoCs Add clock data arrays for all UniPhier SoCs with a binding document. Signed-off-by: Masahiro Yamada Acked-by: Rob Herring Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/uniphier-clock.txt b/Documentation/devicetree/bindings/clock/uniphier-clock.txt new file mode 100644 index 0000000..c7179d3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/uniphier-clock.txt @@ -0,0 +1,134 @@ +UniPhier clock controller + + +System clock +------------ + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-sld3-clock" - for sLD3 SoC. + "socionext,uniphier-ld4-clock" - for LD4 SoC. + "socionext,uniphier-pro4-clock" - for Pro4 SoC. + "socionext,uniphier-sld8-clock" - for sLD8 SoC. + "socionext,uniphier-pro5-clock" - for Pro5 SoC. + "socionext,uniphier-pxs2-clock" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-clock" - for LD11 SoC. + "socionext,uniphier-ld20-clock" - for LD20 SoC. +- #clock-cells: should be 1. + +Example: + + sysctrl@61840000 { + compatible = "socionext,uniphier-sysctrl", + "simple-mfd", "syscon"; + reg = <0x61840000 0x4000>; + + clock { + compatible = "socionext,uniphier-ld20-clock"; + #clock-cells = <1>; + }; + + other nodes ... + }; + +Provided clocks: + + 8: ST DMAC +12: GIO (Giga bit stream I/O) +14: USB3 ch0 host +15: USB3 ch1 host +16: USB3 ch0 PHY0 +17: USB3 ch0 PHY1 +20: USB3 ch1 PHY0 +21: USB3 ch1 PHY1 + + +Media I/O (MIO) clock +--------------------- + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-sld3-mio-clock" - for sLD3 SoC. + "socionext,uniphier-ld4-mio-clock" - for LD4 SoC. + "socionext,uniphier-pro4-mio-clock" - for Pro4 SoC. + "socionext,uniphier-sld8-mio-clock" - for sLD8 SoC. + "socionext,uniphier-pro5-mio-clock" - for Pro5 SoC. + "socionext,uniphier-pxs2-mio-clock" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-mio-clock" - for LD11 SoC. + "socionext,uniphier-ld20-mio-clock" - for LD20 SoC. +- #clock-cells: should be 1. + +Example: + + mioctrl@59810000 { + compatible = "socionext,uniphier-mioctrl", + "simple-mfd", "syscon"; + reg = <0x59810000 0x800>; + + clock { + compatible = "socionext,uniphier-ld20-mio-clock"; + #clock-cells = <1>; + }; + + other nodes ... + }; + +Provided clocks: + + 0: SD ch0 host + 1: eMMC host + 2: SD ch1 host + 7: MIO DMAC + 8: USB2 ch0 host + 9: USB2 ch1 host +10: USB2 ch2 host +11: USB2 ch3 host +12: USB2 ch0 PHY +13: USB2 ch1 PHY +14: USB2 ch2 PHY +15: USB2 ch3 PHY + + +Peripheral clock +---------------- + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-sld3-peri-clock" - for sLD3 SoC. + "socionext,uniphier-ld4-peri-clock" - for LD4 SoC. + "socionext,uniphier-pro4-peri-clock" - for Pro4 SoC. + "socionext,uniphier-sld8-peri-clock" - for sLD8 SoC. + "socionext,uniphier-pro5-peri-clock" - for Pro5 SoC. + "socionext,uniphier-pxs2-peri-clock" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-peri-clock" - for LD11 SoC. + "socionext,uniphier-ld20-peri-clock" - for LD20 SoC. +- #clock-cells: should be 1. + +Example: + + perictrl@59820000 { + compatible = "socionext,uniphier-perictrl", + "simple-mfd", "syscon"; + reg = <0x59820000 0x200>; + + clock { + compatible = "socionext,uniphier-ld20-peri-clock"; + #clock-cells = <1>; + }; + + other nodes ... + }; + +Provided clocks: + + 0: UART ch0 + 1: UART ch1 + 2: UART ch2 + 3: UART ch3 + 4: I2C ch0 + 5: I2C ch1 + 6: I2C ch2 + 7: I2C ch3 + 8: I2C ch4 + 9: I2C ch5 +10: I2C ch6 diff --git a/drivers/clk/uniphier/Makefile b/drivers/clk/uniphier/Makefile index 88a28ca..f27b3603 100644 --- a/drivers/clk/uniphier/Makefile +++ b/drivers/clk/uniphier/Makefile @@ -3,3 +3,6 @@ obj-y += clk-uniphier-fixed-factor.o obj-y += clk-uniphier-fixed-rate.o obj-y += clk-uniphier-gate.o obj-y += clk-uniphier-mux.o +obj-y += clk-uniphier-sys.o +obj-y += clk-uniphier-mio.o +obj-y += clk-uniphier-peri.o diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index a6e2a94..5ffb898 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -109,6 +109,97 @@ static int uniphier_clk_remove(struct platform_device *pdev) } static const struct of_device_id uniphier_clk_match[] = { + /* System clock */ + { + .compatible = "socionext,uniphier-ld4-clock", + .data = uniphier_ld4_sys_clk_data, + }, + { + .compatible = "socionext,uniphier-pro4-clock", + .data = uniphier_pro4_sys_clk_data, + }, + { + .compatible = "socionext,uniphier-sld8-clock", + .data = uniphier_sld8_sys_clk_data, + }, + { + .compatible = "socionext,uniphier-pro5-clock", + .data = uniphier_pro5_sys_clk_data, + }, + { + .compatible = "socionext,uniphier-pxs2-clock", + .data = uniphier_pxs2_sys_clk_data, + }, + { + .compatible = "socionext,uniphier-ld11-clock", + .data = uniphier_ld11_sys_clk_data, + }, + { + .compatible = "socionext,uniphier-ld20-clock", + .data = uniphier_ld20_sys_clk_data, + }, + /* Media I/O clock */ + { + .compatible = "socionext,uniphier-sld3-mio-clock", + .data = uniphier_sld3_mio_clk_data, + }, + { + .compatible = "socionext,uniphier-ld4-mio-clock", + .data = uniphier_sld3_mio_clk_data, + }, + { + .compatible = "socionext,uniphier-pro4-mio-clock", + .data = uniphier_sld3_mio_clk_data, + }, + { + .compatible = "socionext,uniphier-sld8-mio-clock", + .data = uniphier_sld3_mio_clk_data, + }, + { + .compatible = "socionext,uniphier-pro5-mio-clock", + .data = uniphier_pro5_mio_clk_data, + }, + { + .compatible = "socionext,uniphier-pxs2-mio-clock", + .data = uniphier_pro5_mio_clk_data, + }, + { + .compatible = "socionext,uniphier-ld11-mio-clock", + .data = uniphier_sld3_mio_clk_data, + }, + { + .compatible = "socionext,uniphier-ld20-mio-clock", + .data = uniphier_pro5_mio_clk_data, + }, + /* Peripheral clock */ + { + .compatible = "socionext,uniphier-ld4-peri-clock", + .data = uniphier_ld4_peri_clk_data, + }, + { + .compatible = "socionext,uniphier-pro4-peri-clock", + .data = uniphier_pro4_peri_clk_data, + }, + { + .compatible = "socionext,uniphier-sld8-peri-clock", + .data = uniphier_ld4_peri_clk_data, + }, + { + .compatible = "socionext,uniphier-pro5-peri-clock", + .data = uniphier_pro4_peri_clk_data, + }, + { + .compatible = "socionext,uniphier-pxs2-peri-clock", + .data = uniphier_pro4_peri_clk_data, + }, + { + .compatible = "socionext,uniphier-ld11-peri-clock", + .data = uniphier_pro4_peri_clk_data, + }, + { + .compatible = "socionext,uniphier-ld20-peri-clock", + .data = uniphier_pro4_peri_clk_data, + }, { /* sentinel */ } }; diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c new file mode 100644 index 0000000..6aa7ec7 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-mio.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "clk-uniphier.h" + +#define UNIPHIER_MIO_CLK_SD_FIXED \ + UNIPHIER_CLK_FACTOR("sd-44m", -1, "sd-133m", 1, 3), \ + UNIPHIER_CLK_FACTOR("sd-33m", -1, "sd-200m", 1, 6), \ + UNIPHIER_CLK_FACTOR("sd-50m", -1, "sd-200m", 1, 4), \ + UNIPHIER_CLK_FACTOR("sd-67m", -1, "sd-200m", 1, 3), \ + UNIPHIER_CLK_FACTOR("sd-100m", -1, "sd-200m", 1, 2), \ + UNIPHIER_CLK_FACTOR("sd-40m", -1, "sd-200m", 1, 5), \ + UNIPHIER_CLK_FACTOR("sd-25m", -1, "sd-200m", 1, 8), \ + UNIPHIER_CLK_FACTOR("sd-22m", -1, "sd-133m", 1, 6) + +#define UNIPHIER_MIO_CLK_SD(_idx, ch) \ + { \ + .name = "sd" #ch "-sel", \ + .type = UNIPHIER_CLK_TYPE_MUX, \ + .idx = -1, \ + .data.mux = { \ + .parent_names = { \ + "sd-44m", \ + "sd-33m", \ + "sd-50m", \ + "sd-67m", \ + "sd-100m", \ + "sd-40m", \ + "sd-25m", \ + "sd-22m", \ + }, \ + .num_parents = 8, \ + .reg = 0x30 + 0x200 * (ch), \ + .masks = { \ + 0x00031000, \ + 0x00031000, \ + 0x00031000, \ + 0x00031000, \ + 0x00001300, \ + 0x00001300, \ + 0x00001300, \ + 0x00001300, \ + }, \ + .vals = { \ + 0x00000000, \ + 0x00010000, \ + 0x00020000, \ + 0x00030000, \ + 0x00001000, \ + 0x00001100, \ + 0x00001200, \ + 0x00001300, \ + }, \ + }, \ + }, \ + UNIPHIER_CLK_GATE("sd" #ch, (_idx), "sd" #ch "-sel", 0x20 + 0x200 * (ch), 8) + +#define UNIPHIER_MIO_CLK_USB2(idx, ch) \ + UNIPHIER_CLK_GATE("usb2" #ch, (idx), "usb2", 0x20 + 0x200 * (ch), 28) + +#define UNIPHIER_MIO_CLK_USB2_PHY(idx, ch) \ + UNIPHIER_CLK_GATE("usb2" #ch "-phy", (idx), "usb2", 0x20 + 0x200 * (ch), 29) + +#define UNIPHIER_MIO_CLK_DMAC(idx) \ + UNIPHIER_CLK_GATE("miodmac", (idx), "stdmac", 0x20, 25) + +const struct uniphier_clk_data uniphier_sld3_mio_clk_data[] = { + UNIPHIER_MIO_CLK_SD_FIXED, + UNIPHIER_MIO_CLK_SD(0, 0), + UNIPHIER_MIO_CLK_SD(1, 1), + UNIPHIER_MIO_CLK_SD(2, 2), + UNIPHIER_MIO_CLK_DMAC(7), + UNIPHIER_MIO_CLK_USB2(8, 0), + UNIPHIER_MIO_CLK_USB2(9, 1), + UNIPHIER_MIO_CLK_USB2(10, 2), + UNIPHIER_MIO_CLK_USB2(11, 3), + UNIPHIER_MIO_CLK_USB2_PHY(12, 0), + UNIPHIER_MIO_CLK_USB2_PHY(13, 1), + UNIPHIER_MIO_CLK_USB2_PHY(14, 2), + UNIPHIER_MIO_CLK_USB2_PHY(15, 3), + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_pro5_mio_clk_data[] = { + UNIPHIER_MIO_CLK_SD_FIXED, + UNIPHIER_MIO_CLK_SD(0, 0), + UNIPHIER_MIO_CLK_SD(1, 1), + { /* sentinel */ } +}; diff --git a/drivers/clk/uniphier/clk-uniphier-peri.c b/drivers/clk/uniphier/clk-uniphier-peri.c new file mode 100644 index 0000000..521c80e --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-peri.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "clk-uniphier.h" + +#define UNIPHIER_PERI_CLK_UART(idx, ch) \ + UNIPHIER_CLK_GATE("uart" #ch, (idx), "uart", 0x24, 19 + (ch)) + +#define UNIPHIER_PERI_CLK_I2C_COMMON \ + UNIPHIER_CLK_GATE("i2c-common", -1, "i2c", 0x20, 1) + +#define UNIPHIER_PERI_CLK_I2C(idx, ch) \ + UNIPHIER_CLK_GATE("i2c" #ch, (idx), "i2c-common", 0x24, 5 + (ch)) + +#define UNIPHIER_PERI_CLK_FI2C(idx, ch) \ + UNIPHIER_CLK_GATE("i2c" #ch, (idx), "i2c", 0x24, 24 + (ch)) + +const struct uniphier_clk_data uniphier_ld4_peri_clk_data[] = { + UNIPHIER_PERI_CLK_UART(0, 0), + UNIPHIER_PERI_CLK_UART(1, 1), + UNIPHIER_PERI_CLK_UART(2, 2), + UNIPHIER_PERI_CLK_UART(3, 3), + UNIPHIER_PERI_CLK_I2C_COMMON, + UNIPHIER_PERI_CLK_I2C(4, 0), + UNIPHIER_PERI_CLK_I2C(5, 1), + UNIPHIER_PERI_CLK_I2C(6, 2), + UNIPHIER_PERI_CLK_I2C(7, 3), + UNIPHIER_PERI_CLK_I2C(8, 4), + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_pro4_peri_clk_data[] = { + UNIPHIER_PERI_CLK_UART(0, 0), + UNIPHIER_PERI_CLK_UART(1, 1), + UNIPHIER_PERI_CLK_UART(2, 2), + UNIPHIER_PERI_CLK_UART(3, 3), + UNIPHIER_PERI_CLK_FI2C(4, 0), + UNIPHIER_PERI_CLK_FI2C(5, 1), + UNIPHIER_PERI_CLK_FI2C(6, 2), + UNIPHIER_PERI_CLK_FI2C(7, 3), + UNIPHIER_PERI_CLK_FI2C(8, 4), + UNIPHIER_PERI_CLK_FI2C(9, 5), + UNIPHIER_PERI_CLK_FI2C(10, 6), + { /* sentinel */ } +}; diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c new file mode 100644 index 0000000..5d02999 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include "clk-uniphier.h" + +#define UNIPHIER_SLD3_SYS_CLK_SD \ + UNIPHIER_CLK_FACTOR("sd-200m", -1, "spll", 1, 8), \ + UNIPHIER_CLK_FACTOR("sd-133m", -1, "vpll27a", 1, 2) + +#define UNIPHIER_PRO5_SYS_CLK_SD \ + UNIPHIER_CLK_FACTOR("sd-200m", -1, "spll", 1, 12), \ + UNIPHIER_CLK_FACTOR("sd-133m", -1, "spll", 1, 18) + +#define UNIPHIER_LD20_SYS_CLK_SD \ + UNIPHIER_CLK_FACTOR("sd-200m", -1, "spll", 1, 10), \ + UNIPHIER_CLK_FACTOR("sd-133m", -1, "spll", 1, 15) + +#define UNIPHIER_SLD3_SYS_CLK_STDMAC(idx) \ + UNIPHIER_CLK_GATE("stdmac", (idx), NULL, 0x2104, 10) + +#define UNIPHIER_LD11_SYS_CLK_STDMAC(idx) \ + UNIPHIER_CLK_GATE("stdmac", (idx), NULL, 0x210c, 8) + +#define UNIPHIER_PRO4_SYS_CLK_GIO(idx) \ + UNIPHIER_CLK_GATE("gio", (idx), NULL, 0x2104, 6) + +#define UNIPHIER_PRO4_SYS_CLK_USB3(idx, ch) \ + UNIPHIER_CLK_GATE("usb3" #ch, (idx), NULL, 0x2104, 16 + (ch)) + +const struct uniphier_clk_data uniphier_sld3_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 65, 1), /* 1597.44 MHz */ + UNIPHIER_CLK_FACTOR("upll", -1, "ref", 6000, 512), /* 288 MHz */ + UNIPHIER_CLK_FACTOR("a2pll", -1, "ref", 24, 1), /* 589.824 MHz */ + UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 5625, 512), /* 270 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 16), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), + UNIPHIER_SLD3_SYS_CLK_SD, + UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), + UNIPHIER_SLD3_SYS_CLK_STDMAC(8), + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_ld4_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 65, 1), /* 1597.44 MHz */ + UNIPHIER_CLK_FACTOR("upll", -1, "ref", 6000, 512), /* 288 MHz */ + UNIPHIER_CLK_FACTOR("a2pll", -1, "ref", 24, 1), /* 589.824 MHz */ + UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 5625, 512), /* 270 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 16), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), + UNIPHIER_SLD3_SYS_CLK_SD, + UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), + UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 64, 1), /* 1600 MHz */ + UNIPHIER_CLK_FACTOR("upll", -1, "ref", 288, 25), /* 288 MHz */ + UNIPHIER_CLK_FACTOR("a2pll", -1, "upll", 256, 125), /* 589.824 MHz */ + UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 270, 25), /* 270 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 8), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 32), + UNIPHIER_SLD3_SYS_CLK_SD, + UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), + UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* HSC, MIO, RLE */ + UNIPHIER_PRO4_SYS_CLK_GIO(12), /* Ether, SATA, USB3 */ + UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), + UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_sld8_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 64, 1), /* 1600 MHz */ + UNIPHIER_CLK_FACTOR("upll", -1, "ref", 288, 25), /* 288 MHz */ + UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 270, 25), /* 270 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 20), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), + UNIPHIER_SLD3_SYS_CLK_SD, + UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), + UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 120, 1), /* 2400 MHz */ + UNIPHIER_CLK_FACTOR("dapll1", -1, "ref", 128, 1), /* 2560 MHz */ + UNIPHIER_CLK_FACTOR("dapll2", -1, "ref", 144, 125), /* 2949.12 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "dapll2", 1, 40), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), + UNIPHIER_PRO5_SYS_CLK_SD, + UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* HSC */ + UNIPHIER_PRO4_SYS_CLK_GIO(12), /* PCIe, USB3 */ + UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), + UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 96, 1), /* 2400 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 27), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), + UNIPHIER_PRO5_SYS_CLK_SD, + UNIPHIER_SLD3_SYS_CLK_STDMAC(8), /* HSC, RLE */ + /* GIO is always clock-enabled: no function for 0x2104 bit6 */ + UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), + UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + /* The document mentions 0x2104 bit 18, but not functional */ + UNIPHIER_CLK_GATE("usb30-phy", 16, NULL, 0x2104, 19), + UNIPHIER_CLK_GATE("usb31-phy", 20, NULL, 0x2104, 20), + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_ld11_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 80, 1), /* 2000 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 34), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), + UNIPHIER_LD11_SYS_CLK_STDMAC(8), /* HSC, MIO */ + UNIPHIER_CLK_FACTOR("usb2", -1, "ref", 24, 25), + { /* sentinel */ } +}; + +const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = { + UNIPHIER_CLK_FACTOR("spll", -1, "ref", 80, 1), /* 2000 MHz */ + UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 34), + UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), + UNIPHIER_LD20_SYS_CLK_SD, + UNIPHIER_LD11_SYS_CLK_STDMAC(8), /* HSC */ + /* GIO is always clock-enabled: no function for 0x210c bit5 */ + /* + * clock for USB Link is enabled by the logic "OR" of bit 14 and bit 15. + * We do not use bit 15 here. + */ + UNIPHIER_CLK_GATE("usb30", 14, NULL, 0x210c, 14), + UNIPHIER_CLK_GATE("usb30-phy0", 16, NULL, 0x210c, 12), + UNIPHIER_CLK_GATE("usb30-phy1", 17, NULL, 0x210c, 13), + { /* sentinel */ } +}; diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h index 3e354e9..3ae1840 100644 --- a/drivers/clk/uniphier/clk-uniphier.h +++ b/drivers/clk/uniphier/clk-uniphier.h @@ -106,4 +106,17 @@ struct clk_hw *uniphier_clk_register_mux(struct device *dev, const char *name, const struct uniphier_clk_mux_data *data); +extern const struct uniphier_clk_data uniphier_sld3_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_ld4_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_pro4_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_sld8_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_pro5_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_ld11_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_ld20_sys_clk_data[]; +extern const struct uniphier_clk_data uniphier_sld3_mio_clk_data[]; +extern const struct uniphier_clk_data uniphier_pro5_mio_clk_data[]; +extern const struct uniphier_clk_data uniphier_ld4_peri_clk_data[]; +extern const struct uniphier_clk_data uniphier_pro4_peri_clk_data[]; + #endif /* __CLK_UNIPHIER_H__ */ -- cgit v0.10.2 From 377d6479d298339888c5d6fb460d3275e1763f8f Mon Sep 17 00:00:00 2001 From: Kalle Kankare Date: Mon, 19 Sep 2016 12:30:00 +0200 Subject: clk: imx53: Add clocks configuration Add clocks configuration for CSI, FIRI and IEEE1588. Signed-off-by: Fabien Lahoudere Acked-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c index 29d4c44..1e3c9ea 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx51-imx53.c @@ -126,6 +126,7 @@ static const char *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", }; static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_root_gate", }; static const char *step_sels[] = { "lp_apm", }; static const char *cpu_podf_sels[] = { "pll1_sw", "step_sel" }; +static const char *ieee1588_sels[] = { "pll3_sw", "pll4_sw", "dummy" /* usbphy2_clk */, "dummy" /* fec_phy_clk */ }; static struct clk *clk[IMX5_CLK_END]; static struct clk_onecell_data clk_data; @@ -543,6 +544,25 @@ static void __init mx53_clocks_init(struct device_node *np) clk[IMX5_CLK_I2C3_GATE] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22); clk[IMX5_CLK_SATA_GATE] = imx_clk_gate2("sata_gate", "ipg", MXC_CCM_CCGR4, 2); + clk[IMX5_CLK_FIRI_SEL] = imx_clk_mux("firi_sel", MXC_CCM_CSCMR2, 12, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_FIRI_PRED] = imx_clk_divider("firi_pred", "firi_sel", MXC_CCM_CSCDR3, 6, 3); + clk[IMX5_CLK_FIRI_PODF] = imx_clk_divider("firi_podf", "firi_pred", MXC_CCM_CSCDR3, 0, 6); + clk[IMX5_CLK_FIRI_SERIAL_GATE] = imx_clk_gate2("firi_serial_gate", "firi_podf", MXC_CCM_CCGR1, 28); + clk[IMX5_CLK_FIRI_IPG_GATE] = imx_clk_gate2("firi_ipg_gate", "ipg", MXC_CCM_CCGR1, 26); + + clk[IMX5_CLK_CSI0_MCLK1_SEL] = imx_clk_mux("csi0_mclk1_sel", MXC_CCM_CSCMR2, 22, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[IMX5_CLK_CSI0_MCLK1_PRED] = imx_clk_divider("csi0_mclk1_pred", "csi0_mclk1_sel", MXC_CCM_CSCDR4, 6, 3); + clk[IMX5_CLK_CSI0_MCLK1_PODF] = imx_clk_divider("csi0_mclk1_podf", "csi0_mclk1_pred", MXC_CCM_CSCDR4, 0, 6); + clk[IMX5_CLK_CSI0_MCLK1_GATE] = imx_clk_gate2("csi0_mclk1_serial_gate", "csi0_mclk1_podf", MXC_CCM_CCGR6, 4); + + clk[IMX5_CLK_IEEE1588_SEL] = imx_clk_mux("ieee1588_sel", MXC_CCM_CSCMR2, 14, 2, + ieee1588_sels, ARRAY_SIZE(ieee1588_sels)); + clk[IMX5_CLK_IEEE1588_PRED] = imx_clk_divider("ieee1588_pred", "ieee1588_sel", MXC_CCM_CSCDR2, 6, 3); + clk[IMX5_CLK_IEEE1588_PODF] = imx_clk_divider("ieee1588_podf", "ieee1588_pred", MXC_CCM_CSCDR2, 0, 6); + clk[IMX5_CLK_IEEE1588_GATE] = imx_clk_gate2("ieee1588_serial_gate", "ieee1588_podf", MXC_CCM_CCGR7, 6); + clk[IMX5_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", MXC_CCM_CCOSR, 0, 4, mx53_cko1_sel, ARRAY_SIZE(mx53_cko1_sel)); clk[IMX5_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", MXC_CCM_CCOSR, 4, 3); diff --git a/include/dt-bindings/clock/imx5-clock.h b/include/dt-bindings/clock/imx5-clock.h index f4b7478..d382fc7 100644 --- a/include/dt-bindings/clock/imx5-clock.h +++ b/include/dt-bindings/clock/imx5-clock.h @@ -201,6 +201,19 @@ #define IMX5_CLK_STEP_SEL 189 #define IMX5_CLK_CPU_PODF_SEL 190 #define IMX5_CLK_ARM 191 -#define IMX5_CLK_END 192 +#define IMX5_CLK_FIRI_PRED 192 +#define IMX5_CLK_FIRI_SEL 193 +#define IMX5_CLK_FIRI_PODF 194 +#define IMX5_CLK_FIRI_SERIAL_GATE 195 +#define IMX5_CLK_FIRI_IPG_GATE 196 +#define IMX5_CLK_CSI0_MCLK1_PRED 197 +#define IMX5_CLK_CSI0_MCLK1_SEL 198 +#define IMX5_CLK_CSI0_MCLK1_PODF 199 +#define IMX5_CLK_CSI0_MCLK1_GATE 200 +#define IMX5_CLK_IEEE1588_PRED 201 +#define IMX5_CLK_IEEE1588_SEL 202 +#define IMX5_CLK_IEEE1588_PODF 203 +#define IMX5_CLK_IEEE1588_GATE 204 +#define IMX5_CLK_END 205 #endif /* __DT_BINDINGS_CLOCK_IMX5_H */ -- cgit v0.10.2 From b1d51b448e4e6a392283b3eab06a7c5ec6d8a4e2 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 16 Sep 2016 11:16:10 +0200 Subject: clk: imx6: fix i.MX6DL clock tree to reflect reality The current clock tree only implements the minimal set of differences between the i.MX6Q and the i.MX6DL, but that doesn't really reflect reality. Apply the following fixes to match the RM: - DL has no GPU3D_SHADER_SEL/PODF, the shader domain is clocked by GPU3D_CORE - GPU3D_SHADER_SEL/PODF has been repurposed as GPU2D_CORE_SEL/PODF - GPU2D_CORE_SEL/PODF has been repurposed as MLB_SEL/PODF Cc: stable@vger.kernel.org Signed-off-by: Lucas Stach Acked-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index ba1c1ae..64c2431 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -318,11 +318,16 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels)); clk[IMX6QDL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2)); + } else if (clk_on_imx6dl()) { + clk[IMX6QDL_CLK_MLB_SEL] = imx_clk_mux("mlb_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); } else { clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); } clk[IMX6QDL_CLK_GPU3D_CORE_SEL] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels)); - clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); + if (clk_on_imx6dl()) + clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); + else + clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); clk[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); clk[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); @@ -400,9 +405,15 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); } - clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); + if (clk_on_imx6dl()) + clk[IMX6QDL_CLK_MLB_PODF] = imx_clk_divider("mlb_podf", "mlb_sel", base + 0x18, 23, 3); + else + clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); clk[IMX6QDL_CLK_GPU3D_CORE_PODF] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3); - clk[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); + if (clk_on_imx6dl()) + clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 29, 3); + else + clk[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); clk[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3); clk[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3); clk[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0); @@ -473,14 +484,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai); clk[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); clk[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); - if (clk_on_imx6dl()) - /* - * The multiplexer and divider of imx6q clock gpu3d_shader get - * redefined/reused as gpu2d_core_sel and gpu2d_core_podf on imx6dl. - */ - clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu3d_shader", base + 0x6c, 24); - else - clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); + clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4); @@ -511,7 +515,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) * The multiplexer and divider of the imx6q clock gpu2d get * redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl. */ - clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "gpu2d_core_podf", base + 0x74, 18); + clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "mlb_podf", base + 0x74, 18); else clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20); diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h index 2905033..da59fd9 100644 --- a/include/dt-bindings/clock/imx6qdl-clock.h +++ b/include/dt-bindings/clock/imx6qdl-clock.h @@ -269,6 +269,8 @@ #define IMX6QDL_CLK_PRG0_APB 256 #define IMX6QDL_CLK_PRG1_APB 257 #define IMX6QDL_CLK_PRE_AXI 258 -#define IMX6QDL_CLK_END 259 +#define IMX6QDL_CLK_MLB_SEL 259 +#define IMX6QDL_CLK_MLB_PODF 260 +#define IMX6QDL_CLK_END 261 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */ -- cgit v0.10.2 From d8846023aed1293e54d33499558fc2aa2b2f393f Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 16 Sep 2016 11:16:11 +0200 Subject: clk: imx6: initialize GPU clocks Initialize the GPU clock muxes to sane inputs. Until now they have not been changed from their default values, which means that both GPU3D shader and GPU2D core were fed by clock inputs whose rates exceed the maximium allowed frequency of the cores by as much as 200MHz. This fixes a severe GPU stability issue on i.MX6DL. Cc: stable@vger.kernel.org Signed-off-by: Lucas Stach Acked-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 64c2431..ce8ea10 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -633,6 +633,24 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) if (IS_ENABLED(CONFIG_PCI_IMX6)) clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]); + /* + * Initialize the GPU clock muxes, so that the maximum specified clock + * rates for the respective SoC are not exceeded. + */ + if (clk_on_imx6dl()) { + clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], + clk[IMX6QDL_CLK_PLL2_PFD1_594M]); + clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], + clk[IMX6QDL_CLK_PLL2_PFD1_594M]); + } else if (clk_on_imx6q()) { + clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], + clk[IMX6QDL_CLK_MMDC_CH0_AXI]); + clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL], + clk[IMX6QDL_CLK_PLL2_PFD1_594M]); + clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], + clk[IMX6QDL_CLK_PLL3_USB_OTG]); + } + imx_register_uart_clocks(uart_clks); } CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); -- cgit v0.10.2 From ec187ef0ce9880d9dc360261807c434e77783ac8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 20 Sep 2016 22:58:29 +0200 Subject: clk: at91: move slow clock controller clocks to sckc.c Move all clocks related to the slow clock controller to sckc.c. This avoids extern definitions and allows to remove sckc.h Signed-off-by: Alexandre Belloni [sboyd@codeaurora.org: Mark some functions static] Signed-off-by: Stephen Boyd diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index cd831e1..560a8b9 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c @@ -13,42 +13,11 @@ #include #include #include -#include #include #include #include #include "pmc.h" -#include "sckc.h" - -#define SLOW_CLOCK_FREQ 32768 -#define SLOWCK_SW_CYCLES 5 -#define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \ - SLOW_CLOCK_FREQ) - -#define AT91_SCKC_CR 0x00 -#define AT91_SCKC_RCEN (1 << 0) -#define AT91_SCKC_OSC32EN (1 << 1) -#define AT91_SCKC_OSC32BYP (1 << 2) -#define AT91_SCKC_OSCSEL (1 << 3) - -struct clk_slow_osc { - struct clk_hw hw; - void __iomem *sckcr; - unsigned long startup_usec; -}; - -#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw) - -struct clk_slow_rc_osc { - struct clk_hw hw; - void __iomem *sckcr; - unsigned long frequency; - unsigned long accuracy; - unsigned long startup_usec; -}; - -#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw) struct clk_sam9260_slow { struct clk_hw hw; @@ -57,340 +26,6 @@ struct clk_sam9260_slow { #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw) -struct clk_sam9x5_slow { - struct clk_hw hw; - void __iomem *sckcr; - u8 parent; -}; - -#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw) - -static int clk_slow_osc_prepare(struct clk_hw *hw) -{ - struct clk_slow_osc *osc = to_clk_slow_osc(hw); - void __iomem *sckcr = osc->sckcr; - u32 tmp = readl(sckcr); - - if (tmp & AT91_SCKC_OSC32BYP) - return 0; - - writel(tmp | AT91_SCKC_OSC32EN, sckcr); - - usleep_range(osc->startup_usec, osc->startup_usec + 1); - - return 0; -} - -static void clk_slow_osc_unprepare(struct clk_hw *hw) -{ - struct clk_slow_osc *osc = to_clk_slow_osc(hw); - void __iomem *sckcr = osc->sckcr; - u32 tmp = readl(sckcr); - - if (tmp & AT91_SCKC_OSC32BYP) - return; - - writel(tmp & ~AT91_SCKC_OSC32EN, sckcr); -} - -static int clk_slow_osc_is_prepared(struct clk_hw *hw) -{ - struct clk_slow_osc *osc = to_clk_slow_osc(hw); - void __iomem *sckcr = osc->sckcr; - u32 tmp = readl(sckcr); - - if (tmp & AT91_SCKC_OSC32BYP) - return 1; - - return !!(tmp & AT91_SCKC_OSC32EN); -} - -static const struct clk_ops slow_osc_ops = { - .prepare = clk_slow_osc_prepare, - .unprepare = clk_slow_osc_unprepare, - .is_prepared = clk_slow_osc_is_prepared, -}; - -static struct clk_hw * __init -at91_clk_register_slow_osc(void __iomem *sckcr, - const char *name, - const char *parent_name, - unsigned long startup, - bool bypass) -{ - struct clk_slow_osc *osc; - struct clk_hw *hw; - struct clk_init_data init; - int ret; - - if (!sckcr || !name || !parent_name) - return ERR_PTR(-EINVAL); - - osc = kzalloc(sizeof(*osc), GFP_KERNEL); - if (!osc) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &slow_osc_ops; - init.parent_names = &parent_name; - init.num_parents = 1; - init.flags = CLK_IGNORE_UNUSED; - - osc->hw.init = &init; - osc->sckcr = sckcr; - osc->startup_usec = startup; - - if (bypass) - writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, - sckcr); - - hw = &osc->hw; - ret = clk_hw_register(NULL, &osc->hw); - if (ret) { - kfree(osc); - hw = ERR_PTR(ret); - } - - return hw; -} - -void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, - void __iomem *sckcr) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - u32 startup; - bool bypass; - - parent_name = of_clk_get_parent_name(np, 0); - of_property_read_string(np, "clock-output-names", &name); - of_property_read_u32(np, "atmel,startup-time-usec", &startup); - bypass = of_property_read_bool(np, "atmel,osc-bypass"); - - hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, - bypass); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - -static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); - - return osc->frequency; -} - -static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw, - unsigned long parent_acc) -{ - struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); - - return osc->accuracy; -} - -static int clk_slow_rc_osc_prepare(struct clk_hw *hw) -{ - struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); - void __iomem *sckcr = osc->sckcr; - - writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr); - - usleep_range(osc->startup_usec, osc->startup_usec + 1); - - return 0; -} - -static void clk_slow_rc_osc_unprepare(struct clk_hw *hw) -{ - struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); - void __iomem *sckcr = osc->sckcr; - - writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr); -} - -static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw) -{ - struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); - - return !!(readl(osc->sckcr) & AT91_SCKC_RCEN); -} - -static const struct clk_ops slow_rc_osc_ops = { - .prepare = clk_slow_rc_osc_prepare, - .unprepare = clk_slow_rc_osc_unprepare, - .is_prepared = clk_slow_rc_osc_is_prepared, - .recalc_rate = clk_slow_rc_osc_recalc_rate, - .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy, -}; - -static struct clk_hw * __init -at91_clk_register_slow_rc_osc(void __iomem *sckcr, - const char *name, - unsigned long frequency, - unsigned long accuracy, - unsigned long startup) -{ - struct clk_slow_rc_osc *osc; - struct clk_hw *hw; - struct clk_init_data init; - int ret; - - if (!sckcr || !name) - return ERR_PTR(-EINVAL); - - osc = kzalloc(sizeof(*osc), GFP_KERNEL); - if (!osc) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &slow_rc_osc_ops; - init.parent_names = NULL; - init.num_parents = 0; - init.flags = CLK_IGNORE_UNUSED; - - osc->hw.init = &init; - osc->sckcr = sckcr; - osc->frequency = frequency; - osc->accuracy = accuracy; - osc->startup_usec = startup; - - hw = &osc->hw; - ret = clk_hw_register(NULL, &osc->hw); - if (ret) { - kfree(osc); - hw = ERR_PTR(ret); - } - - return hw; -} - -void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, - void __iomem *sckcr) -{ - struct clk_hw *hw; - u32 frequency = 0; - u32 accuracy = 0; - u32 startup = 0; - const char *name = np->name; - - of_property_read_string(np, "clock-output-names", &name); - of_property_read_u32(np, "clock-frequency", &frequency); - of_property_read_u32(np, "clock-accuracy", &accuracy); - of_property_read_u32(np, "atmel,startup-time-usec", &startup); - - hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, - startup); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - -static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); - void __iomem *sckcr = slowck->sckcr; - u32 tmp; - - if (index > 1) - return -EINVAL; - - tmp = readl(sckcr); - - if ((!index && !(tmp & AT91_SCKC_OSCSEL)) || - (index && (tmp & AT91_SCKC_OSCSEL))) - return 0; - - if (index) - tmp |= AT91_SCKC_OSCSEL; - else - tmp &= ~AT91_SCKC_OSCSEL; - - writel(tmp, sckcr); - - usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1); - - return 0; -} - -static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw) -{ - struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); - - return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL); -} - -static const struct clk_ops sam9x5_slow_ops = { - .set_parent = clk_sam9x5_slow_set_parent, - .get_parent = clk_sam9x5_slow_get_parent, -}; - -static struct clk_hw * __init -at91_clk_register_sam9x5_slow(void __iomem *sckcr, - const char *name, - const char **parent_names, - int num_parents) -{ - struct clk_sam9x5_slow *slowck; - struct clk_hw *hw; - struct clk_init_data init; - int ret; - - if (!sckcr || !name || !parent_names || !num_parents) - return ERR_PTR(-EINVAL); - - slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); - if (!slowck) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &sam9x5_slow_ops; - init.parent_names = parent_names; - init.num_parents = num_parents; - init.flags = 0; - - slowck->hw.init = &init; - slowck->sckcr = sckcr; - slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); - - hw = &slowck->hw; - ret = clk_hw_register(NULL, &slowck->hw); - if (ret) { - kfree(slowck); - hw = ERR_PTR(ret); - } - - return hw; -} - -void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, - void __iomem *sckcr) -{ - struct clk_hw *hw; - const char *parent_names[2]; - unsigned int num_parents; - const char *name = np->name; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > 2) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - of_property_read_string(np, "clock-output-names", &name); - - hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, - num_parents); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw) { struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw); diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 1184d76..311956a 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -12,11 +12,373 @@ #include #include +#include #include #include #include -#include "sckc.h" +#define SLOW_CLOCK_FREQ 32768 +#define SLOWCK_SW_CYCLES 5 +#define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \ + SLOW_CLOCK_FREQ) + +#define AT91_SCKC_CR 0x00 +#define AT91_SCKC_RCEN (1 << 0) +#define AT91_SCKC_OSC32EN (1 << 1) +#define AT91_SCKC_OSC32BYP (1 << 2) +#define AT91_SCKC_OSCSEL (1 << 3) + +struct clk_slow_osc { + struct clk_hw hw; + void __iomem *sckcr; + unsigned long startup_usec; +}; + +#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw) + +struct clk_slow_rc_osc { + struct clk_hw hw; + void __iomem *sckcr; + unsigned long frequency; + unsigned long accuracy; + unsigned long startup_usec; +}; + +#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw) + +struct clk_sam9x5_slow { + struct clk_hw hw; + void __iomem *sckcr; + u8 parent; +}; + +#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw) + +static int clk_slow_osc_prepare(struct clk_hw *hw) +{ + struct clk_slow_osc *osc = to_clk_slow_osc(hw); + void __iomem *sckcr = osc->sckcr; + u32 tmp = readl(sckcr); + + if (tmp & AT91_SCKC_OSC32BYP) + return 0; + + writel(tmp | AT91_SCKC_OSC32EN, sckcr); + + usleep_range(osc->startup_usec, osc->startup_usec + 1); + + return 0; +} + +static void clk_slow_osc_unprepare(struct clk_hw *hw) +{ + struct clk_slow_osc *osc = to_clk_slow_osc(hw); + void __iomem *sckcr = osc->sckcr; + u32 tmp = readl(sckcr); + + if (tmp & AT91_SCKC_OSC32BYP) + return; + + writel(tmp & ~AT91_SCKC_OSC32EN, sckcr); +} + +static int clk_slow_osc_is_prepared(struct clk_hw *hw) +{ + struct clk_slow_osc *osc = to_clk_slow_osc(hw); + void __iomem *sckcr = osc->sckcr; + u32 tmp = readl(sckcr); + + if (tmp & AT91_SCKC_OSC32BYP) + return 1; + + return !!(tmp & AT91_SCKC_OSC32EN); +} + +static const struct clk_ops slow_osc_ops = { + .prepare = clk_slow_osc_prepare, + .unprepare = clk_slow_osc_unprepare, + .is_prepared = clk_slow_osc_is_prepared, +}; + +static struct clk_hw * __init +at91_clk_register_slow_osc(void __iomem *sckcr, + const char *name, + const char *parent_name, + unsigned long startup, + bool bypass) +{ + struct clk_slow_osc *osc; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + if (!sckcr || !name || !parent_name) + return ERR_PTR(-EINVAL); + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); + if (!osc) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &slow_osc_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_IGNORE_UNUSED; + + osc->hw.init = &init; + osc->sckcr = sckcr; + osc->startup_usec = startup; + + if (bypass) + writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, + sckcr); + + hw = &osc->hw; + ret = clk_hw_register(NULL, &osc->hw); + if (ret) { + kfree(osc); + hw = ERR_PTR(ret); + } + + return hw; +} + +static void __init +of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr) +{ + struct clk_hw *hw; + const char *parent_name; + const char *name = np->name; + u32 startup; + bool bypass; + + parent_name = of_clk_get_parent_name(np, 0); + of_property_read_string(np, "clock-output-names", &name); + of_property_read_u32(np, "atmel,startup-time-usec", &startup); + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, + bypass); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} + +static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); + + return osc->frequency; +} + +static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw, + unsigned long parent_acc) +{ + struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); + + return osc->accuracy; +} + +static int clk_slow_rc_osc_prepare(struct clk_hw *hw) +{ + struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); + void __iomem *sckcr = osc->sckcr; + + writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr); + + usleep_range(osc->startup_usec, osc->startup_usec + 1); + + return 0; +} + +static void clk_slow_rc_osc_unprepare(struct clk_hw *hw) +{ + struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); + void __iomem *sckcr = osc->sckcr; + + writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr); +} + +static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw) +{ + struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); + + return !!(readl(osc->sckcr) & AT91_SCKC_RCEN); +} + +static const struct clk_ops slow_rc_osc_ops = { + .prepare = clk_slow_rc_osc_prepare, + .unprepare = clk_slow_rc_osc_unprepare, + .is_prepared = clk_slow_rc_osc_is_prepared, + .recalc_rate = clk_slow_rc_osc_recalc_rate, + .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy, +}; + +static struct clk_hw * __init +at91_clk_register_slow_rc_osc(void __iomem *sckcr, + const char *name, + unsigned long frequency, + unsigned long accuracy, + unsigned long startup) +{ + struct clk_slow_rc_osc *osc; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + if (!sckcr || !name) + return ERR_PTR(-EINVAL); + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); + if (!osc) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &slow_rc_osc_ops; + init.parent_names = NULL; + init.num_parents = 0; + init.flags = CLK_IGNORE_UNUSED; + + osc->hw.init = &init; + osc->sckcr = sckcr; + osc->frequency = frequency; + osc->accuracy = accuracy; + osc->startup_usec = startup; + + hw = &osc->hw; + ret = clk_hw_register(NULL, &osc->hw); + if (ret) { + kfree(osc); + hw = ERR_PTR(ret); + } + + return hw; +} + +static void __init +of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr) +{ + struct clk_hw *hw; + u32 frequency = 0; + u32 accuracy = 0; + u32 startup = 0; + const char *name = np->name; + + of_property_read_string(np, "clock-output-names", &name); + of_property_read_u32(np, "clock-frequency", &frequency); + of_property_read_u32(np, "clock-accuracy", &accuracy); + of_property_read_u32(np, "atmel,startup-time-usec", &startup); + + hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, + startup); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} + +static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); + void __iomem *sckcr = slowck->sckcr; + u32 tmp; + + if (index > 1) + return -EINVAL; + + tmp = readl(sckcr); + + if ((!index && !(tmp & AT91_SCKC_OSCSEL)) || + (index && (tmp & AT91_SCKC_OSCSEL))) + return 0; + + if (index) + tmp |= AT91_SCKC_OSCSEL; + else + tmp &= ~AT91_SCKC_OSCSEL; + + writel(tmp, sckcr); + + usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1); + + return 0; +} + +static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw) +{ + struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); + + return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL); +} + +static const struct clk_ops sam9x5_slow_ops = { + .set_parent = clk_sam9x5_slow_set_parent, + .get_parent = clk_sam9x5_slow_get_parent, +}; + +static struct clk_hw * __init +at91_clk_register_sam9x5_slow(void __iomem *sckcr, + const char *name, + const char **parent_names, + int num_parents) +{ + struct clk_sam9x5_slow *slowck; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + if (!sckcr || !name || !parent_names || !num_parents) + return ERR_PTR(-EINVAL); + + slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); + if (!slowck) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &sam9x5_slow_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.flags = 0; + + slowck->hw.init = &init; + slowck->sckcr = sckcr; + slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); + + hw = &slowck->hw; + ret = clk_hw_register(NULL, &slowck->hw); + if (ret) { + kfree(slowck); + hw = ERR_PTR(ret); + } + + return hw; +} + +static void __init +of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr) +{ + struct clk_hw *hw; + const char *parent_names[2]; + unsigned int num_parents; + const char *name = np->name; + + num_parents = of_clk_get_parent_count(np); + if (num_parents == 0 || num_parents > 2) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + + of_property_read_string(np, "clock-output-names", &name); + + hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, + num_parents); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} static const struct of_device_id sckc_clk_ids[] __initconst = { /* Slow clock */ diff --git a/drivers/clk/at91/sckc.h b/drivers/clk/at91/sckc.h deleted file mode 100644 index 836fcf5..0000000 --- a/drivers/clk/at91/sckc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * drivers/clk/at91/sckc.h - * - * Copyright (C) 2013 Boris BREZILLON - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __AT91_SCKC_H_ -#define __AT91_SCKC_H_ - -extern void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, - void __iomem *sckcr); -extern void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, - void __iomem *sckcr); -extern void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, - void __iomem *sckcr); - -#endif /* __AT91_SCKC_H_ */ -- cgit v0.10.2 From 4b13b6451a9dce278881d236d33d4bb0cb28592b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 20 Sep 2016 22:58:30 +0200 Subject: clk: at91: Add sama5d4 sckc support Starting with sama5d4, the crystal oscillator is always enabled at startup and the SCKC doesn't have an OSC32EN bit anymore. Add support for that new controller. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index 181bc8a..5f3ad65 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -6,7 +6,8 @@ This binding uses the common clock binding[1]. Required properties: - compatible : shall be one of the following: - "atmel,at91sam9x5-sckc": + "atmel,at91sam9x5-sckc" or + "atmel,sama5d4-sckc": at91 SCKC (Slow Clock Controller) This node contains the slow clock definitions. diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 311956a..199d1b3 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -36,6 +36,15 @@ struct clk_slow_osc { #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw) +struct clk_sama5d4_slow_osc { + struct clk_hw hw; + void __iomem *sckcr; + unsigned long startup_usec; + bool prepared; +}; + +#define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw) + struct clk_slow_rc_osc { struct clk_hw hw; void __iomem *sckcr; @@ -417,3 +426,94 @@ static void __init of_at91sam9x5_sckc_setup(struct device_node *np) } CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", of_at91sam9x5_sckc_setup); + +static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) +{ + struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); + + if (osc->prepared) + return 0; + + /* + * Assume that if it has already been selected (for example by the + * bootloader), enough time has aready passed. + */ + if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) { + osc->prepared = true; + return 0; + } + + usleep_range(osc->startup_usec, osc->startup_usec + 1); + osc->prepared = true; + + return 0; +} + +static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw) +{ + struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); + + return osc->prepared; +} + +static const struct clk_ops sama5d4_slow_osc_ops = { + .prepare = clk_sama5d4_slow_osc_prepare, + .is_prepared = clk_sama5d4_slow_osc_is_prepared, +}; + +static void __init of_sama5d4_sckc_setup(struct device_node *np) +{ + void __iomem *regbase = of_iomap(np, 0); + struct clk_hw *hw; + struct clk_sama5d4_slow_osc *osc; + struct clk_init_data init; + const char *xtal_name; + const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; + bool bypass; + int ret; + + if (!regbase) + return; + + hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0], + NULL, 0, 32768, + 250000000); + if (IS_ERR(hw)) + return; + + xtal_name = of_clk_get_parent_name(np, 0); + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); + if (!osc) + return; + + init.name = parent_names[1]; + init.ops = &sama5d4_slow_osc_ops; + init.parent_names = &xtal_name; + init.num_parents = 1; + init.flags = CLK_IGNORE_UNUSED; + + osc->hw.init = &init; + osc->sckcr = regbase; + osc->startup_usec = 1200000; + + if (bypass) + writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase); + + hw = &osc->hw; + ret = clk_hw_register(NULL, &osc->hw); + if (ret) { + kfree(osc); + return; + } + + hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc", + of_sama5d4_sckc_setup); -- cgit v0.10.2 From 4135b7f8d42180d6d9820b53b0ab5e3377b7c364 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 20 Sep 2016 22:58:31 +0200 Subject: clk: at91: sckc: optimize boot time Assume that if the oscillator is enabled (OSC32EN bit is present), the delay has already elapsed as the bootloader probably waited for the oscillator to settle. This could waste up to 1.2s. Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 199d1b3..ab6ecef 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -69,7 +69,7 @@ static int clk_slow_osc_prepare(struct clk_hw *hw) void __iomem *sckcr = osc->sckcr; u32 tmp = readl(sckcr); - if (tmp & AT91_SCKC_OSC32BYP) + if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN)) return 0; writel(tmp | AT91_SCKC_OSC32EN, sckcr); -- cgit v0.10.2 From 5519cf23ad548c3991ce9ce5c44dba963d11fe85 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Sep 2016 22:00:15 +0200 Subject: clk: sunxi-ng: Fix reset offset for the A23 and A33 There's been a copy and paste mistake in the A23 and A33 from the H3, leading in the reset offset for the UART and I2C. Signed-off-by: Maxime Ripard Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index 11e624a..2646d98 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -689,14 +689,14 @@ static struct ccu_reset_map sun8i_a23_ccu_resets[] = { [RST_BUS_I2S0] = { 0x2d0, BIT(12) }, [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, - [RST_BUS_I2C0] = { 0x2d4, BIT(0) }, - [RST_BUS_I2C1] = { 0x2d4, BIT(1) }, - [RST_BUS_I2C2] = { 0x2d4, BIT(2) }, - [RST_BUS_UART0] = { 0x2d4, BIT(16) }, - [RST_BUS_UART1] = { 0x2d4, BIT(17) }, - [RST_BUS_UART2] = { 0x2d4, BIT(18) }, - [RST_BUS_UART3] = { 0x2d4, BIT(19) }, - [RST_BUS_UART4] = { 0x2d4, BIT(20) }, + [RST_BUS_I2C0] = { 0x2d8, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d8, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d8, BIT(2) }, + [RST_BUS_UART0] = { 0x2d8, BIT(16) }, + [RST_BUS_UART1] = { 0x2d8, BIT(17) }, + [RST_BUS_UART2] = { 0x2d8, BIT(18) }, + [RST_BUS_UART3] = { 0x2d8, BIT(19) }, + [RST_BUS_UART4] = { 0x2d8, BIT(20) }, }; static const struct sunxi_ccu_desc sun8i_a23_ccu_desc = { diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c index fc00892..96b40ca 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -732,14 +732,14 @@ static struct ccu_reset_map sun8i_a33_ccu_resets[] = { [RST_BUS_I2S0] = { 0x2d0, BIT(12) }, [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, - [RST_BUS_I2C0] = { 0x2d4, BIT(0) }, - [RST_BUS_I2C1] = { 0x2d4, BIT(1) }, - [RST_BUS_I2C2] = { 0x2d4, BIT(2) }, - [RST_BUS_UART0] = { 0x2d4, BIT(16) }, - [RST_BUS_UART1] = { 0x2d4, BIT(17) }, - [RST_BUS_UART2] = { 0x2d4, BIT(18) }, - [RST_BUS_UART3] = { 0x2d4, BIT(19) }, - [RST_BUS_UART4] = { 0x2d4, BIT(20) }, + [RST_BUS_I2C0] = { 0x2d8, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d8, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d8, BIT(2) }, + [RST_BUS_UART0] = { 0x2d8, BIT(16) }, + [RST_BUS_UART1] = { 0x2d8, BIT(17) }, + [RST_BUS_UART2] = { 0x2d8, BIT(18) }, + [RST_BUS_UART3] = { 0x2d8, BIT(19) }, + [RST_BUS_UART4] = { 0x2d8, BIT(20) }, }; static const struct sunxi_ccu_desc sun8i_a33_ccu_desc = { -- cgit v0.10.2 From af9083627b4764272a341902e37af17188bc17f0 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 20 Sep 2016 14:00:42 +0530 Subject: clk: mediatek: clk-mt8173: Unmap region obtained by of_iomap Free memory mapping if init is not successful. Signed-off-by: Arvind Yadav Reviewed-by: James Liao Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c index 10c9860..0ac3aee 100644 --- a/drivers/clk/mediatek/clk-mt8173.c +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -1074,8 +1074,10 @@ static void __init mtk_apmixedsys_init(struct device_node *node) } mt8173_pll_clk_data = clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); - if (!clk_data) + if (!clk_data) { + iounmap(base); return; + } mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); -- cgit v0.10.2 From 41d88559c31bfd2a7e5dd105362f0e39f810401c Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 20 Sep 2016 16:24:06 +0530 Subject: clk: nxp: clk-lpc32xx: Unmap region obtained by of_iomap Free memory mapping, if lpc32xx_clk_init is not successful. Signed-off-by: Arvind Yadav Acked-by: Vladimir Zapolskiy Acked-by: Sylvain Lemieux Signed-off-by: Stephen Boyd diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index 90d740a..34c9735 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -1513,6 +1513,7 @@ static void __init lpc32xx_clk_init(struct device_node *np) if (IS_ERR(clk_regmap)) { pr_err("failed to regmap system control block: %ld\n", PTR_ERR(clk_regmap)); + iounmap(base); return; } -- cgit v0.10.2 From ad715b268a501533ecb2e891a624841d1bb5137c Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Wed, 21 Sep 2016 11:05:57 +0200 Subject: clk: mvebu: fix setting unwanted flags in CP110 gate clock Armada CP110 system controller comprises its own routine responsble for registering gate clocks. Among others 'flags' field in struct clk_init_data was not set, using a random values, which may cause an unpredicted behavior. This patch fixes the problem by resetting all fields of clk_init_data before assigning values for all gated clocks of Armada 7k/8k SoCs family. Fixes: d3da3eaef7f4 ("clk: mvebu: new driver for Armada CP110 system ...") Signed-off-by: Marcin Wojtas CC: Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index 7fa42d6..59fe76e 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -142,6 +142,8 @@ static struct clk *cp110_register_gate(const char *name, if (!gate) return ERR_PTR(-ENOMEM); + memset(&init, 0, sizeof(init)); + init.name = name; init.ops = &cp110_gate_ops; init.parent_names = &parent_name; -- cgit v0.10.2 From a0245eb76ad0f652f1eb14f48ca2d3c4391aef66 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Wed, 21 Sep 2016 11:05:58 +0200 Subject: clk: mvebu: dynamically allocate resources in Armada CP110 system controller Original commit, which added support for Armada CP110 system controller used global variables for storing all clock information. It worked fine for Armada 7k SoC, with single CP110 block. After dual-CP110 Armada 8k was introduced, the data got overwritten and corrupted. This patch fixes the issue by allocating resources dynamically in the driver probe and storing it as platform drvdata. Fixes: d3da3eaef7f4 ("clk: mvebu: new driver for Armada CP110 system ...") Signed-off-by: Marcin Wojtas Reviewed-by: Thomas Petazzoni CC: Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index 59fe76e..f2303da 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -81,13 +81,6 @@ enum { #define CP110_GATE_EIP150 25 #define CP110_GATE_EIP197 26 -static struct clk *cp110_clks[CP110_CLK_NUM]; - -static struct clk_onecell_data cp110_clk_data = { - .clks = cp110_clks, - .clk_num = CP110_CLK_NUM, -}; - struct cp110_gate_clk { struct clk_hw hw; struct regmap *regmap; @@ -196,7 +189,8 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) struct regmap *regmap; struct device_node *np = pdev->dev.of_node; const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name; - struct clk *clk; + struct clk_onecell_data *cp110_clk_data; + struct clk *clk, **cp110_clks; u32 nand_clk_ctrl; int i, ret; @@ -209,6 +203,20 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) if (ret) return ret; + cp110_clks = devm_kcalloc(&pdev->dev, sizeof(struct clk *), + CP110_CLK_NUM, GFP_KERNEL); + if (!cp110_clks) + return -ENOMEM; + + cp110_clk_data = devm_kzalloc(&pdev->dev, + sizeof(*cp110_clk_data), + GFP_KERNEL); + if (!cp110_clk_data) + return -ENOMEM; + + cp110_clk_data->clks = cp110_clks; + cp110_clk_data->clk_num = CP110_CLK_NUM; + /* Register the APLL which is the root of the clk tree */ of_property_read_string_index(np, "core-clock-output-names", CP110_CORE_APLL, &apll_name); @@ -336,10 +344,12 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) cp110_clks[CP110_MAX_CORE_CLOCKS + i] = clk; } - ret = of_clk_add_provider(np, cp110_of_clk_get, &cp110_clk_data); + ret = of_clk_add_provider(np, cp110_of_clk_get, cp110_clk_data); if (ret) goto fail_clk_add; + platform_set_drvdata(pdev, cp110_clks); + return 0; fail_clk_add: @@ -366,6 +376,7 @@ fail0: static int cp110_syscon_clk_remove(struct platform_device *pdev) { + struct clk **cp110_clks = platform_get_drvdata(pdev); int i; of_clk_del_provider(pdev->dev.of_node); -- cgit v0.10.2 From c72f2883c31e8c21832f3d48d5aa6ee8d83b3c43 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 23 Sep 2016 09:45:08 +0800 Subject: clk: zx296718: register driver earlier with core_initcall Clock driver should be registered with an earlier initcall than module_init which is used by most of client device drivers. Otherwise, probing of these client drivers will likely be deferred due to that calls into clk API will return -EPROBE_DEFER. Deferred probing is not a problem for most subsystems, but could bring some side effect for particular subsystem, like display. On ZX296718 platform, we get Linux logo and boot log lost from display device, just because the DRM/KMS driver gets -EPROBE_DEFER from devm_clk_get() call. Let's use core_initcall (qcom and a few other clk drivers use that) for driver registration to avoid those unnecessary -EPROBE_DEFER and get rid of the side effect with ZX296718 display system. Signed-off-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c index c7716c1..707d629 100644 --- a/drivers/clk/zte/clk-zx296718.c +++ b/drivers/clk/zte/clk-zx296718.c @@ -917,4 +917,8 @@ static struct platform_driver zx_clk_driver = { }, }; -builtin_platform_driver(zx_clk_driver); +static int __init zx_clk_init(void) +{ + return platform_driver_register(&zx_clk_driver); +} +core_initcall(zx_clk_init); -- cgit v0.10.2 From 5963f19ca2b7e46cafc9647c8390bb20563b91cc Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 23 Sep 2016 21:29:36 +0900 Subject: clk: change the type of clk_hw_onecell_data.num to unsigned int The "num" is the number of clk_hw entries in the structure, so "unsigned int" would be a better fit. (size_t looks like data size we count by byte.) Besides, struct clk_onecell_data already uses unsigned int for "clk_num". Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 37b8fdc..af59638 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -772,7 +772,7 @@ struct clk_onecell_data { }; struct clk_hw_onecell_data { - size_t num; + unsigned int num; struct clk_hw *hws[]; }; -- cgit v0.10.2 From a8e3ced421c1cd24221543a2bfda3134d46a6f21 Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Mon, 19 Sep 2016 12:38:54 +0800 Subject: clk: Loongson1: Refactor Loongson1 clock Factor out the common functions into loongson1/clk.c to support both Loongson1B and Loongson1C. And, put the rest into loongson1/clk-loongson1b.c. Signed-off-by: Kelvin Cheung Signed-off-by: Stephen Boyd diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 8264d81..925081e 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -26,7 +26,6 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o -obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o @@ -61,6 +60,7 @@ obj-$(CONFIG_ARCH_HISI) += hisilicon/ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_MACH_INGENIC) += ingenic/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ +obj-$(CONFIG_MACH_LOONGSON32) += loongson1/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/ obj-$(CONFIG_MACH_PIC32) += microchip/ diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c deleted file mode 100644 index 8430e45..0000000 --- a/drivers/clk/clk-ls1x.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2012 Zhang, Keguang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include - -#include - -#define OSC (33 * 1000000) -#define DIV_APB 2 - -static DEFINE_SPINLOCK(_lock); - -static int ls1x_pll_clk_enable(struct clk_hw *hw) -{ - return 0; -} - -static void ls1x_pll_clk_disable(struct clk_hw *hw) -{ -} - -static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - u32 pll, rate; - - pll = __raw_readl(LS1X_CLK_PLL_FREQ); - rate = 12 + (pll & 0x3f) + (((pll >> 8) & 0x3ff) >> 10); - rate *= OSC; - rate >>= 1; - - return rate; -} - -static const struct clk_ops ls1x_pll_clk_ops = { - .enable = ls1x_pll_clk_enable, - .disable = ls1x_pll_clk_disable, - .recalc_rate = ls1x_pll_recalc_rate, -}; - -static struct clk_hw *__init clk_hw_register_pll(struct device *dev, - const char *name, - const char *parent_name, - unsigned long flags) -{ - int ret; - struct clk_hw *hw; - struct clk_init_data init; - - /* allocate the divider */ - hw = kzalloc(sizeof(struct clk_hw), GFP_KERNEL); - if (!hw) { - pr_err("%s: could not allocate clk_hw\n", __func__); - return ERR_PTR(-ENOMEM); - } - - init.name = name; - init.ops = &ls1x_pll_clk_ops; - init.flags = flags | CLK_IS_BASIC; - init.parent_names = (parent_name ? &parent_name : NULL); - init.num_parents = (parent_name ? 1 : 0); - hw->init = &init; - - /* register the clock */ - ret = clk_hw_register(dev, hw); - if (ret) { - kfree(hw); - hw = ERR_PTR(ret); - } - - return hw; -} - -static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; -static const char * const ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", }; -static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; - -void __init ls1x_clk_init(void) -{ - struct clk_hw *hw; - - hw = clk_hw_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); - clk_hw_register_clkdev(hw, "osc_33m_clk", NULL); - - /* clock derived from 33 MHz OSC clk */ - hw = clk_hw_register_pll(NULL, "pll_clk", "osc_33m_clk", 0); - clk_hw_register_clkdev(hw, "pll_clk", NULL); - - /* clock derived from PLL clk */ - /* _____ - * _______________________| | - * OSC ___/ | MUX |___ CPU CLK - * \___ PLL ___ CPU DIV ___| | - * |_____| - */ - hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", - CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, - DIV_CPU_SHIFT, DIV_CPU_WIDTH, - CLK_DIVIDER_ONE_BASED | - CLK_DIVIDER_ROUND_CLOSEST, &_lock); - clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); - hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, - ARRAY_SIZE(cpu_parents), - CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, - BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); - clk_hw_register_clkdev(hw, "cpu_clk", NULL); - - /* _____ - * _______________________| | - * OSC ___/ | MUX |___ DC CLK - * \___ PLL ___ DC DIV ___| | - * |_____| - */ - hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", - 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, - DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_hw_register_clkdev(hw, "dc_clk_div", NULL); - hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, - ARRAY_SIZE(dc_parents), - CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, - BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); - clk_hw_register_clkdev(hw, "dc_clk", NULL); - - /* _____ - * _______________________| | - * OSC ___/ | MUX |___ DDR CLK - * \___ PLL ___ DDR DIV ___| | - * |_____| - */ - hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", - 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, - DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, - &_lock); - clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); - hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, - ARRAY_SIZE(ahb_parents), - CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, - BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); - clk_hw_register_clkdev(hw, "ahb_clk", NULL); - clk_hw_register_clkdev(hw, "stmmaceth", NULL); - - /* clock derived from AHB clk */ - /* APB clk is always half of the AHB clk */ - hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, - DIV_APB); - clk_hw_register_clkdev(hw, "apb_clk", NULL); - clk_hw_register_clkdev(hw, "ls1x_i2c", NULL); - clk_hw_register_clkdev(hw, "ls1x_pwmtimer", NULL); - clk_hw_register_clkdev(hw, "ls1x_spi", NULL); - clk_hw_register_clkdev(hw, "ls1x_wdt", NULL); - clk_hw_register_clkdev(hw, "serial8250", NULL); -} diff --git a/drivers/clk/loongson1/Makefile b/drivers/clk/loongson1/Makefile new file mode 100644 index 0000000..5a162a1 --- /dev/null +++ b/drivers/clk/loongson1/Makefile @@ -0,0 +1,2 @@ +obj-y += clk.o +obj-$(CONFIG_LOONGSON1_LS1B) += clk-loongson1b.o diff --git a/drivers/clk/loongson1/clk-loongson1b.c b/drivers/clk/loongson1/clk-loongson1b.c new file mode 100644 index 0000000..5b6817e --- /dev/null +++ b/drivers/clk/loongson1/clk-loongson1b.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012-2016 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +#include +#include "clk.h" + +#define OSC (33 * 1000000) +#define DIV_APB 2 + +static DEFINE_SPINLOCK(_lock); + +static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 pll, rate; + + pll = __raw_readl(LS1X_CLK_PLL_FREQ); + rate = 12 + (pll & 0x3f) + (((pll >> 8) & 0x3ff) >> 10); + rate *= OSC; + rate >>= 1; + + return rate; +} + +static const struct clk_ops ls1x_pll_clk_ops = { + .recalc_rate = ls1x_pll_recalc_rate, +}; + +static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; +static const char * const ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", }; +static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; + +void __init ls1x_clk_init(void) +{ + struct clk_hw *hw; + + hw = clk_hw_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); + clk_hw_register_clkdev(hw, "osc_33m_clk", NULL); + + /* clock derived from 33 MHz OSC clk */ + hw = clk_hw_register_pll(NULL, "pll_clk", "osc_33m_clk", + &ls1x_pll_clk_ops, 0); + clk_hw_register_clkdev(hw, "pll_clk", NULL); + + /* clock derived from PLL clk */ + /* _____ + * _______________________| | + * OSC ___/ | MUX |___ CPU CLK + * \___ PLL ___ CPU DIV ___| | + * |_____| + */ + hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", + CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, + DIV_CPU_SHIFT, DIV_CPU_WIDTH, + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ROUND_CLOSEST, &_lock); + clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, + ARRAY_SIZE(cpu_parents), + CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, + BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); + clk_hw_register_clkdev(hw, "cpu_clk", NULL); + + /* _____ + * _______________________| | + * OSC ___/ | MUX |___ DC CLK + * \___ PLL ___ DC DIV ___| | + * |_____| + */ + hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", + 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, + DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); + clk_hw_register_clkdev(hw, "dc_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, + ARRAY_SIZE(dc_parents), + CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, + BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); + clk_hw_register_clkdev(hw, "dc_clk", NULL); + + /* _____ + * _______________________| | + * OSC ___/ | MUX |___ DDR CLK + * \___ PLL ___ DDR DIV ___| | + * |_____| + */ + hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", + 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, + DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, + &_lock); + clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); + hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, + ARRAY_SIZE(ahb_parents), + CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, + BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); + clk_hw_register_clkdev(hw, "ahb_clk", NULL); + clk_hw_register_clkdev(hw, "stmmaceth", NULL); + + /* clock derived from AHB clk */ + /* APB clk is always half of the AHB clk */ + hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, + DIV_APB); + clk_hw_register_clkdev(hw, "apb_clk", NULL); + clk_hw_register_clkdev(hw, "ls1x_i2c", NULL); + clk_hw_register_clkdev(hw, "ls1x_pwmtimer", NULL); + clk_hw_register_clkdev(hw, "ls1x_spi", NULL); + clk_hw_register_clkdev(hw, "ls1x_wdt", NULL); + clk_hw_register_clkdev(hw, "serial8250", NULL); +} diff --git a/drivers/clk/loongson1/clk.c b/drivers/clk/loongson1/clk.c new file mode 100644 index 0000000..cfcfd14 --- /dev/null +++ b/drivers/clk/loongson1/clk.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012-2016 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include + +struct clk_hw *__init clk_hw_register_pll(struct device *dev, + const char *name, + const char *parent_name, + const struct clk_ops *ops, + unsigned long flags) +{ + int ret; + struct clk_hw *hw; + struct clk_init_data init; + + /* allocate the divider */ + hw = kzalloc(sizeof(*hw), GFP_KERNEL); + if (!hw) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + hw->init = &init; + + /* register the clock */ + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(hw); + hw = ERR_PTR(ret); + } + + return hw; +} diff --git a/drivers/clk/loongson1/clk.h b/drivers/clk/loongson1/clk.h new file mode 100644 index 0000000..085d74b --- /dev/null +++ b/drivers/clk/loongson1/clk.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2012-2016 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __LOONGSON1_CLK_H +#define __LOONGSON1_CLK_H + +struct clk_hw *clk_hw_register_pll(struct device *dev, + const char *name, + const char *parent_name, + const struct clk_ops *ops, + unsigned long flags); + +#endif /* __LOONGSON1_CLK_H */ -- cgit v0.10.2 From c99c7a9ac6756964b0ffa508b9b4f55b5be7d12b Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Mon, 19 Sep 2016 12:38:55 +0800 Subject: clk: Loongson1: Update clocks of Loongson1B This patch updates some clock names of Loongson1B, and adds AC97, DMA and NAND clock. Signed-off-by: Kelvin Cheung Signed-off-by: Stephen Boyd diff --git a/drivers/clk/loongson1/clk-loongson1b.c b/drivers/clk/loongson1/clk-loongson1b.c index 5b6817e..4b3d9d2 100644 --- a/drivers/clk/loongson1/clk-loongson1b.c +++ b/drivers/clk/loongson1/clk-loongson1b.c @@ -37,19 +37,19 @@ static const struct clk_ops ls1x_pll_clk_ops = { .recalc_rate = ls1x_pll_recalc_rate, }; -static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; -static const char * const ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", }; -static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; +static const char *const cpu_parents[] = { "cpu_clk_div", "osc_clk", }; +static const char *const ahb_parents[] = { "ahb_clk_div", "osc_clk", }; +static const char *const dc_parents[] = { "dc_clk_div", "osc_clk", }; void __init ls1x_clk_init(void) { struct clk_hw *hw; - hw = clk_hw_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC); - clk_hw_register_clkdev(hw, "osc_33m_clk", NULL); + hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); + clk_hw_register_clkdev(hw, "osc_clk", NULL); /* clock derived from 33 MHz OSC clk */ - hw = clk_hw_register_pll(NULL, "pll_clk", "osc_33m_clk", + hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", &ls1x_pll_clk_ops, 0); clk_hw_register_clkdev(hw, "pll_clk", NULL); @@ -104,6 +104,7 @@ void __init ls1x_clk_init(void) CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); clk_hw_register_clkdev(hw, "ahb_clk", NULL); + clk_hw_register_clkdev(hw, "ls1x-dma", NULL); clk_hw_register_clkdev(hw, "stmmaceth", NULL); /* clock derived from AHB clk */ @@ -111,9 +112,11 @@ void __init ls1x_clk_init(void) hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, DIV_APB); clk_hw_register_clkdev(hw, "apb_clk", NULL); - clk_hw_register_clkdev(hw, "ls1x_i2c", NULL); - clk_hw_register_clkdev(hw, "ls1x_pwmtimer", NULL); - clk_hw_register_clkdev(hw, "ls1x_spi", NULL); - clk_hw_register_clkdev(hw, "ls1x_wdt", NULL); + clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); + clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); + clk_hw_register_clkdev(hw, "ls1x-nand", NULL); + clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); + clk_hw_register_clkdev(hw, "ls1x-spi", NULL); + clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); clk_hw_register_clkdev(hw, "serial8250", NULL); } -- cgit v0.10.2 From f0ffaf187addb5dcab76885fff9314b716fc8072 Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Mon, 19 Sep 2016 12:38:56 +0800 Subject: clk: Loongson1: Make use of GENMASK Make use of GENMASK instead of open coding the equivalent operation, and update the PLL formula. Signed-off-by: Kelvin Cheung Signed-off-by: Stephen Boyd diff --git a/drivers/clk/loongson1/clk-loongson1b.c b/drivers/clk/loongson1/clk-loongson1b.c index 4b3d9d2..f36a97e 100644 --- a/drivers/clk/loongson1/clk-loongson1b.c +++ b/drivers/clk/loongson1/clk-loongson1b.c @@ -26,7 +26,7 @@ static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, u32 pll, rate; pll = __raw_readl(LS1X_CLK_PLL_FREQ); - rate = 12 + (pll & 0x3f) + (((pll >> 8) & 0x3ff) >> 10); + rate = 12 + (pll & GENMASK(5, 0)); rate *= OSC; rate >>= 1; -- cgit v0.10.2 From b4626a7f489238a59f08f0b216e883bac07260d7 Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Tue, 20 Sep 2016 23:54:56 +0800 Subject: CLK: Add Loongson1C clock support This patch adds clock support to Loongson1C SoC. Signed-off-by: Yang Ling Acked-by: Keguang Zhang Signed-off-by: Stephen Boyd diff --git a/drivers/clk/loongson1/Makefile b/drivers/clk/loongson1/Makefile index 5a162a1..b7f6a16 100644 --- a/drivers/clk/loongson1/Makefile +++ b/drivers/clk/loongson1/Makefile @@ -1,2 +1,3 @@ obj-y += clk.o obj-$(CONFIG_LOONGSON1_LS1B) += clk-loongson1b.o +obj-$(CONFIG_LOONGSON1_LS1C) += clk-loongson1c.o diff --git a/drivers/clk/loongson1/clk-loongson1c.c b/drivers/clk/loongson1/clk-loongson1c.c new file mode 100644 index 0000000..3466f73 --- /dev/null +++ b/drivers/clk/loongson1/clk-loongson1c.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016 Yang Ling + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include + +#include +#include "clk.h" + +#define OSC (24 * 1000000) +#define DIV_APB 1 + +static DEFINE_SPINLOCK(_lock); + +static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 pll, rate; + + pll = __raw_readl(LS1X_CLK_PLL_FREQ); + rate = ((pll >> 8) & 0xff) + ((pll >> 16) & 0xff); + rate *= OSC; + rate >>= 2; + + return rate; +} + +static const struct clk_ops ls1x_pll_clk_ops = { + .recalc_rate = ls1x_pll_recalc_rate, +}; + +static const struct clk_div_table ahb_div_table[] = { + [0] = { .val = 0, .div = 2 }, + [1] = { .val = 1, .div = 4 }, + [2] = { .val = 2, .div = 3 }, + [3] = { .val = 3, .div = 3 }, +}; + +void __init ls1x_clk_init(void) +{ + struct clk_hw *hw; + + hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); + clk_hw_register_clkdev(hw, "osc_clk", NULL); + + /* clock derived from 24 MHz OSC clk */ + hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", + &ls1x_pll_clk_ops, 0); + clk_hw_register_clkdev(hw, "pll_clk", NULL); + + hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", + CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, + DIV_CPU_SHIFT, DIV_CPU_WIDTH, + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ROUND_CLOSEST, &_lock); + clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); + hw = clk_hw_register_fixed_factor(NULL, "cpu_clk", "cpu_clk_div", + 0, 1, 1); + clk_hw_register_clkdev(hw, "cpu_clk", NULL); + + hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", + 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, + DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); + clk_hw_register_clkdev(hw, "dc_clk_div", NULL); + hw = clk_hw_register_fixed_factor(NULL, "dc_clk", "dc_clk_div", + 0, 1, 1); + clk_hw_register_clkdev(hw, "dc_clk", NULL); + + hw = clk_hw_register_divider_table(NULL, "ahb_clk_div", "cpu_clk_div", + 0, LS1X_CLK_PLL_FREQ, DIV_DDR_SHIFT, + DIV_DDR_WIDTH, CLK_DIVIDER_ALLOW_ZERO, + ahb_div_table, &_lock); + clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); + hw = clk_hw_register_fixed_factor(NULL, "ahb_clk", "ahb_clk_div", + 0, 1, 1); + clk_hw_register_clkdev(hw, "ahb_clk", NULL); + clk_hw_register_clkdev(hw, "ls1x-dma", NULL); + clk_hw_register_clkdev(hw, "stmmaceth", NULL); + + /* clock derived from AHB clk */ + hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, + DIV_APB); + clk_hw_register_clkdev(hw, "apb_clk", NULL); + clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); + clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); + clk_hw_register_clkdev(hw, "ls1x-nand", NULL); + clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); + clk_hw_register_clkdev(hw, "ls1x-spi", NULL); + clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); + clk_hw_register_clkdev(hw, "serial8250", NULL); +} -- cgit v0.10.2