1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2017, The Linux Foundation. All rights reserved. 3 */ 4 5 #include <linux/bitops.h> 6 #include <linux/clk.h> 7 #include <linux/clk-provider.h> 8 #include <linux/delay.h> 9 #include <linux/err.h> 10 #include <linux/log2.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 #include <linux/regmap.h> 15 #include <linux/slab.h> 16 #include <linux/types.h> 17 18 #define REG_DIV_CTL1 0x43 19 #define DIV_CTL1_DIV_FACTOR_MASK GENMASK(2, 0) 20 21 #define REG_EN_CTL 0x46 22 #define REG_EN_MASK BIT(7) 23 24 struct clkdiv { 25 struct regmap *regmap; 26 u16 base; 27 spinlock_t lock; 28 29 struct clk_hw hw; 30 unsigned int cxo_period_ns; 31 }; 32 33 static inline struct clkdiv *to_clkdiv(struct clk_hw *hw) 34 { 35 return container_of(hw, struct clkdiv, hw); 36 } 37 38 static inline unsigned int div_factor_to_div(unsigned int div_factor) 39 { 40 if (!div_factor) 41 div_factor = 1; 42 43 return 1 << (div_factor - 1); 44 } 45 46 static inline unsigned int div_to_div_factor(unsigned int div) 47 { 48 return min(ilog2(div) + 1, 7); 49 } 50 51 static bool is_spmi_pmic_clkdiv_enabled(struct clkdiv *clkdiv) 52 { 53 unsigned int val = 0; 54 55 regmap_read(clkdiv->regmap, clkdiv->base + REG_EN_CTL, &val); 56 57 return val & REG_EN_MASK; 58 } 59 60 static int 61 __spmi_pmic_clkdiv_set_enable_state(struct clkdiv *clkdiv, bool enable, 62 unsigned int div_factor) 63 { 64 int ret; 65 unsigned int ns = clkdiv->cxo_period_ns; 66 unsigned int div = div_factor_to_div(div_factor); 67 68 ret = regmap_update_bits(clkdiv->regmap, clkdiv->base + REG_EN_CTL, 69 REG_EN_MASK, enable ? REG_EN_MASK : 0); 70 if (ret) 71 return ret; 72 73 if (enable) 74 ndelay((2 + 3 * div) * ns); 75 else 76 ndelay(3 * div * ns); 77 78 return 0; 79 } 80 81 static int spmi_pmic_clkdiv_set_enable_state(struct clkdiv *clkdiv, bool enable) 82 { 83 unsigned int div_factor; 84 85 regmap_read(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, &div_factor); 86 div_factor &= DIV_CTL1_DIV_FACTOR_MASK; 87 88 return __spmi_pmic_clkdiv_set_enable_state(clkdiv, enable, div_factor); 89 } 90 91 static int clk_spmi_pmic_div_enable(struct clk_hw *hw) 92 { 93 struct clkdiv *clkdiv = to_clkdiv(hw); 94 unsigned long flags; 95 int ret; 96 97 spin_lock_irqsave(&clkdiv->lock, flags); 98 ret = spmi_pmic_clkdiv_set_enable_state(clkdiv, true); 99 spin_unlock_irqrestore(&clkdiv->lock, flags); 100 101 return ret; 102 } 103 104 static void clk_spmi_pmic_div_disable(struct clk_hw *hw) 105 { 106 struct clkdiv *clkdiv = to_clkdiv(hw); 107 unsigned long flags; 108 109 spin_lock_irqsave(&clkdiv->lock, flags); 110 spmi_pmic_clkdiv_set_enable_state(clkdiv, false); 111 spin_unlock_irqrestore(&clkdiv->lock, flags); 112 } 113 114 static long clk_spmi_pmic_div_round_rate(struct clk_hw *hw, unsigned long rate, 115 unsigned long *parent_rate) 116 { 117 unsigned int div, div_factor; 118 119 div = DIV_ROUND_UP(*parent_rate, rate); 120 div_factor = div_to_div_factor(div); 121 div = div_factor_to_div(div_factor); 122 123 return *parent_rate / div; 124 } 125 126 static unsigned long 127 clk_spmi_pmic_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 128 { 129 struct clkdiv *clkdiv = to_clkdiv(hw); 130 unsigned int div_factor; 131 132 regmap_read(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, &div_factor); 133 div_factor &= DIV_CTL1_DIV_FACTOR_MASK; 134 135 return parent_rate / div_factor_to_div(div_factor); 136 } 137 138 static int clk_spmi_pmic_div_set_rate(struct clk_hw *hw, unsigned long rate, 139 unsigned long parent_rate) 140 { 141 struct clkdiv *clkdiv = to_clkdiv(hw); 142 unsigned int div_factor = div_to_div_factor(parent_rate / rate); 143 unsigned long flags; 144 bool enabled; 145 int ret; 146 147 spin_lock_irqsave(&clkdiv->lock, flags); 148 enabled = is_spmi_pmic_clkdiv_enabled(clkdiv); 149 if (enabled) { 150 ret = spmi_pmic_clkdiv_set_enable_state(clkdiv, false); 151 if (ret) 152 goto unlock; 153 } 154 155 ret = regmap_update_bits(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, 156 DIV_CTL1_DIV_FACTOR_MASK, div_factor); 157 if (ret) 158 goto unlock; 159 160 if (enabled) 161 ret = __spmi_pmic_clkdiv_set_enable_state(clkdiv, true, 162 div_factor); 163 164 unlock: 165 spin_unlock_irqrestore(&clkdiv->lock, flags); 166 167 return ret; 168 } 169 170 static const struct clk_ops clk_spmi_pmic_div_ops = { 171 .enable = clk_spmi_pmic_div_enable, 172 .disable = clk_spmi_pmic_div_disable, 173 .set_rate = clk_spmi_pmic_div_set_rate, 174 .recalc_rate = clk_spmi_pmic_div_recalc_rate, 175 .round_rate = clk_spmi_pmic_div_round_rate, 176 }; 177 178 struct spmi_pmic_div_clk_cc { 179 int nclks; 180 struct clkdiv clks[]; 181 }; 182 183 static struct clk_hw * 184 spmi_pmic_div_clk_hw_get(struct of_phandle_args *clkspec, void *data) 185 { 186 struct spmi_pmic_div_clk_cc *cc = data; 187 int idx = clkspec->args[0] - 1; /* Start at 1 instead of 0 */ 188 189 if (idx < 0 || idx >= cc->nclks) { 190 pr_err("%s: index value %u is invalid; allowed range [1, %d]\n", 191 __func__, clkspec->args[0], cc->nclks); 192 return ERR_PTR(-EINVAL); 193 } 194 195 return &cc->clks[idx].hw; 196 } 197 198 static int spmi_pmic_clkdiv_probe(struct platform_device *pdev) 199 { 200 struct spmi_pmic_div_clk_cc *cc; 201 struct clk_init_data init = {}; 202 struct clkdiv *clkdiv; 203 struct clk *cxo; 204 struct regmap *regmap; 205 struct device *dev = &pdev->dev; 206 struct device_node *of_node = dev->of_node; 207 struct clk_parent_data parent_data = { .index = 0, }; 208 int nclks, i, ret, cxo_hz; 209 char name[20]; 210 u32 start; 211 212 ret = of_property_read_u32(of_node, "reg", &start); 213 if (ret < 0) { 214 dev_err(dev, "reg property reading failed\n"); 215 return ret; 216 } 217 218 regmap = dev_get_regmap(dev->parent, NULL); 219 if (!regmap) { 220 dev_err(dev, "Couldn't get parent's regmap\n"); 221 return -EINVAL; 222 } 223 224 ret = of_property_read_u32(of_node, "qcom,num-clkdivs", &nclks); 225 if (ret < 0) { 226 dev_err(dev, "qcom,num-clkdivs property reading failed, ret=%d\n", 227 ret); 228 return ret; 229 } 230 231 if (!nclks) 232 return -EINVAL; 233 234 cc = devm_kzalloc(dev, struct_size(cc, clks, nclks), GFP_KERNEL); 235 if (!cc) 236 return -ENOMEM; 237 cc->nclks = nclks; 238 239 cxo = clk_get(dev, "xo"); 240 if (IS_ERR(cxo)) { 241 ret = PTR_ERR(cxo); 242 if (ret != -EPROBE_DEFER) 243 dev_err(dev, "failed to get xo clock\n"); 244 return ret; 245 } 246 cxo_hz = clk_get_rate(cxo); 247 clk_put(cxo); 248 249 init.name = name; 250 init.parent_data = &parent_data; 251 init.num_parents = 1; 252 init.ops = &clk_spmi_pmic_div_ops; 253 254 for (i = 0, clkdiv = cc->clks; i < nclks; i++) { 255 snprintf(name, sizeof(name), "div_clk%d", i + 1); 256 257 spin_lock_init(&clkdiv[i].lock); 258 clkdiv[i].base = start + i * 0x100; 259 clkdiv[i].regmap = regmap; 260 clkdiv[i].cxo_period_ns = NSEC_PER_SEC / cxo_hz; 261 clkdiv[i].hw.init = &init; 262 263 ret = devm_clk_hw_register(dev, &clkdiv[i].hw); 264 if (ret) 265 return ret; 266 } 267 268 return devm_of_clk_add_hw_provider(dev, spmi_pmic_div_clk_hw_get, cc); 269 } 270 271 static const struct of_device_id spmi_pmic_clkdiv_match_table[] = { 272 { .compatible = "qcom,spmi-clkdiv" }, 273 { /* sentinel */ } 274 }; 275 MODULE_DEVICE_TABLE(of, spmi_pmic_clkdiv_match_table); 276 277 static struct platform_driver spmi_pmic_clkdiv_driver = { 278 .driver = { 279 .name = "qcom,spmi-pmic-clkdiv", 280 .of_match_table = spmi_pmic_clkdiv_match_table, 281 }, 282 .probe = spmi_pmic_clkdiv_probe, 283 }; 284 module_platform_driver(spmi_pmic_clkdiv_driver); 285 286 MODULE_DESCRIPTION("QCOM SPMI PMIC clkdiv driver"); 287 MODULE_LICENSE("GPL v2"); 288