1 /* 2 * Copyright 2016 Maxime Ripard 3 * 4 * Maxime Ripard <maxime.ripard@free-electrons.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17 #include <linux/clk.h> 18 #include <linux/clk-provider.h> 19 #include <linux/iopoll.h> 20 #include <linux/slab.h> 21 22 #include "ccu_common.h" 23 #include "ccu_gate.h" 24 #include "ccu_reset.h" 25 26 static DEFINE_SPINLOCK(ccu_lock); 27 28 void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) 29 { 30 void __iomem *addr; 31 u32 reg; 32 33 if (!lock) 34 return; 35 36 if (common->features & CCU_FEATURE_LOCK_REG) 37 addr = common->base + common->lock_reg; 38 else 39 addr = common->base + common->reg; 40 41 WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000)); 42 } 43 44 /* 45 * This clock notifier is called when the frequency of a PLL clock is 46 * changed. In common PLL designs, changes to the dividers take effect 47 * almost immediately, while changes to the multipliers (implemented 48 * as dividers in the feedback loop) take a few cycles to work into 49 * the feedback loop for the PLL to stablize. 50 * 51 * Sometimes when the PLL clock rate is changed, the decrease in the 52 * divider is too much for the decrease in the multiplier to catch up. 53 * The PLL clock rate will spike, and in some cases, might lock up 54 * completely. 55 * 56 * This notifier callback will gate and then ungate the clock, 57 * effectively resetting it, so it proceeds to work. Care must be 58 * taken to reparent consumers to other temporary clocks during the 59 * rate change, and that this notifier callback must be the first 60 * to be registered. 61 */ 62 static int ccu_pll_notifier_cb(struct notifier_block *nb, 63 unsigned long event, void *data) 64 { 65 struct ccu_pll_nb *pll = to_ccu_pll_nb(nb); 66 int ret = 0; 67 68 if (event != POST_RATE_CHANGE) 69 goto out; 70 71 ccu_gate_helper_disable(pll->common, pll->enable); 72 73 ret = ccu_gate_helper_enable(pll->common, pll->enable); 74 if (ret) 75 goto out; 76 77 ccu_helper_wait_for_lock(pll->common, pll->lock); 78 79 out: 80 return notifier_from_errno(ret); 81 } 82 83 int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb) 84 { 85 pll_nb->clk_nb.notifier_call = ccu_pll_notifier_cb; 86 87 return clk_notifier_register(pll_nb->common->hw.clk, 88 &pll_nb->clk_nb); 89 } 90 91 int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, 92 const struct sunxi_ccu_desc *desc) 93 { 94 struct ccu_reset *reset; 95 int i, ret; 96 97 for (i = 0; i < desc->num_ccu_clks; i++) { 98 struct ccu_common *cclk = desc->ccu_clks[i]; 99 100 if (!cclk) 101 continue; 102 103 cclk->base = reg; 104 cclk->lock = &ccu_lock; 105 } 106 107 for (i = 0; i < desc->hw_clks->num ; i++) { 108 struct clk_hw *hw = desc->hw_clks->hws[i]; 109 110 if (!hw) 111 continue; 112 113 ret = clk_hw_register(NULL, hw); 114 if (ret) { 115 pr_err("Couldn't register clock %d - %s\n", 116 i, clk_hw_get_name(hw)); 117 goto err_clk_unreg; 118 } 119 } 120 121 ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, 122 desc->hw_clks); 123 if (ret) 124 goto err_clk_unreg; 125 126 reset = kzalloc(sizeof(*reset), GFP_KERNEL); 127 if (!reset) { 128 ret = -ENOMEM; 129 goto err_alloc_reset; 130 } 131 132 reset->rcdev.of_node = node; 133 reset->rcdev.ops = &ccu_reset_ops; 134 reset->rcdev.owner = THIS_MODULE; 135 reset->rcdev.nr_resets = desc->num_resets; 136 reset->base = reg; 137 reset->lock = &ccu_lock; 138 reset->reset_map = desc->resets; 139 140 ret = reset_controller_register(&reset->rcdev); 141 if (ret) 142 goto err_of_clk_unreg; 143 144 return 0; 145 146 err_of_clk_unreg: 147 kfree(reset); 148 err_alloc_reset: 149 of_clk_del_provider(node); 150 err_clk_unreg: 151 while (--i >= 0) { 152 struct clk_hw *hw = desc->hw_clks->hws[i]; 153 154 if (!hw) 155 continue; 156 clk_hw_unregister(hw); 157 } 158 return ret; 159 } 160