#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/slab.h>
{
struct meson_clk_pll *pll = to_meson_clk_pll(hw);
struct parm *p;
- unsigned long parent_rate_mhz = parent_rate / 1000000;
- unsigned long rate_mhz;
- u16 n, m, frac = 0, od, od2 = 0;
+ u64 rate;
+ u16 n, m, frac = 0, od, od2 = 0, od3 = 0;
u32 reg;
p = &pll->n;
od2 = PARM_GET(p->width, p->shift, reg);
}
+ p = &pll->od3;
+ if (p->width) {
+ reg = readl(pll->base + p->reg_off);
+ od3 = PARM_GET(p->width, p->shift, reg);
+ }
+
+ rate = (u64)m * parent_rate;
+
p = &pll->frac;
if (p->width) {
reg = readl(pll->base + p->reg_off);
frac = PARM_GET(p->width, p->shift, reg);
- rate_mhz = (parent_rate_mhz * m + \
- (parent_rate_mhz * frac >> 12)) * 2 / n;
- rate_mhz = rate_mhz >> od >> od2;
- } else
- rate_mhz = (parent_rate_mhz * m / n) >> od >> od2;
- return rate_mhz * 1000000;
+ rate += mul_u64_u32_shr(parent_rate, frac, p->width);
+ }
+
+ return div_u64(rate, n) >> od >> od2 >> od3;
}
static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
const struct pll_rate_table *rate_table = pll->rate_table;
int i;
+ /*
+ * if the table is missing, just return the current rate
+ * since we don't have the other available frequencies
+ */
+ if (!rate_table)
+ return meson_clk_pll_recalc_rate(hw, *parent_rate);
+
for (i = 0; i < pll->rate_count; i++) {
if (rate <= rate_table[i].rate)
return rate_table[i].rate;
const struct pll_rate_table *rate_table = pll->rate_table;
int i;
+ if (!rate_table)
+ return NULL;
+
for (i = 0; i < pll->rate_count; i++) {
if (rate == rate_table[i].rate)
return &rate_table[i];
writel(reg, pll->base + p->reg_off);
}
+ p = &pll->od3;
+ if (p->width) {
+ reg = readl(pll->base + p->reg_off);
+ reg = PARM_SET(p->width, p->shift, reg, rate_set->od3);
+ writel(reg, pll->base + p->reg_off);
+ }
+
p = &pll->frac;
if (p->width) {
reg = readl(pll->base + p->reg_off);