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 * __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 *clk = NULL; 113 struct clk_init_data init; 114 115 if (!name || !parent_name || id > PERIPHERAL_ID_MAX) 116 return ERR_PTR(-EINVAL); 117 118 periph = kzalloc(sizeof(*periph), GFP_KERNEL); 119 if (!periph) 120 return ERR_PTR(-ENOMEM); 121 122 init.name = name; 123 init.ops = &peripheral_ops; 124 init.parent_names = (parent_name ? &parent_name : NULL); 125 init.num_parents = (parent_name ? 1 : 0); 126 init.flags = 0; 127 128 periph->id = id; 129 periph->hw.init = &init; 130 periph->regmap = regmap; 131 132 clk = clk_register(NULL, &periph->hw); 133 if (IS_ERR(clk)) 134 kfree(periph); 135 136 return clk; 137 } 138 139 static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph) 140 { 141 struct clk_hw *parent; 142 unsigned long parent_rate; 143 int shift = 0; 144 145 if (!periph->auto_div) 146 return; 147 148 if (periph->range.max) { 149 parent = clk_hw_get_parent_by_index(&periph->hw, 0); 150 parent_rate = clk_hw_get_rate(parent); 151 if (!parent_rate) 152 return; 153 154 for (; shift < PERIPHERAL_MAX_SHIFT; shift++) { 155 if (parent_rate >> shift <= periph->range.max) 156 break; 157 } 158 } 159 160 periph->auto_div = false; 161 periph->div = shift; 162 } 163 164 static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) 165 { 166 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 167 unsigned long flags; 168 169 if (periph->id < PERIPHERAL_ID_MIN) 170 return 0; 171 172 spin_lock_irqsave(periph->lock, flags); 173 regmap_write(periph->regmap, AT91_PMC_PCR, 174 (periph->id & AT91_PMC_PCR_PID_MASK)); 175 regmap_update_bits(periph->regmap, AT91_PMC_PCR, 176 AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD | 177 AT91_PMC_PCR_EN, 178 AT91_PMC_PCR_DIV(periph->div) | 179 AT91_PMC_PCR_CMD | 180 AT91_PMC_PCR_EN); 181 spin_unlock_irqrestore(periph->lock, flags); 182 183 return 0; 184 } 185 186 static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) 187 { 188 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 189 unsigned long flags; 190 191 if (periph->id < PERIPHERAL_ID_MIN) 192 return; 193 194 spin_lock_irqsave(periph->lock, flags); 195 regmap_write(periph->regmap, AT91_PMC_PCR, 196 (periph->id & AT91_PMC_PCR_PID_MASK)); 197 regmap_update_bits(periph->regmap, AT91_PMC_PCR, 198 AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD, 199 AT91_PMC_PCR_CMD); 200 spin_unlock_irqrestore(periph->lock, flags); 201 } 202 203 static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) 204 { 205 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 206 unsigned long flags; 207 unsigned int status; 208 209 if (periph->id < PERIPHERAL_ID_MIN) 210 return 1; 211 212 spin_lock_irqsave(periph->lock, flags); 213 regmap_write(periph->regmap, AT91_PMC_PCR, 214 (periph->id & AT91_PMC_PCR_PID_MASK)); 215 regmap_read(periph->regmap, AT91_PMC_PCR, &status); 216 spin_unlock_irqrestore(periph->lock, flags); 217 218 return status & AT91_PMC_PCR_EN ? 1 : 0; 219 } 220 221 static unsigned long 222 clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, 223 unsigned long parent_rate) 224 { 225 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 226 unsigned long flags; 227 unsigned int status; 228 229 if (periph->id < PERIPHERAL_ID_MIN) 230 return parent_rate; 231 232 spin_lock_irqsave(periph->lock, flags); 233 regmap_write(periph->regmap, AT91_PMC_PCR, 234 (periph->id & AT91_PMC_PCR_PID_MASK)); 235 regmap_read(periph->regmap, AT91_PMC_PCR, &status); 236 spin_unlock_irqrestore(periph->lock, flags); 237 238 if (status & AT91_PMC_PCR_EN) { 239 periph->div = PERIPHERAL_RSHIFT(status); 240 periph->auto_div = false; 241 } else { 242 clk_sam9x5_peripheral_autodiv(periph); 243 } 244 245 return parent_rate >> periph->div; 246 } 247 248 static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw, 249 unsigned long rate, 250 unsigned long *parent_rate) 251 { 252 int shift = 0; 253 unsigned long best_rate; 254 unsigned long best_diff; 255 unsigned long cur_rate = *parent_rate; 256 unsigned long cur_diff; 257 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 258 259 if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) 260 return *parent_rate; 261 262 if (periph->range.max) { 263 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) { 264 cur_rate = *parent_rate >> shift; 265 if (cur_rate <= periph->range.max) 266 break; 267 } 268 } 269 270 if (rate >= cur_rate) 271 return cur_rate; 272 273 best_diff = cur_rate - rate; 274 best_rate = cur_rate; 275 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) { 276 cur_rate = *parent_rate >> shift; 277 if (cur_rate < rate) 278 cur_diff = rate - cur_rate; 279 else 280 cur_diff = cur_rate - rate; 281 282 if (cur_diff < best_diff) { 283 best_diff = cur_diff; 284 best_rate = cur_rate; 285 } 286 287 if (!best_diff || cur_rate < rate) 288 break; 289 } 290 291 return best_rate; 292 } 293 294 static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw, 295 unsigned long rate, 296 unsigned long parent_rate) 297 { 298 int shift; 299 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); 300 if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) { 301 if (parent_rate == rate) 302 return 0; 303 else 304 return -EINVAL; 305 } 306 307 if (periph->range.max && rate > periph->range.max) 308 return -EINVAL; 309 310 for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) { 311 if (parent_rate >> shift == rate) { 312 periph->auto_div = false; 313 periph->div = shift; 314 return 0; 315 } 316 } 317 318 return -EINVAL; 319 } 320 321 static const struct clk_ops sam9x5_peripheral_ops = { 322 .enable = clk_sam9x5_peripheral_enable, 323 .disable = clk_sam9x5_peripheral_disable, 324 .is_enabled = clk_sam9x5_peripheral_is_enabled, 325 .recalc_rate = clk_sam9x5_peripheral_recalc_rate, 326 .round_rate = clk_sam9x5_peripheral_round_rate, 327 .set_rate = clk_sam9x5_peripheral_set_rate, 328 }; 329 330 static struct clk * __init 331 at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, 332 const char *name, const char *parent_name, 333 u32 id, const struct clk_range *range) 334 { 335 struct clk_sam9x5_peripheral *periph; 336 struct clk *clk = NULL; 337 struct clk_init_data init; 338 339 if (!name || !parent_name) 340 return ERR_PTR(-EINVAL); 341 342 periph = kzalloc(sizeof(*periph), GFP_KERNEL); 343 if (!periph) 344 return ERR_PTR(-ENOMEM); 345 346 init.name = name; 347 init.ops = &sam9x5_peripheral_ops; 348 init.parent_names = (parent_name ? &parent_name : NULL); 349 init.num_parents = (parent_name ? 1 : 0); 350 init.flags = 0; 351 352 periph->id = id; 353 periph->hw.init = &init; 354 periph->div = 0; 355 periph->regmap = regmap; 356 periph->lock = lock; 357 periph->auto_div = true; 358 periph->range = *range; 359 360 clk = clk_register(NULL, &periph->hw); 361 if (IS_ERR(clk)) 362 kfree(periph); 363 else 364 clk_sam9x5_peripheral_autodiv(periph); 365 366 return clk; 367 } 368 369 static void __init 370 of_at91_clk_periph_setup(struct device_node *np, u8 type) 371 { 372 int num; 373 u32 id; 374 struct clk *clk; 375 const char *parent_name; 376 const char *name; 377 struct device_node *periphclknp; 378 struct regmap *regmap; 379 380 parent_name = of_clk_get_parent_name(np, 0); 381 if (!parent_name) 382 return; 383 384 num = of_get_child_count(np); 385 if (!num || num > PERIPHERAL_MAX) 386 return; 387 388 regmap = syscon_node_to_regmap(of_get_parent(np)); 389 if (IS_ERR(regmap)) 390 return; 391 392 for_each_child_of_node(np, periphclknp) { 393 if (of_property_read_u32(periphclknp, "reg", &id)) 394 continue; 395 396 if (id >= PERIPHERAL_MAX) 397 continue; 398 399 if (of_property_read_string(np, "clock-output-names", &name)) 400 name = periphclknp->name; 401 402 if (type == PERIPHERAL_AT91RM9200) { 403 clk = at91_clk_register_peripheral(regmap, name, 404 parent_name, id); 405 } else { 406 struct clk_range range = CLK_RANGE(0, 0); 407 408 of_at91_get_clk_range(periphclknp, 409 "atmel,clk-output-range", 410 &range); 411 412 clk = at91_clk_register_sam9x5_peripheral(regmap, 413 &pmc_pcr_lock, 414 name, 415 parent_name, 416 id, &range); 417 } 418 419 if (IS_ERR(clk)) 420 continue; 421 422 of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk); 423 } 424 } 425 426 static void __init of_at91rm9200_clk_periph_setup(struct device_node *np) 427 { 428 of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200); 429 } 430 CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral", 431 of_at91rm9200_clk_periph_setup); 432 433 static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np) 434 { 435 of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5); 436 } 437 CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral", 438 of_at91sam9x5_clk_periph_setup); 439 440