0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/kernel.h>
0015 #include <linux/errno.h>
0016 #include <linux/clk-provider.h>
0017 #include <linux/io.h>
0018 #include <linux/clk/ti.h>
0019 #include <linux/delay.h>
0020
0021 #include "clock.h"
0022
0023
0024
0025
0026
0027 #define MAX_MODULE_ENABLE_WAIT 100000
0028
0029
0030
0031
0032
0033 #define CM_FCLKEN 0x0000
0034 #define CM_ICLKEN 0x0010
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 static int _wait_idlest_generic(struct clk_hw_omap *clk,
0051 struct clk_omap_reg *reg,
0052 u32 mask, u8 idlest, const char *name)
0053 {
0054 int i = 0, ena = 0;
0055
0056 ena = (idlest) ? 0 : mask;
0057
0058
0059 for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
0060 if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena)
0061 break;
0062 udelay(1);
0063 }
0064
0065 if (i < MAX_MODULE_ENABLE_WAIT)
0066 pr_debug("omap clock: module associated with clock %s ready after %d loops\n",
0067 name, i);
0068 else
0069 pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n",
0070 name, MAX_MODULE_ENABLE_WAIT);
0071
0072 return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
0073 }
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
0086 {
0087 struct clk_omap_reg companion_reg, idlest_reg;
0088 u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
0089 s16 prcm_mod;
0090 int r;
0091
0092
0093 if (clk->ops->find_companion) {
0094 clk->ops->find_companion(clk, &companion_reg, &other_bit);
0095 if (!(ti_clk_ll_ops->clk_readl(&companion_reg) &
0096 (1 << other_bit)))
0097 return;
0098 }
0099
0100 clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
0101 r = ti_clk_ll_ops->cm_split_idlest_reg(&idlest_reg, &prcm_mod,
0102 &idlest_reg_id);
0103 if (r) {
0104
0105 _wait_idlest_generic(clk, &idlest_reg, (1 << idlest_bit),
0106 idlest_val, clk_hw_get_name(&clk->hw));
0107 } else {
0108 ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id,
0109 idlest_bit);
0110 }
0111 }
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134 void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
0135 struct clk_omap_reg *other_reg,
0136 u8 *other_bit)
0137 {
0138 memcpy(other_reg, &clk->enable_reg, sizeof(*other_reg));
0139
0140
0141
0142
0143
0144 other_reg->offset ^= (CM_FCLKEN ^ CM_ICLKEN);
0145
0146 *other_bit = clk->enable_bit;
0147 }
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
0164 struct clk_omap_reg *idlest_reg, u8 *idlest_bit,
0165 u8 *idlest_val)
0166 {
0167 memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg));
0168
0169 idlest_reg->offset &= ~0xf0;
0170 idlest_reg->offset |= 0x20;
0171
0172 *idlest_bit = clk->enable_bit;
0173
0174
0175
0176
0177
0178
0179 *idlest_val = ti_clk_get_features()->cm_idlest_val;
0180 }
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194 int omap2_dflt_clk_enable(struct clk_hw *hw)
0195 {
0196 struct clk_hw_omap *clk;
0197 u32 v;
0198 int ret = 0;
0199 bool clkdm_control;
0200
0201 if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL)
0202 clkdm_control = false;
0203 else
0204 clkdm_control = true;
0205
0206 clk = to_clk_hw_omap(hw);
0207
0208 if (clkdm_control && clk->clkdm) {
0209 ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
0210 if (ret) {
0211 WARN(1,
0212 "%s: could not enable %s's clockdomain %s: %d\n",
0213 __func__, clk_hw_get_name(hw),
0214 clk->clkdm_name, ret);
0215 return ret;
0216 }
0217 }
0218
0219
0220 v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
0221 if (clk->flags & INVERT_ENABLE)
0222 v &= ~(1 << clk->enable_bit);
0223 else
0224 v |= (1 << clk->enable_bit);
0225 ti_clk_ll_ops->clk_writel(v, &clk->enable_reg);
0226 v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
0227
0228 if (clk->ops && clk->ops->find_idlest)
0229 _omap2_module_wait_ready(clk);
0230
0231 return 0;
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 void omap2_dflt_clk_disable(struct clk_hw *hw)
0244 {
0245 struct clk_hw_omap *clk;
0246 u32 v;
0247
0248 clk = to_clk_hw_omap(hw);
0249
0250 v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
0251 if (clk->flags & INVERT_ENABLE)
0252 v |= (1 << clk->enable_bit);
0253 else
0254 v &= ~(1 << clk->enable_bit);
0255 ti_clk_ll_ops->clk_writel(v, &clk->enable_reg);
0256
0257
0258 if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) &&
0259 clk->clkdm)
0260 ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
0261 }
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271 int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
0272 {
0273 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0274 u32 v;
0275
0276 v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
0277
0278 if (clk->flags & INVERT_ENABLE)
0279 v ^= BIT(clk->enable_bit);
0280
0281 v &= BIT(clk->enable_bit);
0282
0283 return v ? 1 : 0;
0284 }
0285
0286 const struct clk_hw_omap_ops clkhwops_wait = {
0287 .find_idlest = omap2_clk_dflt_find_idlest,
0288 .find_companion = omap2_clk_dflt_find_companion,
0289 };