diff options
| -rw-r--r-- | drivers/sh/clk/cpg.c | 182 |
1 files changed, 75 insertions, 107 deletions
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index eeaec796a395..07e9fb4f8041 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c | |||
| @@ -162,6 +162,72 @@ static struct sh_clk_ops sh_clk_div_enable_clk_ops = { | |||
| 162 | .disable = sh_clk_div_disable, | 162 | .disable = sh_clk_div_disable, |
| 163 | }; | 163 | }; |
| 164 | 164 | ||
| 165 | static int __init sh_clk_init_parent(struct clk *clk) | ||
| 166 | { | ||
| 167 | u32 val; | ||
| 168 | |||
| 169 | if (clk->parent) | ||
| 170 | return 0; | ||
| 171 | |||
| 172 | if (!clk->parent_table || !clk->parent_num) | ||
| 173 | return 0; | ||
| 174 | |||
| 175 | if (!clk->src_width) { | ||
| 176 | pr_err("sh_clk_init_parent: cannot select parent clock\n"); | ||
| 177 | return -EINVAL; | ||
| 178 | } | ||
| 179 | |||
| 180 | val = (sh_clk_read(clk) >> clk->src_shift); | ||
| 181 | val &= (1 << clk->src_width) - 1; | ||
| 182 | |||
| 183 | if (val >= clk->parent_num) { | ||
| 184 | pr_err("sh_clk_init_parent: parent table size failed\n"); | ||
| 185 | return -EINVAL; | ||
| 186 | } | ||
| 187 | |||
| 188 | clk_reparent(clk, clk->parent_table[val]); | ||
| 189 | if (!clk->parent) { | ||
| 190 | pr_err("sh_clk_init_parent: unable to set parent"); | ||
| 191 | return -EINVAL; | ||
| 192 | } | ||
| 193 | |||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static int __init sh_clk_div_register_ops(struct clk *clks, int nr, | ||
| 198 | struct clk_div_table *table, struct sh_clk_ops *ops) | ||
| 199 | { | ||
| 200 | struct clk *clkp; | ||
| 201 | void *freq_table; | ||
| 202 | int nr_divs = table->div_mult_table->nr_divisors; | ||
| 203 | int freq_table_size = sizeof(struct cpufreq_frequency_table); | ||
| 204 | int ret = 0; | ||
| 205 | int k; | ||
| 206 | |||
| 207 | freq_table_size *= (nr_divs + 1); | ||
| 208 | freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); | ||
| 209 | if (!freq_table) { | ||
| 210 | pr_err("%s: unable to alloc memory\n", __func__); | ||
| 211 | return -ENOMEM; | ||
| 212 | } | ||
| 213 | |||
| 214 | for (k = 0; !ret && (k < nr); k++) { | ||
| 215 | clkp = clks + k; | ||
| 216 | |||
| 217 | clkp->ops = ops; | ||
| 218 | clkp->priv = table; | ||
| 219 | |||
| 220 | clkp->freq_table = freq_table + (k * freq_table_size); | ||
| 221 | clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; | ||
| 222 | |||
| 223 | ret = clk_register(clkp); | ||
| 224 | if (ret == 0) | ||
| 225 | ret = sh_clk_init_parent(clkp); | ||
| 226 | } | ||
| 227 | |||
| 228 | return ret; | ||
| 229 | } | ||
| 230 | |||
| 165 | /* | 231 | /* |
| 166 | * div6 support | 232 | * div6 support |
| 167 | */ | 233 | */ |
| @@ -223,82 +289,16 @@ static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = { | |||
| 223 | .set_parent = sh_clk_div6_set_parent, | 289 | .set_parent = sh_clk_div6_set_parent, |
| 224 | }; | 290 | }; |
| 225 | 291 | ||
| 226 | static int __init sh_clk_init_parent(struct clk *clk) | ||
| 227 | { | ||
| 228 | u32 val; | ||
| 229 | |||
| 230 | if (clk->parent) | ||
| 231 | return 0; | ||
| 232 | |||
| 233 | if (!clk->parent_table || !clk->parent_num) | ||
| 234 | return 0; | ||
| 235 | |||
| 236 | if (!clk->src_width) { | ||
| 237 | pr_err("sh_clk_init_parent: cannot select parent clock\n"); | ||
| 238 | return -EINVAL; | ||
| 239 | } | ||
| 240 | |||
| 241 | val = (sh_clk_read(clk) >> clk->src_shift); | ||
| 242 | val &= (1 << clk->src_width) - 1; | ||
| 243 | |||
| 244 | if (val >= clk->parent_num) { | ||
| 245 | pr_err("sh_clk_init_parent: parent table size failed\n"); | ||
| 246 | return -EINVAL; | ||
| 247 | } | ||
| 248 | |||
| 249 | clk_reparent(clk, clk->parent_table[val]); | ||
| 250 | if (!clk->parent) { | ||
| 251 | pr_err("sh_clk_init_parent: unable to set parent"); | ||
| 252 | return -EINVAL; | ||
| 253 | } | ||
| 254 | |||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int __init sh_clk_div6_register_ops(struct clk *clks, int nr, | ||
| 259 | struct sh_clk_ops *ops) | ||
| 260 | { | ||
| 261 | struct clk *clkp; | ||
| 262 | void *freq_table; | ||
| 263 | struct clk_div_table *table = &sh_clk_div6_table; | ||
| 264 | int nr_divs = table->div_mult_table->nr_divisors; | ||
| 265 | int freq_table_size = sizeof(struct cpufreq_frequency_table); | ||
| 266 | int ret = 0; | ||
| 267 | int k; | ||
| 268 | |||
| 269 | freq_table_size *= (nr_divs + 1); | ||
| 270 | freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); | ||
| 271 | if (!freq_table) { | ||
| 272 | pr_err("sh_clk_div6_register: unable to alloc memory\n"); | ||
| 273 | return -ENOMEM; | ||
| 274 | } | ||
| 275 | |||
| 276 | for (k = 0; !ret && (k < nr); k++) { | ||
| 277 | clkp = clks + k; | ||
| 278 | |||
| 279 | clkp->ops = ops; | ||
| 280 | clkp->priv = table; | ||
| 281 | clkp->freq_table = freq_table + (k * freq_table_size); | ||
| 282 | clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; | ||
| 283 | ret = clk_register(clkp); | ||
| 284 | if (ret < 0) | ||
| 285 | break; | ||
| 286 | |||
| 287 | ret = sh_clk_init_parent(clkp); | ||
| 288 | } | ||
| 289 | |||
| 290 | return ret; | ||
| 291 | } | ||
| 292 | |||
| 293 | int __init sh_clk_div6_register(struct clk *clks, int nr) | 292 | int __init sh_clk_div6_register(struct clk *clks, int nr) |
| 294 | { | 293 | { |
| 295 | return sh_clk_div6_register_ops(clks, nr, &sh_clk_div_enable_clk_ops); | 294 | return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table, |
| 295 | &sh_clk_div_enable_clk_ops); | ||
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | int __init sh_clk_div6_reparent_register(struct clk *clks, int nr) | 298 | int __init sh_clk_div6_reparent_register(struct clk *clks, int nr) |
| 299 | { | 299 | { |
| 300 | return sh_clk_div6_register_ops(clks, nr, | 300 | return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table, |
| 301 | &sh_clk_div6_reparent_clk_ops); | 301 | &sh_clk_div6_reparent_clk_ops); |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | /* | 304 | /* |
| @@ -342,54 +342,22 @@ static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = { | |||
| 342 | .set_parent = sh_clk_div4_set_parent, | 342 | .set_parent = sh_clk_div4_set_parent, |
| 343 | }; | 343 | }; |
| 344 | 344 | ||
| 345 | static int __init sh_clk_div4_register_ops(struct clk *clks, int nr, | ||
| 346 | struct clk_div4_table *table, struct sh_clk_ops *ops) | ||
| 347 | { | ||
| 348 | struct clk *clkp; | ||
| 349 | void *freq_table; | ||
| 350 | int nr_divs = table->div_mult_table->nr_divisors; | ||
| 351 | int freq_table_size = sizeof(struct cpufreq_frequency_table); | ||
| 352 | int ret = 0; | ||
| 353 | int k; | ||
| 354 | |||
| 355 | freq_table_size *= (nr_divs + 1); | ||
| 356 | freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); | ||
| 357 | if (!freq_table) { | ||
| 358 | pr_err("sh_clk_div4_register: unable to alloc memory\n"); | ||
| 359 | return -ENOMEM; | ||
| 360 | } | ||
| 361 | |||
| 362 | for (k = 0; !ret && (k < nr); k++) { | ||
| 363 | clkp = clks + k; | ||
| 364 | |||
| 365 | clkp->ops = ops; | ||
| 366 | clkp->priv = table; | ||
| 367 | |||
| 368 | clkp->freq_table = freq_table + (k * freq_table_size); | ||
| 369 | clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; | ||
| 370 | |||
| 371 | ret = clk_register(clkp); | ||
| 372 | } | ||
| 373 | |||
| 374 | return ret; | ||
| 375 | } | ||
| 376 | |||
| 377 | int __init sh_clk_div4_register(struct clk *clks, int nr, | 345 | int __init sh_clk_div4_register(struct clk *clks, int nr, |
| 378 | struct clk_div4_table *table) | 346 | struct clk_div4_table *table) |
| 379 | { | 347 | { |
| 380 | return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div_clk_ops); | 348 | return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops); |
| 381 | } | 349 | } |
| 382 | 350 | ||
| 383 | int __init sh_clk_div4_enable_register(struct clk *clks, int nr, | 351 | int __init sh_clk_div4_enable_register(struct clk *clks, int nr, |
| 384 | struct clk_div4_table *table) | 352 | struct clk_div4_table *table) |
| 385 | { | 353 | { |
| 386 | return sh_clk_div4_register_ops(clks, nr, table, | 354 | return sh_clk_div_register_ops(clks, nr, table, |
| 387 | &sh_clk_div_enable_clk_ops); | 355 | &sh_clk_div_enable_clk_ops); |
| 388 | } | 356 | } |
| 389 | 357 | ||
| 390 | int __init sh_clk_div4_reparent_register(struct clk *clks, int nr, | 358 | int __init sh_clk_div4_reparent_register(struct clk *clks, int nr, |
| 391 | struct clk_div4_table *table) | 359 | struct clk_div4_table *table) |
| 392 | { | 360 | { |
| 393 | return sh_clk_div4_register_ops(clks, nr, table, | 361 | return sh_clk_div_register_ops(clks, nr, table, |
| 394 | &sh_clk_div4_reparent_clk_ops); | 362 | &sh_clk_div4_reparent_clk_ops); |
| 395 | } | 363 | } |
