0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/clk-provider.h>
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include <linux/io.h>
0015 #include <linux/err.h>
0016 #include <linux/string.h>
0017 #include <linux/log2.h>
0018 #include <linux/of.h>
0019 #include <linux/of_address.h>
0020 #include <linux/clk/ti.h>
0021 #include <linux/delay.h>
0022
0023 #include "clock.h"
0024
0025 #define APLL_FORCE_LOCK 0x1
0026 #define APLL_AUTO_IDLE 0x2
0027 #define MAX_APLL_WAIT_TRIES 1000000
0028
0029 #undef pr_fmt
0030 #define pr_fmt(fmt) "%s: " fmt, __func__
0031
0032 static int dra7_apll_enable(struct clk_hw *hw)
0033 {
0034 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0035 int r = 0, i = 0;
0036 struct dpll_data *ad;
0037 const char *clk_name;
0038 u8 state = 1;
0039 u32 v;
0040
0041 ad = clk->dpll_data;
0042 if (!ad)
0043 return -EINVAL;
0044
0045 clk_name = clk_hw_get_name(&clk->hw);
0046
0047 state <<= __ffs(ad->idlest_mask);
0048
0049
0050 v = ti_clk_ll_ops->clk_readl(&ad->idlest_reg);
0051
0052 if ((v & ad->idlest_mask) == state)
0053 return r;
0054
0055 v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
0056 v &= ~ad->enable_mask;
0057 v |= APLL_FORCE_LOCK << __ffs(ad->enable_mask);
0058 ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
0059
0060 state <<= __ffs(ad->idlest_mask);
0061
0062 while (1) {
0063 v = ti_clk_ll_ops->clk_readl(&ad->idlest_reg);
0064 if ((v & ad->idlest_mask) == state)
0065 break;
0066 if (i > MAX_APLL_WAIT_TRIES)
0067 break;
0068 i++;
0069 udelay(1);
0070 }
0071
0072 if (i == MAX_APLL_WAIT_TRIES) {
0073 pr_warn("clock: %s failed transition to '%s'\n",
0074 clk_name, (state) ? "locked" : "bypassed");
0075 r = -EBUSY;
0076 } else
0077 pr_debug("clock: %s transition to '%s' in %d loops\n",
0078 clk_name, (state) ? "locked" : "bypassed", i);
0079
0080 return r;
0081 }
0082
0083 static void dra7_apll_disable(struct clk_hw *hw)
0084 {
0085 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0086 struct dpll_data *ad;
0087 u8 state = 1;
0088 u32 v;
0089
0090 ad = clk->dpll_data;
0091
0092 state <<= __ffs(ad->idlest_mask);
0093
0094 v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
0095 v &= ~ad->enable_mask;
0096 v |= APLL_AUTO_IDLE << __ffs(ad->enable_mask);
0097 ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
0098 }
0099
0100 static int dra7_apll_is_enabled(struct clk_hw *hw)
0101 {
0102 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0103 struct dpll_data *ad;
0104 u32 v;
0105
0106 ad = clk->dpll_data;
0107
0108 v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
0109 v &= ad->enable_mask;
0110
0111 v >>= __ffs(ad->enable_mask);
0112
0113 return v == APLL_AUTO_IDLE ? 0 : 1;
0114 }
0115
0116 static u8 dra7_init_apll_parent(struct clk_hw *hw)
0117 {
0118 return 0;
0119 }
0120
0121 static const struct clk_ops apll_ck_ops = {
0122 .enable = &dra7_apll_enable,
0123 .disable = &dra7_apll_disable,
0124 .is_enabled = &dra7_apll_is_enabled,
0125 .get_parent = &dra7_init_apll_parent,
0126 };
0127
0128 static void __init omap_clk_register_apll(void *user,
0129 struct device_node *node)
0130 {
0131 struct clk_hw *hw = user;
0132 struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
0133 struct dpll_data *ad = clk_hw->dpll_data;
0134 const char *name;
0135 struct clk *clk;
0136 const struct clk_init_data *init = clk_hw->hw.init;
0137
0138 clk = of_clk_get(node, 0);
0139 if (IS_ERR(clk)) {
0140 pr_debug("clk-ref for %pOFn not ready, retry\n",
0141 node);
0142 if (!ti_clk_retry_init(node, hw, omap_clk_register_apll))
0143 return;
0144
0145 goto cleanup;
0146 }
0147
0148 ad->clk_ref = __clk_get_hw(clk);
0149
0150 clk = of_clk_get(node, 1);
0151 if (IS_ERR(clk)) {
0152 pr_debug("clk-bypass for %pOFn not ready, retry\n",
0153 node);
0154 if (!ti_clk_retry_init(node, hw, omap_clk_register_apll))
0155 return;
0156
0157 goto cleanup;
0158 }
0159
0160 ad->clk_bypass = __clk_get_hw(clk);
0161
0162 name = ti_dt_clk_name(node);
0163 clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, name);
0164 if (!IS_ERR(clk)) {
0165 of_clk_add_provider(node, of_clk_src_simple_get, clk);
0166 kfree(init->parent_names);
0167 kfree(init);
0168 return;
0169 }
0170
0171 cleanup:
0172 kfree(clk_hw->dpll_data);
0173 kfree(init->parent_names);
0174 kfree(init);
0175 kfree(clk_hw);
0176 }
0177
0178 static void __init of_dra7_apll_setup(struct device_node *node)
0179 {
0180 struct dpll_data *ad = NULL;
0181 struct clk_hw_omap *clk_hw = NULL;
0182 struct clk_init_data *init = NULL;
0183 const char **parent_names = NULL;
0184 int ret;
0185
0186 ad = kzalloc(sizeof(*ad), GFP_KERNEL);
0187 clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
0188 init = kzalloc(sizeof(*init), GFP_KERNEL);
0189 if (!ad || !clk_hw || !init)
0190 goto cleanup;
0191
0192 clk_hw->dpll_data = ad;
0193 clk_hw->hw.init = init;
0194
0195 init->name = ti_dt_clk_name(node);
0196 init->ops = &apll_ck_ops;
0197
0198 init->num_parents = of_clk_get_parent_count(node);
0199 if (init->num_parents < 1) {
0200 pr_err("dra7 apll %pOFn must have parent(s)\n", node);
0201 goto cleanup;
0202 }
0203
0204 parent_names = kcalloc(init->num_parents, sizeof(char *), GFP_KERNEL);
0205 if (!parent_names)
0206 goto cleanup;
0207
0208 of_clk_parent_fill(node, parent_names, init->num_parents);
0209
0210 init->parent_names = parent_names;
0211
0212 ret = ti_clk_get_reg_addr(node, 0, &ad->control_reg);
0213 ret |= ti_clk_get_reg_addr(node, 1, &ad->idlest_reg);
0214
0215 if (ret)
0216 goto cleanup;
0217
0218 ad->idlest_mask = 0x1;
0219 ad->enable_mask = 0x3;
0220
0221 omap_clk_register_apll(&clk_hw->hw, node);
0222 return;
0223
0224 cleanup:
0225 kfree(parent_names);
0226 kfree(ad);
0227 kfree(clk_hw);
0228 kfree(init);
0229 }
0230 CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup);
0231
0232 #define OMAP2_EN_APLL_LOCKED 0x3
0233 #define OMAP2_EN_APLL_STOPPED 0x0
0234
0235 static int omap2_apll_is_enabled(struct clk_hw *hw)
0236 {
0237 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0238 struct dpll_data *ad = clk->dpll_data;
0239 u32 v;
0240
0241 v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
0242 v &= ad->enable_mask;
0243
0244 v >>= __ffs(ad->enable_mask);
0245
0246 return v == OMAP2_EN_APLL_LOCKED ? 1 : 0;
0247 }
0248
0249 static unsigned long omap2_apll_recalc(struct clk_hw *hw,
0250 unsigned long parent_rate)
0251 {
0252 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0253
0254 if (omap2_apll_is_enabled(hw))
0255 return clk->fixed_rate;
0256
0257 return 0;
0258 }
0259
0260 static int omap2_apll_enable(struct clk_hw *hw)
0261 {
0262 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0263 struct dpll_data *ad = clk->dpll_data;
0264 u32 v;
0265 int i = 0;
0266
0267 v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
0268 v &= ~ad->enable_mask;
0269 v |= OMAP2_EN_APLL_LOCKED << __ffs(ad->enable_mask);
0270 ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
0271
0272 while (1) {
0273 v = ti_clk_ll_ops->clk_readl(&ad->idlest_reg);
0274 if (v & ad->idlest_mask)
0275 break;
0276 if (i > MAX_APLL_WAIT_TRIES)
0277 break;
0278 i++;
0279 udelay(1);
0280 }
0281
0282 if (i == MAX_APLL_WAIT_TRIES) {
0283 pr_warn("%s failed to transition to locked\n",
0284 clk_hw_get_name(&clk->hw));
0285 return -EBUSY;
0286 }
0287
0288 return 0;
0289 }
0290
0291 static void omap2_apll_disable(struct clk_hw *hw)
0292 {
0293 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0294 struct dpll_data *ad = clk->dpll_data;
0295 u32 v;
0296
0297 v = ti_clk_ll_ops->clk_readl(&ad->control_reg);
0298 v &= ~ad->enable_mask;
0299 v |= OMAP2_EN_APLL_STOPPED << __ffs(ad->enable_mask);
0300 ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
0301 }
0302
0303 static const struct clk_ops omap2_apll_ops = {
0304 .enable = &omap2_apll_enable,
0305 .disable = &omap2_apll_disable,
0306 .is_enabled = &omap2_apll_is_enabled,
0307 .recalc_rate = &omap2_apll_recalc,
0308 };
0309
0310 static void omap2_apll_set_autoidle(struct clk_hw_omap *clk, u32 val)
0311 {
0312 struct dpll_data *ad = clk->dpll_data;
0313 u32 v;
0314
0315 v = ti_clk_ll_ops->clk_readl(&ad->autoidle_reg);
0316 v &= ~ad->autoidle_mask;
0317 v |= val << __ffs(ad->autoidle_mask);
0318 ti_clk_ll_ops->clk_writel(v, &ad->control_reg);
0319 }
0320
0321 #define OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP 0x3
0322 #define OMAP2_APLL_AUTOIDLE_DISABLE 0x0
0323
0324 static void omap2_apll_allow_idle(struct clk_hw_omap *clk)
0325 {
0326 omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP);
0327 }
0328
0329 static void omap2_apll_deny_idle(struct clk_hw_omap *clk)
0330 {
0331 omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_DISABLE);
0332 }
0333
0334 static const struct clk_hw_omap_ops omap2_apll_hwops = {
0335 .allow_idle = &omap2_apll_allow_idle,
0336 .deny_idle = &omap2_apll_deny_idle,
0337 };
0338
0339 static void __init of_omap2_apll_setup(struct device_node *node)
0340 {
0341 struct dpll_data *ad = NULL;
0342 struct clk_hw_omap *clk_hw = NULL;
0343 struct clk_init_data *init = NULL;
0344 const char *name;
0345 struct clk *clk;
0346 const char *parent_name;
0347 u32 val;
0348 int ret;
0349
0350 ad = kzalloc(sizeof(*ad), GFP_KERNEL);
0351 clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
0352 init = kzalloc(sizeof(*init), GFP_KERNEL);
0353
0354 if (!ad || !clk_hw || !init)
0355 goto cleanup;
0356
0357 clk_hw->dpll_data = ad;
0358 clk_hw->hw.init = init;
0359 init->ops = &omap2_apll_ops;
0360 name = ti_dt_clk_name(node);
0361 init->name = name;
0362 clk_hw->ops = &omap2_apll_hwops;
0363
0364 init->num_parents = of_clk_get_parent_count(node);
0365 if (init->num_parents != 1) {
0366 pr_err("%pOFn must have one parent\n", node);
0367 goto cleanup;
0368 }
0369
0370 parent_name = of_clk_get_parent_name(node, 0);
0371 init->parent_names = &parent_name;
0372
0373 if (of_property_read_u32(node, "ti,clock-frequency", &val)) {
0374 pr_err("%pOFn missing clock-frequency\n", node);
0375 goto cleanup;
0376 }
0377 clk_hw->fixed_rate = val;
0378
0379 if (of_property_read_u32(node, "ti,bit-shift", &val)) {
0380 pr_err("%pOFn missing bit-shift\n", node);
0381 goto cleanup;
0382 }
0383
0384 clk_hw->enable_bit = val;
0385 ad->enable_mask = 0x3 << val;
0386 ad->autoidle_mask = 0x3 << val;
0387
0388 if (of_property_read_u32(node, "ti,idlest-shift", &val)) {
0389 pr_err("%pOFn missing idlest-shift\n", node);
0390 goto cleanup;
0391 }
0392
0393 ad->idlest_mask = 1 << val;
0394
0395 ret = ti_clk_get_reg_addr(node, 0, &ad->control_reg);
0396 ret |= ti_clk_get_reg_addr(node, 1, &ad->autoidle_reg);
0397 ret |= ti_clk_get_reg_addr(node, 2, &ad->idlest_reg);
0398
0399 if (ret)
0400 goto cleanup;
0401
0402 name = ti_dt_clk_name(node);
0403 clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, name);
0404 if (!IS_ERR(clk)) {
0405 of_clk_add_provider(node, of_clk_src_simple_get, clk);
0406 kfree(init);
0407 return;
0408 }
0409 cleanup:
0410 kfree(ad);
0411 kfree(clk_hw);
0412 kfree(init);
0413 }
0414 CLK_OF_DECLARE(omap2_apll_clock, "ti,omap2-apll-clock",
0415 of_omap2_apll_setup);