aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/sh/clk-cpg.c58
-rw-r--r--include/linux/sh_clk.h19
2 files changed, 70 insertions, 7 deletions
diff --git a/drivers/sh/clk-cpg.c b/drivers/sh/clk-cpg.c
index f5c80ba9ab1c..8c024b984ed8 100644
--- a/drivers/sh/clk-cpg.c
+++ b/drivers/sh/clk-cpg.c
@@ -68,6 +68,39 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
68 return clk->freq_table[idx].frequency; 68 return clk->freq_table[idx].frequency;
69} 69}
70 70
71static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
72{
73 struct clk_div_mult_table *table = &sh_clk_div6_table;
74 u32 value;
75 int ret, i;
76
77 if (!clk->parent_table || !clk->parent_num)
78 return -EINVAL;
79
80 /* Search the parent */
81 for (i = 0; i < clk->parent_num; i++)
82 if (clk->parent_table[i] == parent)
83 break;
84
85 if (i == clk->parent_num)
86 return -ENODEV;
87
88 ret = clk_reparent(clk, parent);
89 if (ret < 0)
90 return ret;
91
92 value = __raw_readl(clk->enable_reg) &
93 ~(((1 << clk->src_width) - 1) << clk->src_shift);
94
95 __raw_writel(value | (i << clk->src_shift), clk->enable_reg);
96
97 /* Rebuild the frequency table */
98 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
99 table, &clk->arch_flags);
100
101 return 0;
102}
103
71static int sh_clk_div6_set_rate(struct clk *clk, 104static int sh_clk_div6_set_rate(struct clk *clk,
72 unsigned long rate, int algo_id) 105 unsigned long rate, int algo_id)
73{ 106{
@@ -117,7 +150,17 @@ static struct clk_ops sh_clk_div6_clk_ops = {
117 .disable = sh_clk_div6_disable, 150 .disable = sh_clk_div6_disable,
118}; 151};
119 152
120int __init sh_clk_div6_register(struct clk *clks, int nr) 153static struct clk_ops sh_clk_div6_reparent_clk_ops = {
154 .recalc = sh_clk_div6_recalc,
155 .round_rate = sh_clk_div_round_rate,
156 .set_rate = sh_clk_div6_set_rate,
157 .enable = sh_clk_div6_enable,
158 .disable = sh_clk_div6_disable,
159 .set_parent = sh_clk_div6_set_parent,
160};
161
162static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
163 struct clk_ops *ops)
121{ 164{
122 struct clk *clkp; 165 struct clk *clkp;
123 void *freq_table; 166 void *freq_table;
@@ -136,7 +179,7 @@ int __init sh_clk_div6_register(struct clk *clks, int nr)
136 for (k = 0; !ret && (k < nr); k++) { 179 for (k = 0; !ret && (k < nr); k++) {
137 clkp = clks + k; 180 clkp = clks + k;
138 181
139 clkp->ops = &sh_clk_div6_clk_ops; 182 clkp->ops = ops;
140 clkp->id = -1; 183 clkp->id = -1;
141 clkp->freq_table = freq_table + (k * freq_table_size); 184 clkp->freq_table = freq_table + (k * freq_table_size);
142 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; 185 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
@@ -147,6 +190,17 @@ int __init sh_clk_div6_register(struct clk *clks, int nr)
147 return ret; 190 return ret;
148} 191}
149 192
193int __init sh_clk_div6_register(struct clk *clks, int nr)
194{
195 return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops);
196}
197
198int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
199{
200 return sh_clk_div6_register_ops(clks, nr,
201 &sh_clk_div6_reparent_clk_ops);
202}
203
150static unsigned long sh_clk_div4_recalc(struct clk *clk) 204static unsigned long sh_clk_div4_recalc(struct clk *clk)
151{ 205{
152 struct clk_div4_table *d4t = clk->priv; 206 struct clk_div4_table *d4t = clk->priv;
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 08a07b9a894f..875ce50719a9 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -142,13 +142,22 @@ int sh_clk_div4_enable_register(struct clk *clks, int nr,
142int sh_clk_div4_reparent_register(struct clk *clks, int nr, 142int sh_clk_div4_reparent_register(struct clk *clks, int nr,
143 struct clk_div4_table *table); 143 struct clk_div4_table *table);
144 144
145#define SH_CLK_DIV6(_parent, _reg, _flags) \ 145#define SH_CLK_DIV6_EXT(_parent, _reg, _flags, _parents, \
146{ \ 146 _num_parents, _src_shift, _src_width) \
147 .parent = _parent, \ 147{ \
148 .enable_reg = (void __iomem *)_reg, \ 148 .parent = _parent, \
149 .flags = _flags, \ 149 .enable_reg = (void __iomem *)_reg, \
150 .flags = _flags, \
151 .parent_table = _parents, \
152 .parent_num = _num_parents, \
153 .src_shift = _src_shift, \
154 .src_width = _src_width, \
150} 155}
151 156
157#define SH_CLK_DIV6(_parent, _reg, _flags) \
158 SH_CLK_DIV6_EXT(_parent, _reg, _flags, NULL, 0, 0, 0)
159
152int sh_clk_div6_register(struct clk *clks, int nr); 160int sh_clk_div6_register(struct clk *clks, int nr);
161int sh_clk_div6_reparent_register(struct clk *clks, int nr);
153 162
154#endif /* __SH_CLOCK_H */ 163#endif /* __SH_CLOCK_H */