1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * OMAP gate clock support
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2013 Texas Instruments, Inc.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Tero Kristo <t-kristo@ti.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
9*4882a593Smuzhiyun * it under the terms of the GNU General Public License version 2 as
10*4882a593Smuzhiyun * published by the Free Software Foundation.
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * This program is distributed "as is" WITHOUT ANY WARRANTY of any
13*4882a593Smuzhiyun * kind, whether express or implied; without even the implied warranty
14*4882a593Smuzhiyun * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*4882a593Smuzhiyun * GNU General Public License for more details.
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/clk-provider.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/io.h>
21*4882a593Smuzhiyun #include <linux/of.h>
22*4882a593Smuzhiyun #include <linux/of_address.h>
23*4882a593Smuzhiyun #include <linux/clk/ti.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "clock.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #undef pr_fmt
28*4882a593Smuzhiyun #define pr_fmt(fmt) "%s: " fmt, __func__
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk);
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun static const struct clk_ops omap_gate_clkdm_clk_ops = {
33*4882a593Smuzhiyun .init = &omap2_init_clk_clkdm,
34*4882a593Smuzhiyun .enable = &omap2_clkops_enable_clkdm,
35*4882a593Smuzhiyun .disable = &omap2_clkops_disable_clkdm,
36*4882a593Smuzhiyun .restore_context = clk_gate_restore_context,
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun const struct clk_ops omap_gate_clk_ops = {
40*4882a593Smuzhiyun .init = &omap2_init_clk_clkdm,
41*4882a593Smuzhiyun .enable = &omap2_dflt_clk_enable,
42*4882a593Smuzhiyun .disable = &omap2_dflt_clk_disable,
43*4882a593Smuzhiyun .is_enabled = &omap2_dflt_clk_is_enabled,
44*4882a593Smuzhiyun .restore_context = clk_gate_restore_context,
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
48*4882a593Smuzhiyun .init = &omap2_init_clk_clkdm,
49*4882a593Smuzhiyun .enable = &omap36xx_gate_clk_enable_with_hsdiv_restore,
50*4882a593Smuzhiyun .disable = &omap2_dflt_clk_disable,
51*4882a593Smuzhiyun .is_enabled = &omap2_dflt_clk_is_enabled,
52*4882a593Smuzhiyun .restore_context = clk_gate_restore_context,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /**
56*4882a593Smuzhiyun * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering
57*4882a593Smuzhiyun * from HSDivider PWRDN problem Implements Errata ID: i556.
58*4882a593Smuzhiyun * @clk: DPLL output struct clk
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
61*4882a593Smuzhiyun * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
62*4882a593Smuzhiyun * valueafter their respective PWRDN bits are set. Any dummy write
63*4882a593Smuzhiyun * (Any other value different from the Read value) to the
64*4882a593Smuzhiyun * corresponding CM_CLKSEL register will refresh the dividers.
65*4882a593Smuzhiyun */
omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw * hw)66*4882a593Smuzhiyun static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *hw)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct clk_omap_divider *parent;
69*4882a593Smuzhiyun struct clk_hw *parent_hw;
70*4882a593Smuzhiyun u32 dummy_v, orig_v;
71*4882a593Smuzhiyun int ret;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* Clear PWRDN bit of HSDIVIDER */
74*4882a593Smuzhiyun ret = omap2_dflt_clk_enable(hw);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* Parent is the x2 node, get parent of parent for the m2 div */
77*4882a593Smuzhiyun parent_hw = clk_hw_get_parent(clk_hw_get_parent(hw));
78*4882a593Smuzhiyun parent = to_clk_omap_divider(parent_hw);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* Restore the dividers */
81*4882a593Smuzhiyun if (!ret) {
82*4882a593Smuzhiyun orig_v = ti_clk_ll_ops->clk_readl(&parent->reg);
83*4882a593Smuzhiyun dummy_v = orig_v;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* Write any other value different from the Read value */
86*4882a593Smuzhiyun dummy_v ^= (1 << parent->shift);
87*4882a593Smuzhiyun ti_clk_ll_ops->clk_writel(dummy_v, &parent->reg);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* Write the original divider */
90*4882a593Smuzhiyun ti_clk_ll_ops->clk_writel(orig_v, &parent->reg);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun return ret;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
_register_gate(struct device * dev,const char * name,const char * parent_name,unsigned long flags,struct clk_omap_reg * reg,u8 bit_idx,u8 clk_gate_flags,const struct clk_ops * ops,const struct clk_hw_omap_ops * hw_ops)96*4882a593Smuzhiyun static struct clk *_register_gate(struct device *dev, const char *name,
97*4882a593Smuzhiyun const char *parent_name, unsigned long flags,
98*4882a593Smuzhiyun struct clk_omap_reg *reg, u8 bit_idx,
99*4882a593Smuzhiyun u8 clk_gate_flags, const struct clk_ops *ops,
100*4882a593Smuzhiyun const struct clk_hw_omap_ops *hw_ops)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun struct clk_init_data init = { NULL };
103*4882a593Smuzhiyun struct clk_hw_omap *clk_hw;
104*4882a593Smuzhiyun struct clk *clk;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
107*4882a593Smuzhiyun if (!clk_hw)
108*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun clk_hw->hw.init = &init;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun init.name = name;
113*4882a593Smuzhiyun init.ops = ops;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun memcpy(&clk_hw->enable_reg, reg, sizeof(*reg));
116*4882a593Smuzhiyun clk_hw->enable_bit = bit_idx;
117*4882a593Smuzhiyun clk_hw->ops = hw_ops;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun clk_hw->flags = clk_gate_flags;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun init.parent_names = &parent_name;
122*4882a593Smuzhiyun init.num_parents = 1;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun init.flags = flags;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, name);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (IS_ERR(clk))
129*4882a593Smuzhiyun kfree(clk_hw);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return clk;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
_of_ti_gate_clk_setup(struct device_node * node,const struct clk_ops * ops,const struct clk_hw_omap_ops * hw_ops)134*4882a593Smuzhiyun static void __init _of_ti_gate_clk_setup(struct device_node *node,
135*4882a593Smuzhiyun const struct clk_ops *ops,
136*4882a593Smuzhiyun const struct clk_hw_omap_ops *hw_ops)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct clk *clk;
139*4882a593Smuzhiyun const char *parent_name;
140*4882a593Smuzhiyun struct clk_omap_reg reg;
141*4882a593Smuzhiyun u8 enable_bit = 0;
142*4882a593Smuzhiyun u32 val;
143*4882a593Smuzhiyun u32 flags = 0;
144*4882a593Smuzhiyun u8 clk_gate_flags = 0;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun if (ops != &omap_gate_clkdm_clk_ops) {
147*4882a593Smuzhiyun if (ti_clk_get_reg_addr(node, 0, ®))
148*4882a593Smuzhiyun return;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (!of_property_read_u32(node, "ti,bit-shift", &val))
151*4882a593Smuzhiyun enable_bit = val;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (of_clk_get_parent_count(node) != 1) {
155*4882a593Smuzhiyun pr_err("%pOFn must have 1 parent\n", node);
156*4882a593Smuzhiyun return;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun parent_name = of_clk_get_parent_name(node, 0);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (of_property_read_bool(node, "ti,set-rate-parent"))
162*4882a593Smuzhiyun flags |= CLK_SET_RATE_PARENT;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (of_property_read_bool(node, "ti,set-bit-to-disable"))
165*4882a593Smuzhiyun clk_gate_flags |= INVERT_ENABLE;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun clk = _register_gate(NULL, node->name, parent_name, flags, ®,
168*4882a593Smuzhiyun enable_bit, clk_gate_flags, ops, hw_ops);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (!IS_ERR(clk))
171*4882a593Smuzhiyun of_clk_add_provider(node, of_clk_src_simple_get, clk);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun static void __init
_of_ti_composite_gate_clk_setup(struct device_node * node,const struct clk_hw_omap_ops * hw_ops)175*4882a593Smuzhiyun _of_ti_composite_gate_clk_setup(struct device_node *node,
176*4882a593Smuzhiyun const struct clk_hw_omap_ops *hw_ops)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun struct clk_hw_omap *gate;
179*4882a593Smuzhiyun u32 val = 0;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun gate = kzalloc(sizeof(*gate), GFP_KERNEL);
182*4882a593Smuzhiyun if (!gate)
183*4882a593Smuzhiyun return;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun if (ti_clk_get_reg_addr(node, 0, &gate->enable_reg))
186*4882a593Smuzhiyun goto cleanup;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun of_property_read_u32(node, "ti,bit-shift", &val);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun gate->enable_bit = val;
191*4882a593Smuzhiyun gate->ops = hw_ops;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE))
194*4882a593Smuzhiyun return;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun cleanup:
197*4882a593Smuzhiyun kfree(gate);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun static void __init
of_ti_composite_no_wait_gate_clk_setup(struct device_node * node)201*4882a593Smuzhiyun of_ti_composite_no_wait_gate_clk_setup(struct device_node *node)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun _of_ti_composite_gate_clk_setup(node, NULL);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock",
206*4882a593Smuzhiyun of_ti_composite_no_wait_gate_clk_setup);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
of_ti_composite_interface_clk_setup(struct device_node * node)209*4882a593Smuzhiyun static void __init of_ti_composite_interface_clk_setup(struct device_node *node)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun CLK_OF_DECLARE(ti_composite_interface_clk, "ti,composite-interface-clock",
214*4882a593Smuzhiyun of_ti_composite_interface_clk_setup);
215*4882a593Smuzhiyun #endif
216*4882a593Smuzhiyun
of_ti_composite_gate_clk_setup(struct device_node * node)217*4882a593Smuzhiyun static void __init of_ti_composite_gate_clk_setup(struct device_node *node)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun _of_ti_composite_gate_clk_setup(node, &clkhwops_wait);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun CLK_OF_DECLARE(ti_composite_gate_clk, "ti,composite-gate-clock",
222*4882a593Smuzhiyun of_ti_composite_gate_clk_setup);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun
of_ti_clkdm_gate_clk_setup(struct device_node * node)225*4882a593Smuzhiyun static void __init of_ti_clkdm_gate_clk_setup(struct device_node *node)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun _of_ti_gate_clk_setup(node, &omap_gate_clkdm_clk_ops, NULL);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun CLK_OF_DECLARE(ti_clkdm_gate_clk, "ti,clkdm-gate-clock",
230*4882a593Smuzhiyun of_ti_clkdm_gate_clk_setup);
231*4882a593Smuzhiyun
of_ti_hsdiv_gate_clk_setup(struct device_node * node)232*4882a593Smuzhiyun static void __init of_ti_hsdiv_gate_clk_setup(struct device_node *node)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun _of_ti_gate_clk_setup(node, &omap_gate_clk_hsdiv_restore_ops,
235*4882a593Smuzhiyun &clkhwops_wait);
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun CLK_OF_DECLARE(ti_hsdiv_gate_clk, "ti,hsdiv-gate-clock",
238*4882a593Smuzhiyun of_ti_hsdiv_gate_clk_setup);
239*4882a593Smuzhiyun
of_ti_gate_clk_setup(struct device_node * node)240*4882a593Smuzhiyun static void __init of_ti_gate_clk_setup(struct device_node *node)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup);
245*4882a593Smuzhiyun
of_ti_wait_gate_clk_setup(struct device_node * node)246*4882a593Smuzhiyun static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, &clkhwops_wait);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun CLK_OF_DECLARE(ti_wait_gate_clk, "ti,wait-gate-clock",
251*4882a593Smuzhiyun of_ti_wait_gate_clk_setup);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun #ifdef CONFIG_ARCH_OMAP3
of_ti_am35xx_gate_clk_setup(struct device_node * node)254*4882a593Smuzhiyun static void __init of_ti_am35xx_gate_clk_setup(struct device_node *node)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
257*4882a593Smuzhiyun &clkhwops_am35xx_ipss_module_wait);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun CLK_OF_DECLARE(ti_am35xx_gate_clk, "ti,am35xx-gate-clock",
260*4882a593Smuzhiyun of_ti_am35xx_gate_clk_setup);
261*4882a593Smuzhiyun
of_ti_dss_gate_clk_setup(struct device_node * node)262*4882a593Smuzhiyun static void __init of_ti_dss_gate_clk_setup(struct device_node *node)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
265*4882a593Smuzhiyun &clkhwops_omap3430es2_dss_usbhost_wait);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun CLK_OF_DECLARE(ti_dss_gate_clk, "ti,dss-gate-clock",
268*4882a593Smuzhiyun of_ti_dss_gate_clk_setup);
269*4882a593Smuzhiyun #endif
270