1 /* 2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 */ 10 11 #include <linux/clk-provider.h> 12 #include <linux/clkdev.h> 13 #include <linux/clk/at91_pmc.h> 14 #include <linux/of.h> 15 #include <linux/mfd/syscon.h> 16 #include <linux/regmap.h> 17 18 #include "pmc.h" 19 20 DEFINE_SPINLOCK(pmc_pcr_lock); 21 22 #define PERIPHERAL_MAX 64 23 24 #define PERIPHERAL_AT91RM9200 0 25 #define PERIPHERAL_AT91SAM9X5 1 26 27 #define PERIPHERAL_ID_MIN 2 28 #define PERIPHERAL_ID_MAX 31 29 #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) 30 31 #define PERIPHERAL_RSHIFT_MASK 0x3 32 #define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK) 33 34 #define PERIPHERAL_MAX_SHIFT 3 35 36 struct clk_peripheral { 37 struct clk_hw hw; 38 struct regmap *regmap; 39 u32 id; 40 }; 41 42 #define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw) 43 44 struct clk_sam9x5_peripheral { 45 struct clk_hw hw; 46 struct regmap *regmap; 47 struct clk_range range; 48 spinlock_t *lock; 49 u32 id; 50 u32 div; 51 bool auto_div; 52 }; 53 54 #define to_clk_sam9x5_peripheral(hw) \ 55 container_of(hw, struct clk_sam9x5_peripheral, hw) 56 57 static int clk_peripheral_enable(struct clk_hw *hw) 58 { 59 struct clk_peripheral *periph = to_clk_peripheral(hw); 60 int offset = AT91_PMC_PCER; 61 u32 id = periph->id; 62 63 if (id < PERIPHERAL_ID_MIN) 64 return 0; 65 if (id > PERIPHERAL_ID_MAX) 66 offset = AT91_PMC_PCER1; 67 regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id)); 68 69 return 0; 70 } 71 72 static void clk_peripheral_disable(struct clk_hw *hw) 73 { 74 struct clk_peripheral *periph = to_clk_peripheral(hw); 75 int offset = AT91_PMC_PCDR; 76 u32 id = periph->id; 77 78 if (id < PERIPHERAL_ID_MIN) 79 return; 80 if (id > PERIPHERAL_ID_MAX) 81 offset = AT91_PMC_PCDR1; 82 regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id)); 83 } 84 85 static int clk_peripheral_is_enabled(struct clk_hw *hw) 86 { 87 struct clk_peripheral *periph = to_clk_peripheral(hw); 88 int offset = AT91_PMC_PCSR; 89 unsigned int status; 90 u32 id = periph->id; 91 92 if (id < PERIPHERAL_ID_MIN) 93 return 1; 94 if (id > PERIPHERAL_ID_MAX) 95 offset = AT91_PMC_PCSR1; 96 regmap_read(periph->regmap, offset, &status); 97 98 return status & PERIPHERAL_MASK(id) ? 1 : 0; 99 } 100 101 static const struct clk_ops peripheral_ops = { 102 .enable = clk_peripheral_enable, 103 .disable = clk_peripheral_disable, 104 .is_enabled = clk_peripheral_is_enabled, 105 }; 106 107 static struct clk_hw * __init 108 at91_clk_register_peripheral(struct regmap *regmap, const char *name, 109 const char *parent_name, u32 id) 110 { 111 struct clk_peripheral *periph; 112 struct clk_init_data init; 113 struct clk_hw *hw; 114 int ret; 115 116 if (!name || !parent_name || id > PERIPHERAL_ID_MAX) 117 return ERR_PTR(-EINVAL); 118 119 periph = kzalloc(sizeof(*periph), GFP_KERNEL); 120 if (!periph) 121 return ERR_PTR(-ENOMEM); 122 123 init.name = name; 124 init.ops = &peripheral_ops; 125 init.parent_names = (parent_name ? &parent_name : NULL); 126 init.num_parents = (parent_name ? 1 : 0); 127 init.flags = 0; 128 129 periph->id = id; 130 periph->hw.init = &init; 131 periph->regmap = regmap; 132 133 hw = &periph->hw; 134 ret = clk_hw_register(NULL, &periph->hw); 135 if (ret) { 136 kfree(periph); 137 hw = ERR_PTR(ret); 138 } 139 140 return hw; 141 } 142 143 static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph) 144 { 145 struct clk_hw *parent; 146 unsigned long parent_rate; 147 int shift = 0; 148 149 if (!periph->auto_div) 150 return; 151 152 if (periph->range.max) { 153 parent = clk_hw_get_parent_by_index(&periph->hw, 0); 154 parent_rate = clk_hw_get_rate(parent); 155 if (!parent_rate) 156 return; 157 158 for (; shift < PERIPHERAL_MAX_SHIFT; shift++) { 159 if (parent_rate >> shift <= periph->range.max) 160 break; 161 } 162 } 163 164 periph->auto_div = false; 165 periph->div = shift; 166 } 167 168 static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) 169 { 170 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 171 unsigned long flags; 172 173 if (periph->id < PERIPHERAL_ID_MIN) 174 return 0; 175 176 spin_lock_irqsave(periph->lock, flags); 177 regmap_write(periph->regmap, AT91_PMC_PCR, 178 (periph->id & AT91_PMC_PCR_PID_MASK)); 179 regmap_update_bits(periph->regmap, AT91_PMC_PCR, 180 AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD | 181 AT91_PMC_PCR_EN, 182 AT91_PMC_PCR_DIV(periph->div) | 183 AT91_PMC_PCR_CMD | 184 AT91_PMC_PCR_EN); 185 spin_unlock_irqrestore(periph->lock, flags); 186 187 return 0; 188 } 189 190 static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) 191 { 192 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 193 unsigned long flags; 194 195 if (periph->id < PERIPHERAL_ID_MIN) 196 return; 197 198 spin_lock_irqsave(periph->lock, flags); 199 regmap_write(periph->regmap, AT91_PMC_PCR, 200 (periph->id & AT91_PMC_PCR_PID_MASK)); 201 regmap_update_bits(periph->regmap, AT91_PMC_PCR, 202 AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD, 203 AT91_PMC_PCR_CMD); 204 spin_unlock_irqrestore(periph->lock, flags); 205 } 206 207 static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) 208 { 209 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 210 unsigned long flags; 211 unsigned int status; 212 213 if (periph->id < PERIPHERAL_ID_MIN) 214 return 1; 215 216 spin_lock_irqsave(periph->lock, flags); 217 regmap_write(periph->regmap, AT91_PMC_PCR, 218 (periph->id & AT91_PMC_PCR_PID_MASK)); 219 regmap_read(periph->regmap, AT91_PMC_PCR, &status); 220 spin_unlock_irqrestore(periph->lock, flags); 221 222 return status & AT91_PMC_PCR_EN ? 1 : 0; 223 } 224 225 static unsigned long 226 clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, 227 unsigned long parent_rate) 228 { 229 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 230 unsigned long flags; 231 unsigned int status; 232 233 if (periph->id < PERIPHERAL_ID_MIN) 234 return parent_rate; 235 236 spin_lock_irqsave(periph->lock, flags); 237 regmap_write(periph->regmap, AT91_PMC_PCR, 238 (periph->id & AT91_PMC_PCR_PID_MASK)); 239 regmap_read(periph->regmap, AT91_PMC_PCR, &status); 240 spin_unlock_irqrestore(periph->lock, flags); 241 242 if (status & AT91_PMC_PCR_EN) { 243 periph->div = PERIPHERAL_RSHIFT(status); 244 periph->auto_div = false; 245 } else { 246 clk_sam9x5_peripheral_autodiv(periph); 247 } 248 249 return parent_rate >> periph->div; 250 } 251 252 static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw, 253 unsigned long rate, 254 unsigned long *parent_rate) 255 { 256 int shift = 0; 257 unsigned long best_rate; 258 unsigned long best_diff; 259 unsigned long cur_rate = *parent_rate; 260 unsigned long cur_diff; 261 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 262 263 if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) 264 return *parent_rate; 265 266 if (periph->range.max) { 267 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) { 268 cur_rate = *parent_rate >> shift; 269 if (cur_rate <= periph->range.max) 270 break; 271 } 272 } 273 274 if (rate >= cur_rate) 275 return cur_rate; 276 277 best_diff = cur_rate - rate; 278 best_rate = cur_rate; 279 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) { 280 cur_rate = *parent_rate >> shift; 281 if (cur_rate < rate) 282 cur_diff = rate - cur_rate; 283 else 284 cur_diff = cur_rate - rate; 285 286 if (cur_diff < best_diff) { 287 best_diff = cur_diff; 288 best_rate = cur_rate; 289 } 290 291 if (!best_diff || cur_rate < rate) 292 break; 293 } 294 295 return best_rate; 296 } 297 298 static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw, 299 unsigned long rate, 300 unsigned long parent_rate) 301 { 302 int shift; 303 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 304 if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) { 305 if (parent_rate == rate) 306 return 0; 307 else 308 return -EINVAL; 309 } 310 311 if (periph->range.max && rate > periph->range.max) 312 return -EINVAL; 313 314 for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) { 315 if (parent_rate >> shift == rate) { 316 periph->auto_div = false; 317 periph->div = shift; 318 return 0; 319 } 320 } 321 322 return -EINVAL; 323 } 324 325 static const struct clk_ops sam9x5_peripheral_ops = { 326 .enable = clk_sam9x5_peripheral_enable, 327 .disable = clk_sam9x5_peripheral_disable, 328 .is_enabled = clk_sam9x5_peripheral_is_enabled, 329 .recalc_rate = clk_sam9x5_peripheral_recalc_rate, 330 .round_rate = clk_sam9x5_peripheral_round_rate, 331 .set_rate = clk_sam9x5_peripheral_set_rate, 332 }; 333 334 static struct clk_hw * __init 335 at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, 336 const char *name, const char *parent_name, 337 u32 id, const struct clk_range *range) 338 { 339 struct clk_sam9x5_peripheral *periph; 340 struct clk_init_data init; 341 struct clk_hw *hw; 342 int ret; 343 344 if (!name || !parent_name) 345 return ERR_PTR(-EINVAL); 346 347 periph = kzalloc(sizeof(*periph), GFP_KERNEL); 348 if (!periph) 349 return ERR_PTR(-ENOMEM); 350 351 init.name = name; 352 init.ops = &sam9x5_peripheral_ops; 353 init.parent_names = (parent_name ? &parent_name : NULL); 354 init.num_parents = (parent_name ? 1 : 0); 355 init.flags = 0; 356 357 periph->id = id; 358 periph->hw.init = &init; 359 periph->div = 0; 360 periph->regmap = regmap; 361 periph->lock = lock; 362 periph->auto_div = true; 363 periph->range = *range; 364 365 hw = &periph->hw; 366 ret = clk_hw_register(NULL, &periph->hw); 367 if (ret) { 368 kfree(periph); 369 hw = ERR_PTR(ret); 370 } else { 371 clk_sam9x5_peripheral_autodiv(periph); 372 pmc_register_id(id); 373 } 374 375 return hw; 376 } 377 378 static void __init 379 of_at91_clk_periph_setup(struct device_node *np, u8 type) 380 { 381 int num; 382 u32 id; 383 struct clk_hw *hw; 384 const char *parent_name; 385 const char *name; 386 struct device_node *periphclknp; 387 struct regmap *regmap; 388 389 parent_name = of_clk_get_parent_name(np, 0); 390 if (!parent_name) 391 return; 392 393 num = of_get_child_count(np); 394 if (!num || num > PERIPHERAL_MAX) 395 return; 396 397 regmap = syscon_node_to_regmap(of_get_parent(np)); 398 if (IS_ERR(regmap)) 399 return; 400 401 for_each_child_of_node(np, periphclknp) { 402 if (of_property_read_u32(periphclknp, "reg", &id)) 403 continue; 404 405 if (id >= PERIPHERAL_MAX) 406 continue; 407 408 if (of_property_read_string(np, "clock-output-names", &name)) 409 name = periphclknp->name; 410 411 if (type == PERIPHERAL_AT91RM9200) { 412 hw = at91_clk_register_peripheral(regmap, name, 413 parent_name, id); 414 } else { 415 struct clk_range range = CLK_RANGE(0, 0); 416 417 of_at91_get_clk_range(periphclknp, 418 "atmel,clk-output-range", 419 &range); 420 421 hw = at91_clk_register_sam9x5_peripheral(regmap, 422 &pmc_pcr_lock, 423 name, 424 parent_name, 425 id, &range); 426 } 427 428 if (IS_ERR(hw)) 429 continue; 430 431 of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw); 432 } 433 } 434 435 static void __init of_at91rm9200_clk_periph_setup(struct device_node *np) 436 { 437 of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200); 438 } 439 CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral", 440 of_at91rm9200_clk_periph_setup); 441 442 static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np) 443 { 444 of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5); 445 } 446 CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral", 447 of_at91sam9x5_clk_periph_setup); 448 449