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 SAM9X5_USB_DIV_SHIFT 8 21 #define SAM9X5_USB_MAX_DIV 0xf 22 23 #define RM9200_USB_DIV_SHIFT 28 24 #define RM9200_USB_DIV_TAB_SIZE 4 25 26 struct at91sam9x5_clk_usb { 27 struct clk_hw hw; 28 struct regmap *regmap; 29 }; 30 31 #define to_at91sam9x5_clk_usb(hw) \ 32 container_of(hw, struct at91sam9x5_clk_usb, hw) 33 34 struct at91rm9200_clk_usb { 35 struct clk_hw hw; 36 struct regmap *regmap; 37 u32 divisors[4]; 38 }; 39 40 #define to_at91rm9200_clk_usb(hw) \ 41 container_of(hw, struct at91rm9200_clk_usb, hw) 42 43 static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, 44 unsigned long parent_rate) 45 { 46 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 47 unsigned int usbr; 48 u8 usbdiv; 49 50 regmap_read(usb->regmap, AT91_PMC_USB, &usbr); 51 usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; 52 53 return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); 54 } 55 56 static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, 57 struct clk_rate_request *req) 58 { 59 struct clk_hw *parent; 60 long best_rate = -EINVAL; 61 unsigned long tmp_rate; 62 int best_diff = -1; 63 int tmp_diff; 64 int i; 65 66 for (i = 0; i < clk_hw_get_num_parents(hw); i++) { 67 int div; 68 69 parent = clk_hw_get_parent_by_index(hw, i); 70 if (!parent) 71 continue; 72 73 for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) { 74 unsigned long tmp_parent_rate; 75 76 tmp_parent_rate = req->rate * div; 77 tmp_parent_rate = clk_hw_round_rate(parent, 78 tmp_parent_rate); 79 tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); 80 if (tmp_rate < req->rate) 81 tmp_diff = req->rate - tmp_rate; 82 else 83 tmp_diff = tmp_rate - req->rate; 84 85 if (best_diff < 0 || best_diff > tmp_diff) { 86 best_rate = tmp_rate; 87 best_diff = tmp_diff; 88 req->best_parent_rate = tmp_parent_rate; 89 req->best_parent_hw = parent; 90 } 91 92 if (!best_diff || tmp_rate < req->rate) 93 break; 94 } 95 96 if (!best_diff) 97 break; 98 } 99 100 if (best_rate < 0) 101 return best_rate; 102 103 req->rate = best_rate; 104 return 0; 105 } 106 107 static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) 108 { 109 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 110 111 if (index > 1) 112 return -EINVAL; 113 114 regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 115 index ? AT91_PMC_USBS : 0); 116 117 return 0; 118 } 119 120 static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) 121 { 122 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 123 unsigned int usbr; 124 125 regmap_read(usb->regmap, AT91_PMC_USB, &usbr); 126 127 return usbr & AT91_PMC_USBS; 128 } 129 130 static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, 131 unsigned long parent_rate) 132 { 133 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 134 unsigned long div; 135 136 if (!rate) 137 return -EINVAL; 138 139 div = DIV_ROUND_CLOSEST(parent_rate, rate); 140 if (div > SAM9X5_USB_MAX_DIV + 1 || !div) 141 return -EINVAL; 142 143 regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_OHCIUSBDIV, 144 (div - 1) << SAM9X5_USB_DIV_SHIFT); 145 146 return 0; 147 } 148 149 static const struct clk_ops at91sam9x5_usb_ops = { 150 .recalc_rate = at91sam9x5_clk_usb_recalc_rate, 151 .determine_rate = at91sam9x5_clk_usb_determine_rate, 152 .get_parent = at91sam9x5_clk_usb_get_parent, 153 .set_parent = at91sam9x5_clk_usb_set_parent, 154 .set_rate = at91sam9x5_clk_usb_set_rate, 155 }; 156 157 static int at91sam9n12_clk_usb_enable(struct clk_hw *hw) 158 { 159 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 160 161 regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 162 AT91_PMC_USBS); 163 164 return 0; 165 } 166 167 static void at91sam9n12_clk_usb_disable(struct clk_hw *hw) 168 { 169 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 170 171 regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 0); 172 } 173 174 static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw) 175 { 176 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 177 unsigned int usbr; 178 179 regmap_read(usb->regmap, AT91_PMC_USB, &usbr); 180 181 return usbr & AT91_PMC_USBS; 182 } 183 184 static const struct clk_ops at91sam9n12_usb_ops = { 185 .enable = at91sam9n12_clk_usb_enable, 186 .disable = at91sam9n12_clk_usb_disable, 187 .is_enabled = at91sam9n12_clk_usb_is_enabled, 188 .recalc_rate = at91sam9x5_clk_usb_recalc_rate, 189 .determine_rate = at91sam9x5_clk_usb_determine_rate, 190 .set_rate = at91sam9x5_clk_usb_set_rate, 191 }; 192 193 struct clk_hw * __init 194 at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, 195 const char **parent_names, u8 num_parents) 196 { 197 struct at91sam9x5_clk_usb *usb; 198 struct clk_hw *hw; 199 struct clk_init_data init; 200 int ret; 201 202 usb = kzalloc(sizeof(*usb), GFP_KERNEL); 203 if (!usb) 204 return ERR_PTR(-ENOMEM); 205 206 init.name = name; 207 init.ops = &at91sam9x5_usb_ops; 208 init.parent_names = parent_names; 209 init.num_parents = num_parents; 210 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | 211 CLK_SET_RATE_PARENT; 212 213 usb->hw.init = &init; 214 usb->regmap = regmap; 215 216 hw = &usb->hw; 217 ret = clk_hw_register(NULL, &usb->hw); 218 if (ret) { 219 kfree(usb); 220 hw = ERR_PTR(ret); 221 } 222 223 return hw; 224 } 225 226 struct clk_hw * __init 227 at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, 228 const char *parent_name) 229 { 230 struct at91sam9x5_clk_usb *usb; 231 struct clk_hw *hw; 232 struct clk_init_data init; 233 int ret; 234 235 usb = kzalloc(sizeof(*usb), GFP_KERNEL); 236 if (!usb) 237 return ERR_PTR(-ENOMEM); 238 239 init.name = name; 240 init.ops = &at91sam9n12_usb_ops; 241 init.parent_names = &parent_name; 242 init.num_parents = 1; 243 init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT; 244 245 usb->hw.init = &init; 246 usb->regmap = regmap; 247 248 hw = &usb->hw; 249 ret = clk_hw_register(NULL, &usb->hw); 250 if (ret) { 251 kfree(usb); 252 hw = ERR_PTR(ret); 253 } 254 255 return hw; 256 } 257 258 static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw, 259 unsigned long parent_rate) 260 { 261 struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); 262 unsigned int pllbr; 263 u8 usbdiv; 264 265 regmap_read(usb->regmap, AT91_CKGR_PLLBR, &pllbr); 266 267 usbdiv = (pllbr & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT; 268 if (usb->divisors[usbdiv]) 269 return parent_rate / usb->divisors[usbdiv]; 270 271 return 0; 272 } 273 274 static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, 275 unsigned long *parent_rate) 276 { 277 struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); 278 struct clk_hw *parent = clk_hw_get_parent(hw); 279 unsigned long bestrate = 0; 280 int bestdiff = -1; 281 unsigned long tmprate; 282 int tmpdiff; 283 int i = 0; 284 285 for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { 286 unsigned long tmp_parent_rate; 287 288 if (!usb->divisors[i]) 289 continue; 290 291 tmp_parent_rate = rate * usb->divisors[i]; 292 tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate); 293 tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]); 294 if (tmprate < rate) 295 tmpdiff = rate - tmprate; 296 else 297 tmpdiff = tmprate - rate; 298 299 if (bestdiff < 0 || bestdiff > tmpdiff) { 300 bestrate = tmprate; 301 bestdiff = tmpdiff; 302 *parent_rate = tmp_parent_rate; 303 } 304 305 if (!bestdiff) 306 break; 307 } 308 309 return bestrate; 310 } 311 312 static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, 313 unsigned long parent_rate) 314 { 315 int i; 316 struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); 317 unsigned long div; 318 319 if (!rate) 320 return -EINVAL; 321 322 div = DIV_ROUND_CLOSEST(parent_rate, rate); 323 324 for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { 325 if (usb->divisors[i] == div) { 326 regmap_update_bits(usb->regmap, AT91_CKGR_PLLBR, 327 AT91_PMC_USBDIV, 328 i << RM9200_USB_DIV_SHIFT); 329 330 return 0; 331 } 332 } 333 334 return -EINVAL; 335 } 336 337 static const struct clk_ops at91rm9200_usb_ops = { 338 .recalc_rate = at91rm9200_clk_usb_recalc_rate, 339 .round_rate = at91rm9200_clk_usb_round_rate, 340 .set_rate = at91rm9200_clk_usb_set_rate, 341 }; 342 343 struct clk_hw * __init 344 at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, 345 const char *parent_name, const u32 *divisors) 346 { 347 struct at91rm9200_clk_usb *usb; 348 struct clk_hw *hw; 349 struct clk_init_data init; 350 int ret; 351 352 usb = kzalloc(sizeof(*usb), GFP_KERNEL); 353 if (!usb) 354 return ERR_PTR(-ENOMEM); 355 356 init.name = name; 357 init.ops = &at91rm9200_usb_ops; 358 init.parent_names = &parent_name; 359 init.num_parents = 1; 360 init.flags = CLK_SET_RATE_PARENT; 361 362 usb->hw.init = &init; 363 usb->regmap = regmap; 364 memcpy(usb->divisors, divisors, sizeof(usb->divisors)); 365 366 hw = &usb->hw; 367 ret = clk_hw_register(NULL, &usb->hw); 368 if (ret) { 369 kfree(usb); 370 hw = ERR_PTR(ret); 371 } 372 373 return hw; 374 } 375