1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * OMAP clockdomain 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.h>
19*4882a593Smuzhiyun #include <linux/clk-provider.h>
20*4882a593Smuzhiyun #include <linux/slab.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 /**
31*4882a593Smuzhiyun * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
32*4882a593Smuzhiyun * @hw: struct clk_hw * of the clock being enabled
33*4882a593Smuzhiyun *
34*4882a593Smuzhiyun * Increment the usecount of the clockdomain of the clock pointed to
35*4882a593Smuzhiyun * by @hw; if the usecount is 1, the clockdomain will be "enabled."
36*4882a593Smuzhiyun * Only needed for clocks that don't use omap2_dflt_clk_enable() as
37*4882a593Smuzhiyun * their enable function pointer. Passes along the return value of
38*4882a593Smuzhiyun * clkdm_clk_enable(), -EINVAL if @hw is not associated with a
39*4882a593Smuzhiyun * clockdomain, or 0 if clock framework-based clockdomain control is
40*4882a593Smuzhiyun * not implemented.
41*4882a593Smuzhiyun */
omap2_clkops_enable_clkdm(struct clk_hw * hw)42*4882a593Smuzhiyun int omap2_clkops_enable_clkdm(struct clk_hw *hw)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun struct clk_hw_omap *clk;
45*4882a593Smuzhiyun int ret = 0;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun clk = to_clk_hw_omap(hw);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (unlikely(!clk->clkdm)) {
50*4882a593Smuzhiyun pr_err("%s: %s: no clkdm set ?!\n", __func__,
51*4882a593Smuzhiyun clk_hw_get_name(hw));
52*4882a593Smuzhiyun return -EINVAL;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
56*4882a593Smuzhiyun pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
57*4882a593Smuzhiyun __func__, clk_hw_get_name(hw));
58*4882a593Smuzhiyun return 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
62*4882a593Smuzhiyun WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
63*4882a593Smuzhiyun __func__, clk_hw_get_name(hw), clk->clkdm_name, ret);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun return ret;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /**
69*4882a593Smuzhiyun * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
70*4882a593Smuzhiyun * @hw: struct clk_hw * of the clock being disabled
71*4882a593Smuzhiyun *
72*4882a593Smuzhiyun * Decrement the usecount of the clockdomain of the clock pointed to
73*4882a593Smuzhiyun * by @hw; if the usecount is 0, the clockdomain will be "disabled."
74*4882a593Smuzhiyun * Only needed for clocks that don't use omap2_dflt_clk_disable() as their
75*4882a593Smuzhiyun * disable function pointer. No return value.
76*4882a593Smuzhiyun */
omap2_clkops_disable_clkdm(struct clk_hw * hw)77*4882a593Smuzhiyun void omap2_clkops_disable_clkdm(struct clk_hw *hw)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun struct clk_hw_omap *clk;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun clk = to_clk_hw_omap(hw);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (unlikely(!clk->clkdm)) {
84*4882a593Smuzhiyun pr_err("%s: %s: no clkdm set ?!\n", __func__,
85*4882a593Smuzhiyun clk_hw_get_name(hw));
86*4882a593Smuzhiyun return;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
90*4882a593Smuzhiyun pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
91*4882a593Smuzhiyun __func__, clk_hw_get_name(hw));
92*4882a593Smuzhiyun return;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /**
99*4882a593Smuzhiyun * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
100*4882a593Smuzhiyun * @clk: OMAP clock struct ptr to use
101*4882a593Smuzhiyun *
102*4882a593Smuzhiyun * Convert a clockdomain name stored in a struct clk 'clk' into a
103*4882a593Smuzhiyun * clockdomain pointer, and save it into the struct clk. Intended to be
104*4882a593Smuzhiyun * called during clk_register(). Returns 0 on success, -EERROR otherwise.
105*4882a593Smuzhiyun */
omap2_init_clk_clkdm(struct clk_hw * hw)106*4882a593Smuzhiyun int omap2_init_clk_clkdm(struct clk_hw *hw)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct clk_hw_omap *clk = to_clk_hw_omap(hw);
109*4882a593Smuzhiyun struct clockdomain *clkdm;
110*4882a593Smuzhiyun const char *clk_name;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if (!clk->clkdm_name)
113*4882a593Smuzhiyun return 0;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun clk_name = __clk_get_name(hw->clk);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun clkdm = ti_clk_ll_ops->clkdm_lookup(clk->clkdm_name);
118*4882a593Smuzhiyun if (clkdm) {
119*4882a593Smuzhiyun pr_debug("clock: associated clk %s to clkdm %s\n",
120*4882a593Smuzhiyun clk_name, clk->clkdm_name);
121*4882a593Smuzhiyun clk->clkdm = clkdm;
122*4882a593Smuzhiyun } else {
123*4882a593Smuzhiyun pr_debug("clock: could not associate clk %s to clkdm %s\n",
124*4882a593Smuzhiyun clk_name, clk->clkdm_name);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
of_ti_clockdomain_setup(struct device_node * node)130*4882a593Smuzhiyun static void __init of_ti_clockdomain_setup(struct device_node *node)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct clk *clk;
133*4882a593Smuzhiyun struct clk_hw *clk_hw;
134*4882a593Smuzhiyun const char *clkdm_name = node->name;
135*4882a593Smuzhiyun int i;
136*4882a593Smuzhiyun unsigned int num_clks;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun num_clks = of_clk_get_parent_count(node);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun for (i = 0; i < num_clks; i++) {
141*4882a593Smuzhiyun clk = of_clk_get(node, i);
142*4882a593Smuzhiyun if (IS_ERR(clk)) {
143*4882a593Smuzhiyun pr_err("%s: Failed get %pOF' clock nr %d (%ld)\n",
144*4882a593Smuzhiyun __func__, node, i, PTR_ERR(clk));
145*4882a593Smuzhiyun continue;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun clk_hw = __clk_get_hw(clk);
148*4882a593Smuzhiyun if (!omap2_clk_is_hw_omap(clk_hw)) {
149*4882a593Smuzhiyun pr_warn("can't setup clkdm for basic clk %s\n",
150*4882a593Smuzhiyun __clk_get_name(clk));
151*4882a593Smuzhiyun clk_put(clk);
152*4882a593Smuzhiyun continue;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name;
155*4882a593Smuzhiyun omap2_init_clk_clkdm(clk_hw);
156*4882a593Smuzhiyun clk_put(clk);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun static const struct of_device_id ti_clkdm_match_table[] __initconst = {
161*4882a593Smuzhiyun { .compatible = "ti,clockdomain" },
162*4882a593Smuzhiyun { }
163*4882a593Smuzhiyun };
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /**
166*4882a593Smuzhiyun * ti_dt_clockdomains_setup - setup device tree clockdomains
167*4882a593Smuzhiyun *
168*4882a593Smuzhiyun * Initializes clockdomain nodes for a SoC. This parses through all the
169*4882a593Smuzhiyun * nodes with compatible = "ti,clockdomain", and add the clockdomain
170*4882a593Smuzhiyun * info for all the clocks listed under these. This function shall be
171*4882a593Smuzhiyun * called after rest of the DT clock init has completed and all
172*4882a593Smuzhiyun * clock nodes have been registered.
173*4882a593Smuzhiyun */
ti_dt_clockdomains_setup(void)174*4882a593Smuzhiyun void __init ti_dt_clockdomains_setup(void)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun struct device_node *np;
177*4882a593Smuzhiyun for_each_matching_node(np, ti_clkdm_match_table) {
178*4882a593Smuzhiyun of_ti_clockdomain_setup(np);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun }
181