0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/errno.h>
0011 #include <linux/clk.h>
0012 #include <linux/io.h>
0013 #include <linux/bitops.h>
0014 #include <linux/clk/ti.h>
0015
0016 #include "clock.h"
0017
0018
0019
0020
0021
0022
0023
0024 #define OMAP4_DPLL_LP_FINT_MAX 1000000
0025 #define OMAP4_DPLL_LP_FOUT_MAX 100000000
0026
0027
0028
0029
0030 #define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BIT(8)
0031 #define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BIT(10)
0032 #define OMAP4430_DPLL_REGM4XEN_MASK BIT(11)
0033
0034
0035 #define OMAP4430_REGM4XEN_MULT 4
0036
0037 static void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk)
0038 {
0039 u32 v;
0040 u32 mask;
0041
0042 if (!clk)
0043 return;
0044
0045 mask = clk->flags & CLOCK_CLKOUTX2 ?
0046 OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
0047 OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
0048
0049 v = ti_clk_ll_ops->clk_readl(&clk->clksel_reg);
0050
0051 v &= ~mask;
0052 ti_clk_ll_ops->clk_writel(v, &clk->clksel_reg);
0053 }
0054
0055 static void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk)
0056 {
0057 u32 v;
0058 u32 mask;
0059
0060 if (!clk)
0061 return;
0062
0063 mask = clk->flags & CLOCK_CLKOUTX2 ?
0064 OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
0065 OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
0066
0067 v = ti_clk_ll_ops->clk_readl(&clk->clksel_reg);
0068
0069 v |= mask;
0070 ti_clk_ll_ops->clk_writel(v, &clk->clksel_reg);
0071 }
0072
0073 const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = {
0074 .allow_idle = omap4_dpllmx_allow_gatectrl,
0075 .deny_idle = omap4_dpllmx_deny_gatectrl,
0076 };
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 static void omap4_dpll_lpmode_recalc(struct dpll_data *dd)
0091 {
0092 long fint, fout;
0093
0094 fint = clk_hw_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1);
0095 fout = fint * dd->last_rounded_m;
0096
0097 if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX))
0098 dd->last_rounded_lpmode = 1;
0099 else
0100 dd->last_rounded_lpmode = 0;
0101 }
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
0114 unsigned long parent_rate)
0115 {
0116 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0117 u32 v;
0118 unsigned long rate;
0119 struct dpll_data *dd;
0120
0121 if (!clk || !clk->dpll_data)
0122 return 0;
0123
0124 dd = clk->dpll_data;
0125
0126 rate = omap2_get_dpll_rate(clk);
0127
0128
0129 v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
0130 if (v & OMAP4430_DPLL_REGM4XEN_MASK)
0131 rate *= OMAP4430_REGM4XEN_MULT;
0132
0133 return rate;
0134 }
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
0150 unsigned long target_rate,
0151 unsigned long *parent_rate)
0152 {
0153 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0154 struct dpll_data *dd;
0155 long r;
0156
0157 if (!clk || !clk->dpll_data)
0158 return -EINVAL;
0159
0160 dd = clk->dpll_data;
0161
0162 dd->last_rounded_m4xen = 0;
0163
0164
0165
0166
0167
0168 r = omap2_dpll_round_rate(hw, target_rate, NULL);
0169 if (r != ~0)
0170 goto out;
0171
0172
0173
0174
0175
0176
0177 r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT,
0178 NULL);
0179 if (r == ~0)
0180 return r;
0181
0182 dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
0183 dd->last_rounded_m4xen = 1;
0184
0185 out:
0186 omap4_dpll_lpmode_recalc(dd);
0187
0188 return dd->last_rounded_rate;
0189 }
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
0202 struct clk_rate_request *req)
0203 {
0204 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0205 struct dpll_data *dd;
0206
0207 if (!req->rate)
0208 return -EINVAL;
0209
0210 dd = clk->dpll_data;
0211 if (!dd)
0212 return -EINVAL;
0213
0214 if (clk_hw_get_rate(dd->clk_bypass) == req->rate &&
0215 (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
0216 req->best_parent_hw = dd->clk_bypass;
0217 } else {
0218 req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate,
0219 &req->best_parent_rate);
0220 req->best_parent_hw = dd->clk_ref;
0221 }
0222
0223 req->best_parent_rate = req->rate;
0224
0225 return 0;
0226 }