597 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>4 */5 6#include <linux/clk-provider.h>7#include <linux/clkdev.h>8#include <linux/clk/at91_pmc.h>9#include <linux/delay.h>10#include <linux/mfd/syscon.h>11#include <linux/regmap.h>12 13#include "pmc.h"14 15#define SLOW_CLOCK_FREQ 3276816#define MAINF_DIV 1617#define MAINFRDY_TIMEOUT (((MAINF_DIV + 1) * USEC_PER_SEC) / \18 SLOW_CLOCK_FREQ)19#define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ)20#define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT21 22#define MOR_KEY_MASK (0xff << 16)23 24#define clk_main_parent_select(s) (((s) & \25 (AT91_PMC_MOSCEN | \26 AT91_PMC_OSCBYPASS)) ? 1 : 0)27 28struct clk_main_osc {29 struct clk_hw hw;30 struct regmap *regmap;31 struct at91_clk_pms pms;32};33 34#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)35 36struct clk_main_rc_osc {37 struct clk_hw hw;38 struct regmap *regmap;39 unsigned long frequency;40 unsigned long accuracy;41 struct at91_clk_pms pms;42};43 44#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)45 46struct clk_rm9200_main {47 struct clk_hw hw;48 struct regmap *regmap;49};50 51#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)52 53struct clk_sam9x5_main {54 struct clk_hw hw;55 struct regmap *regmap;56 struct at91_clk_pms pms;57 u8 parent;58};59 60#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)61 62static inline bool clk_main_osc_ready(struct regmap *regmap)63{64 unsigned int status;65 66 regmap_read(regmap, AT91_PMC_SR, &status);67 68 return status & AT91_PMC_MOSCS;69}70 71static int clk_main_osc_prepare(struct clk_hw *hw)72{73 struct clk_main_osc *osc = to_clk_main_osc(hw);74 struct regmap *regmap = osc->regmap;75 u32 tmp;76 77 regmap_read(regmap, AT91_CKGR_MOR, &tmp);78 tmp &= ~MOR_KEY_MASK;79 80 if (tmp & AT91_PMC_OSCBYPASS)81 return 0;82 83 if (!(tmp & AT91_PMC_MOSCEN)) {84 tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;85 regmap_write(regmap, AT91_CKGR_MOR, tmp);86 }87 88 while (!clk_main_osc_ready(regmap))89 cpu_relax();90 91 return 0;92}93 94static void clk_main_osc_unprepare(struct clk_hw *hw)95{96 struct clk_main_osc *osc = to_clk_main_osc(hw);97 struct regmap *regmap = osc->regmap;98 u32 tmp;99 100 regmap_read(regmap, AT91_CKGR_MOR, &tmp);101 if (tmp & AT91_PMC_OSCBYPASS)102 return;103 104 if (!(tmp & AT91_PMC_MOSCEN))105 return;106 107 tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);108 regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);109}110 111static int clk_main_osc_is_prepared(struct clk_hw *hw)112{113 struct clk_main_osc *osc = to_clk_main_osc(hw);114 struct regmap *regmap = osc->regmap;115 u32 tmp, status;116 117 regmap_read(regmap, AT91_CKGR_MOR, &tmp);118 if (tmp & AT91_PMC_OSCBYPASS)119 return 1;120 121 regmap_read(regmap, AT91_PMC_SR, &status);122 123 return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);124}125 126static int clk_main_osc_save_context(struct clk_hw *hw)127{128 struct clk_main_osc *osc = to_clk_main_osc(hw);129 130 osc->pms.status = clk_main_osc_is_prepared(hw);131 132 return 0;133}134 135static void clk_main_osc_restore_context(struct clk_hw *hw)136{137 struct clk_main_osc *osc = to_clk_main_osc(hw);138 139 if (osc->pms.status)140 clk_main_osc_prepare(hw);141}142 143static const struct clk_ops main_osc_ops = {144 .prepare = clk_main_osc_prepare,145 .unprepare = clk_main_osc_unprepare,146 .is_prepared = clk_main_osc_is_prepared,147 .save_context = clk_main_osc_save_context,148 .restore_context = clk_main_osc_restore_context,149};150 151struct clk_hw * __init152at91_clk_register_main_osc(struct regmap *regmap,153 const char *name,154 const char *parent_name,155 struct clk_parent_data *parent_data,156 bool bypass)157{158 struct clk_main_osc *osc;159 struct clk_init_data init = {};160 struct clk_hw *hw;161 int ret;162 163 if (!name || !(parent_name || parent_data))164 return ERR_PTR(-EINVAL);165 166 osc = kzalloc(sizeof(*osc), GFP_KERNEL);167 if (!osc)168 return ERR_PTR(-ENOMEM);169 170 init.name = name;171 init.ops = &main_osc_ops;172 if (parent_data)173 init.parent_data = (const struct clk_parent_data *)parent_data;174 else175 init.parent_names = &parent_name;176 init.num_parents = 1;177 init.flags = CLK_IGNORE_UNUSED;178 179 osc->hw.init = &init;180 osc->regmap = regmap;181 182 if (bypass)183 regmap_update_bits(regmap,184 AT91_CKGR_MOR, MOR_KEY_MASK |185 AT91_PMC_OSCBYPASS,186 AT91_PMC_OSCBYPASS | AT91_PMC_KEY);187 188 hw = &osc->hw;189 ret = clk_hw_register(NULL, &osc->hw);190 if (ret) {191 kfree(osc);192 hw = ERR_PTR(ret);193 }194 195 return hw;196}197 198static bool clk_main_rc_osc_ready(struct regmap *regmap)199{200 unsigned int status;201 202 regmap_read(regmap, AT91_PMC_SR, &status);203 204 return !!(status & AT91_PMC_MOSCRCS);205}206 207static int clk_main_rc_osc_prepare(struct clk_hw *hw)208{209 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);210 struct regmap *regmap = osc->regmap;211 unsigned int mor;212 213 regmap_read(regmap, AT91_CKGR_MOR, &mor);214 215 if (!(mor & AT91_PMC_MOSCRCEN))216 regmap_update_bits(regmap, AT91_CKGR_MOR,217 MOR_KEY_MASK | AT91_PMC_MOSCRCEN,218 AT91_PMC_MOSCRCEN | AT91_PMC_KEY);219 220 while (!clk_main_rc_osc_ready(regmap))221 cpu_relax();222 223 return 0;224}225 226static void clk_main_rc_osc_unprepare(struct clk_hw *hw)227{228 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);229 struct regmap *regmap = osc->regmap;230 unsigned int mor;231 232 regmap_read(regmap, AT91_CKGR_MOR, &mor);233 234 if (!(mor & AT91_PMC_MOSCRCEN))235 return;236 237 regmap_update_bits(regmap, AT91_CKGR_MOR,238 MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);239}240 241static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)242{243 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);244 struct regmap *regmap = osc->regmap;245 unsigned int mor, status;246 247 regmap_read(regmap, AT91_CKGR_MOR, &mor);248 regmap_read(regmap, AT91_PMC_SR, &status);249 250 return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);251}252 253static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,254 unsigned long parent_rate)255{256 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);257 258 return osc->frequency;259}260 261static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,262 unsigned long parent_acc)263{264 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);265 266 return osc->accuracy;267}268 269static int clk_main_rc_osc_save_context(struct clk_hw *hw)270{271 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);272 273 osc->pms.status = clk_main_rc_osc_is_prepared(hw);274 275 return 0;276}277 278static void clk_main_rc_osc_restore_context(struct clk_hw *hw)279{280 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);281 282 if (osc->pms.status)283 clk_main_rc_osc_prepare(hw);284}285 286static const struct clk_ops main_rc_osc_ops = {287 .prepare = clk_main_rc_osc_prepare,288 .unprepare = clk_main_rc_osc_unprepare,289 .is_prepared = clk_main_rc_osc_is_prepared,290 .recalc_rate = clk_main_rc_osc_recalc_rate,291 .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,292 .save_context = clk_main_rc_osc_save_context,293 .restore_context = clk_main_rc_osc_restore_context,294};295 296struct clk_hw * __init297at91_clk_register_main_rc_osc(struct regmap *regmap,298 const char *name,299 u32 frequency, u32 accuracy)300{301 struct clk_main_rc_osc *osc;302 struct clk_init_data init;303 struct clk_hw *hw;304 int ret;305 306 if (!name || !frequency)307 return ERR_PTR(-EINVAL);308 309 osc = kzalloc(sizeof(*osc), GFP_KERNEL);310 if (!osc)311 return ERR_PTR(-ENOMEM);312 313 init.name = name;314 init.ops = &main_rc_osc_ops;315 init.parent_names = NULL;316 init.num_parents = 0;317 init.flags = CLK_IGNORE_UNUSED;318 319 osc->hw.init = &init;320 osc->regmap = regmap;321 osc->frequency = frequency;322 osc->accuracy = accuracy;323 324 hw = &osc->hw;325 ret = clk_hw_register(NULL, hw);326 if (ret) {327 kfree(osc);328 hw = ERR_PTR(ret);329 }330 331 return hw;332}333 334static int clk_main_probe_frequency(struct regmap *regmap)335{336 unsigned long prep_time, timeout;337 unsigned int mcfr;338 339 timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);340 do {341 prep_time = jiffies;342 regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);343 if (mcfr & AT91_PMC_MAINRDY)344 return 0;345 if (system_state < SYSTEM_RUNNING)346 udelay(MAINF_LOOP_MIN_WAIT);347 else348 usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);349 } while (time_before(prep_time, timeout));350 351 return -ETIMEDOUT;352}353 354static unsigned long clk_main_recalc_rate(struct regmap *regmap,355 unsigned long parent_rate)356{357 unsigned int mcfr;358 359 if (parent_rate)360 return parent_rate;361 362 pr_warn("Main crystal frequency not set, using approximate value\n");363 regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);364 if (!(mcfr & AT91_PMC_MAINRDY))365 return 0;366 367 return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;368}369 370static int clk_rm9200_main_prepare(struct clk_hw *hw)371{372 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);373 374 return clk_main_probe_frequency(clkmain->regmap);375}376 377static int clk_rm9200_main_is_prepared(struct clk_hw *hw)378{379 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);380 unsigned int status;381 382 regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);383 384 return !!(status & AT91_PMC_MAINRDY);385}386 387static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,388 unsigned long parent_rate)389{390 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);391 392 return clk_main_recalc_rate(clkmain->regmap, parent_rate);393}394 395static const struct clk_ops rm9200_main_ops = {396 .prepare = clk_rm9200_main_prepare,397 .is_prepared = clk_rm9200_main_is_prepared,398 .recalc_rate = clk_rm9200_main_recalc_rate,399};400 401struct clk_hw * __init402at91_clk_register_rm9200_main(struct regmap *regmap,403 const char *name,404 const char *parent_name,405 struct clk_hw *parent_hw)406{407 struct clk_rm9200_main *clkmain;408 struct clk_init_data init = {};409 struct clk_hw *hw;410 int ret;411 412 if (!name)413 return ERR_PTR(-EINVAL);414 415 if (!(parent_name || parent_hw))416 return ERR_PTR(-EINVAL);417 418 clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);419 if (!clkmain)420 return ERR_PTR(-ENOMEM);421 422 init.name = name;423 init.ops = &rm9200_main_ops;424 if (parent_hw)425 init.parent_hws = (const struct clk_hw **)&parent_hw;426 else427 init.parent_names = &parent_name;428 init.num_parents = 1;429 init.flags = 0;430 431 clkmain->hw.init = &init;432 clkmain->regmap = regmap;433 434 hw = &clkmain->hw;435 ret = clk_hw_register(NULL, &clkmain->hw);436 if (ret) {437 kfree(clkmain);438 hw = ERR_PTR(ret);439 }440 441 return hw;442}443 444static inline bool clk_sam9x5_main_ready(struct regmap *regmap)445{446 unsigned int status;447 448 regmap_read(regmap, AT91_PMC_SR, &status);449 450 return !!(status & AT91_PMC_MOSCSELS);451}452 453static int clk_sam9x5_main_prepare(struct clk_hw *hw)454{455 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);456 struct regmap *regmap = clkmain->regmap;457 458 while (!clk_sam9x5_main_ready(regmap))459 cpu_relax();460 461 return clk_main_probe_frequency(regmap);462}463 464static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)465{466 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);467 468 return clk_sam9x5_main_ready(clkmain->regmap);469}470 471static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,472 unsigned long parent_rate)473{474 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);475 476 return clk_main_recalc_rate(clkmain->regmap, parent_rate);477}478 479static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)480{481 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);482 struct regmap *regmap = clkmain->regmap;483 unsigned int tmp;484 485 if (index > 1)486 return -EINVAL;487 488 regmap_read(regmap, AT91_CKGR_MOR, &tmp);489 490 if (index && !(tmp & AT91_PMC_MOSCSEL))491 tmp = AT91_PMC_MOSCSEL;492 else if (!index && (tmp & AT91_PMC_MOSCSEL))493 tmp = 0;494 else495 return 0;496 497 regmap_update_bits(regmap, AT91_CKGR_MOR,498 AT91_PMC_MOSCSEL | MOR_KEY_MASK,499 tmp | AT91_PMC_KEY);500 501 while (!clk_sam9x5_main_ready(regmap))502 cpu_relax();503 504 return 0;505}506 507static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)508{509 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);510 unsigned int status;511 512 regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);513 514 return clk_main_parent_select(status);515}516 517static int clk_sam9x5_main_save_context(struct clk_hw *hw)518{519 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);520 521 clkmain->pms.status = clk_main_rc_osc_is_prepared(&clkmain->hw);522 clkmain->pms.parent = clk_sam9x5_main_get_parent(&clkmain->hw);523 524 return 0;525}526 527static void clk_sam9x5_main_restore_context(struct clk_hw *hw)528{529 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);530 int ret;531 532 ret = clk_sam9x5_main_set_parent(hw, clkmain->pms.parent);533 if (ret)534 return;535 536 if (clkmain->pms.status)537 clk_sam9x5_main_prepare(hw);538}539 540static const struct clk_ops sam9x5_main_ops = {541 .prepare = clk_sam9x5_main_prepare,542 .is_prepared = clk_sam9x5_main_is_prepared,543 .recalc_rate = clk_sam9x5_main_recalc_rate,544 .determine_rate = clk_hw_determine_rate_no_reparent,545 .set_parent = clk_sam9x5_main_set_parent,546 .get_parent = clk_sam9x5_main_get_parent,547 .save_context = clk_sam9x5_main_save_context,548 .restore_context = clk_sam9x5_main_restore_context,549};550 551struct clk_hw * __init552at91_clk_register_sam9x5_main(struct regmap *regmap,553 const char *name,554 const char **parent_names,555 struct clk_hw **parent_hws,556 int num_parents)557{558 struct clk_sam9x5_main *clkmain;559 struct clk_init_data init = {};560 unsigned int status;561 struct clk_hw *hw;562 int ret;563 564 if (!name)565 return ERR_PTR(-EINVAL);566 567 if (!(parent_hws || parent_names) || !num_parents)568 return ERR_PTR(-EINVAL);569 570 clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);571 if (!clkmain)572 return ERR_PTR(-ENOMEM);573 574 init.name = name;575 init.ops = &sam9x5_main_ops;576 if (parent_hws)577 init.parent_hws = (const struct clk_hw **)parent_hws;578 else579 init.parent_names = parent_names;580 init.num_parents = num_parents;581 init.flags = CLK_SET_PARENT_GATE;582 583 clkmain->hw.init = &init;584 clkmain->regmap = regmap;585 regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);586 clkmain->parent = clk_main_parent_select(status);587 588 hw = &clkmain->hw;589 ret = clk_hw_register(NULL, &clkmain->hw);590 if (ret) {591 kfree(clkmain);592 hw = ERR_PTR(ret);593 }594 595 return hw;596}597