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