312 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Microchip Image Sensor Controller (ISC) common clock driver setup4 *5 * Copyright (C) 2016 Microchip Technology, Inc.6 *7 * Author: Songjun Wu8 * Author: Eugen Hristev <eugen.hristev@microchip.com>9 *10 */11#include <linux/clk.h>12#include <linux/clkdev.h>13#include <linux/clk-provider.h>14#include <linux/pm_runtime.h>15#include <linux/regmap.h>16 17#include "microchip-isc-regs.h"18#include "microchip-isc.h"19 20static int isc_wait_clk_stable(struct clk_hw *hw)21{22 struct isc_clk *isc_clk = to_isc_clk(hw);23 struct regmap *regmap = isc_clk->regmap;24 unsigned long timeout = jiffies + usecs_to_jiffies(1000);25 unsigned int status;26 27 while (time_before(jiffies, timeout)) {28 regmap_read(regmap, ISC_CLKSR, &status);29 if (!(status & ISC_CLKSR_SIP))30 return 0;31 32 usleep_range(10, 250);33 }34 35 return -ETIMEDOUT;36}37 38static int isc_clk_prepare(struct clk_hw *hw)39{40 struct isc_clk *isc_clk = to_isc_clk(hw);41 int ret;42 43 ret = pm_runtime_resume_and_get(isc_clk->dev);44 if (ret < 0)45 return ret;46 47 return isc_wait_clk_stable(hw);48}49 50static void isc_clk_unprepare(struct clk_hw *hw)51{52 struct isc_clk *isc_clk = to_isc_clk(hw);53 54 isc_wait_clk_stable(hw);55 56 pm_runtime_put_sync(isc_clk->dev);57}58 59static int isc_clk_enable(struct clk_hw *hw)60{61 struct isc_clk *isc_clk = to_isc_clk(hw);62 u32 id = isc_clk->id;63 struct regmap *regmap = isc_clk->regmap;64 unsigned long flags;65 unsigned int status;66 67 dev_dbg(isc_clk->dev, "ISC CLK: %s, id = %d, div = %d, parent id = %d\n",68 __func__, id, isc_clk->div, isc_clk->parent_id);69 70 spin_lock_irqsave(&isc_clk->lock, flags);71 regmap_update_bits(regmap, ISC_CLKCFG,72 ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id),73 (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) |74 (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id)));75 76 regmap_write(regmap, ISC_CLKEN, ISC_CLK(id));77 spin_unlock_irqrestore(&isc_clk->lock, flags);78 79 regmap_read(regmap, ISC_CLKSR, &status);80 if (status & ISC_CLK(id))81 return 0;82 else83 return -EINVAL;84}85 86static void isc_clk_disable(struct clk_hw *hw)87{88 struct isc_clk *isc_clk = to_isc_clk(hw);89 u32 id = isc_clk->id;90 unsigned long flags;91 92 spin_lock_irqsave(&isc_clk->lock, flags);93 regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id));94 spin_unlock_irqrestore(&isc_clk->lock, flags);95}96 97static int isc_clk_is_enabled(struct clk_hw *hw)98{99 struct isc_clk *isc_clk = to_isc_clk(hw);100 u32 status;101 int ret;102 103 ret = pm_runtime_resume_and_get(isc_clk->dev);104 if (ret < 0)105 return 0;106 107 regmap_read(isc_clk->regmap, ISC_CLKSR, &status);108 109 pm_runtime_put_sync(isc_clk->dev);110 111 return status & ISC_CLK(isc_clk->id) ? 1 : 0;112}113 114static unsigned long115isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)116{117 struct isc_clk *isc_clk = to_isc_clk(hw);118 119 return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1);120}121 122static int isc_clk_determine_rate(struct clk_hw *hw,123 struct clk_rate_request *req)124{125 struct isc_clk *isc_clk = to_isc_clk(hw);126 long best_rate = -EINVAL;127 int best_diff = -1;128 unsigned int i, div;129 130 for (i = 0; i < clk_hw_get_num_parents(hw); i++) {131 struct clk_hw *parent;132 unsigned long parent_rate;133 134 parent = clk_hw_get_parent_by_index(hw, i);135 if (!parent)136 continue;137 138 parent_rate = clk_hw_get_rate(parent);139 if (!parent_rate)140 continue;141 142 for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) {143 unsigned long rate;144 int diff;145 146 rate = DIV_ROUND_CLOSEST(parent_rate, div);147 diff = abs(req->rate - rate);148 149 if (best_diff < 0 || best_diff > diff) {150 best_rate = rate;151 best_diff = diff;152 req->best_parent_rate = parent_rate;153 req->best_parent_hw = parent;154 }155 156 if (!best_diff || rate < req->rate)157 break;158 }159 160 if (!best_diff)161 break;162 }163 164 dev_dbg(isc_clk->dev,165 "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",166 __func__, best_rate,167 __clk_get_name((req->best_parent_hw)->clk),168 req->best_parent_rate);169 170 if (best_rate < 0)171 return best_rate;172 173 req->rate = best_rate;174 175 return 0;176}177 178static int isc_clk_set_parent(struct clk_hw *hw, u8 index)179{180 struct isc_clk *isc_clk = to_isc_clk(hw);181 182 if (index >= clk_hw_get_num_parents(hw))183 return -EINVAL;184 185 isc_clk->parent_id = index;186 187 return 0;188}189 190static u8 isc_clk_get_parent(struct clk_hw *hw)191{192 struct isc_clk *isc_clk = to_isc_clk(hw);193 194 return isc_clk->parent_id;195}196 197static int isc_clk_set_rate(struct clk_hw *hw,198 unsigned long rate,199 unsigned long parent_rate)200{201 struct isc_clk *isc_clk = to_isc_clk(hw);202 u32 div;203 204 if (!rate)205 return -EINVAL;206 207 div = DIV_ROUND_CLOSEST(parent_rate, rate);208 if (div > (ISC_CLK_MAX_DIV + 1) || !div)209 return -EINVAL;210 211 isc_clk->div = div - 1;212 213 return 0;214}215 216static const struct clk_ops isc_clk_ops = {217 .prepare = isc_clk_prepare,218 .unprepare = isc_clk_unprepare,219 .enable = isc_clk_enable,220 .disable = isc_clk_disable,221 .is_enabled = isc_clk_is_enabled,222 .recalc_rate = isc_clk_recalc_rate,223 .determine_rate = isc_clk_determine_rate,224 .set_parent = isc_clk_set_parent,225 .get_parent = isc_clk_get_parent,226 .set_rate = isc_clk_set_rate,227};228 229static int isc_clk_register(struct isc_device *isc, unsigned int id)230{231 struct regmap *regmap = isc->regmap;232 struct device_node *np = isc->dev->of_node;233 struct isc_clk *isc_clk;234 struct clk_init_data init;235 const char *clk_name = np->name;236 const char *parent_names[3];237 int num_parents;238 239 if (id == ISC_ISPCK && !isc->ispck_required)240 return 0;241 242 num_parents = of_clk_get_parent_count(np);243 if (num_parents < 1 || num_parents > 3)244 return -EINVAL;245 246 if (num_parents > 2 && id == ISC_ISPCK)247 num_parents = 2;248 249 of_clk_parent_fill(np, parent_names, num_parents);250 251 if (id == ISC_MCK)252 of_property_read_string(np, "clock-output-names", &clk_name);253 else254 clk_name = "isc-ispck";255 256 init.parent_names = parent_names;257 init.num_parents = num_parents;258 init.name = clk_name;259 init.ops = &isc_clk_ops;260 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;261 262 isc_clk = &isc->isc_clks[id];263 isc_clk->hw.init = &init;264 isc_clk->regmap = regmap;265 isc_clk->id = id;266 isc_clk->dev = isc->dev;267 spin_lock_init(&isc_clk->lock);268 269 isc_clk->clk = clk_register(isc->dev, &isc_clk->hw);270 if (IS_ERR(isc_clk->clk)) {271 dev_err(isc->dev, "%s: clock register fail\n", clk_name);272 return PTR_ERR(isc_clk->clk);273 } else if (id == ISC_MCK) {274 of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk);275 }276 277 return 0;278}279 280int microchip_isc_clk_init(struct isc_device *isc)281{282 unsigned int i;283 int ret;284 285 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++)286 isc->isc_clks[i].clk = ERR_PTR(-EINVAL);287 288 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {289 ret = isc_clk_register(isc, i);290 if (ret)291 return ret;292 }293 294 return 0;295}296EXPORT_SYMBOL_GPL(microchip_isc_clk_init);297 298void microchip_isc_clk_cleanup(struct isc_device *isc)299{300 unsigned int i;301 302 of_clk_del_provider(isc->dev->of_node);303 304 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {305 struct isc_clk *isc_clk = &isc->isc_clks[i];306 307 if (!IS_ERR(isc_clk->clk))308 clk_unregister(isc_clk->clk);309 }310}311EXPORT_SYMBOL_GPL(microchip_isc_clk_cleanup);312