Commit c77662a4 authored by Michael Turquette's avatar Michael Turquette

Merge branch 'for-4.1-clk-ti' of github.com:t-kristo/linux-pm into clk-next

parents 3966fab8 9089848d
......@@ -203,7 +203,7 @@ static void __init of_dra7_apll_setup(struct device_node *node)
ad->control_reg = ti_clk_get_reg_addr(node, 0);
ad->idlest_reg = ti_clk_get_reg_addr(node, 1);
if (!ad->control_reg || !ad->idlest_reg)
if (IS_ERR(ad->control_reg) || IS_ERR(ad->idlest_reg))
goto cleanup;
ad->idlest_mask = 0x1;
......@@ -384,7 +384,8 @@ static void __init of_omap2_apll_setup(struct device_node *node)
ad->autoidle_reg = ti_clk_get_reg_addr(node, 1);
ad->idlest_reg = ti_clk_get_reg_addr(node, 2);
if (!ad->control_reg || !ad->autoidle_reg || !ad->idlest_reg)
if (IS_ERR(ad->control_reg) || IS_ERR(ad->autoidle_reg) ||
IS_ERR(ad->idlest_reg))
goto cleanup;
clk = clk_register(NULL, &clk_hw->hw);
......
......@@ -119,7 +119,7 @@ int __init of_ti_clk_autoidle_setup(struct device_node *node)
clk->name = node->name;
clk->reg = ti_clk_get_reg_addr(node, 0);
if (!clk->reg) {
if (IS_ERR(clk->reg)) {
kfree(clk);
return -EINVAL;
}
......
......@@ -4320,7 +4320,6 @@ static struct ti_clk_alias omap3xxx_clks[] = {
CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck),
CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck),
CLK(NULL, "sys_altclk", &sys_altclk),
CLK(NULL, "mcbsp_clks", &mcbsp_clks),
CLK(NULL, "sys_clkout1", &sys_clkout1),
CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck),
CLK(NULL, "core_ck", &core_ck),
......@@ -4369,8 +4368,6 @@ static struct ti_clk_alias omap3xxx_clks[] = {
CLK(NULL, "i2c3_fck", &i2c3_fck),
CLK(NULL, "i2c2_fck", &i2c2_fck),
CLK(NULL, "i2c1_fck", &i2c1_fck),
CLK(NULL, "mcbsp5_fck", &mcbsp5_fck),
CLK(NULL, "mcbsp1_fck", &mcbsp1_fck),
CLK(NULL, "core_48m_fck", &core_48m_fck),
CLK(NULL, "mcspi4_fck", &mcspi4_fck),
CLK(NULL, "mcspi3_fck", &mcspi3_fck),
......@@ -4409,8 +4406,6 @@ static struct ti_clk_alias omap3xxx_clks[] = {
CLK(NULL, "uart1_ick", &uart1_ick),
CLK(NULL, "gpt11_ick", &gpt11_ick),
CLK(NULL, "gpt10_ick", &gpt10_ick),
CLK("omap-mcbsp.5", "ick", &mcbsp5_ick),
CLK("omap-mcbsp.1", "ick", &mcbsp1_ick),
CLK(NULL, "mcbsp5_ick", &mcbsp5_ick),
CLK(NULL, "mcbsp1_ick", &mcbsp1_ick),
CLK(NULL, "omapctrl_ick", &omapctrl_ick),
......@@ -4467,15 +4462,22 @@ static struct ti_clk_alias omap3xxx_clks[] = {
CLK(NULL, "gpt4_ick", &gpt4_ick),
CLK(NULL, "gpt3_ick", &gpt3_ick),
CLK(NULL, "gpt2_ick", &gpt2_ick),
CLK(NULL, "mcbsp_clks", &mcbsp_clks),
CLK("omap-mcbsp.1", "ick", &mcbsp1_ick),
CLK("omap-mcbsp.2", "ick", &mcbsp2_ick),
CLK("omap-mcbsp.3", "ick", &mcbsp3_ick),
CLK("omap-mcbsp.4", "ick", &mcbsp4_ick),
CLK(NULL, "mcbsp4_ick", &mcbsp2_ick),
CLK("omap-mcbsp.5", "ick", &mcbsp5_ick),
CLK(NULL, "mcbsp1_ick", &mcbsp1_ick),
CLK(NULL, "mcbsp2_ick", &mcbsp2_ick),
CLK(NULL, "mcbsp3_ick", &mcbsp3_ick),
CLK(NULL, "mcbsp2_ick", &mcbsp4_ick),
CLK(NULL, "mcbsp4_ick", &mcbsp4_ick),
CLK(NULL, "mcbsp5_ick", &mcbsp5_ick),
CLK(NULL, "mcbsp1_fck", &mcbsp1_fck),
CLK(NULL, "mcbsp2_fck", &mcbsp2_fck),
CLK(NULL, "mcbsp3_fck", &mcbsp3_fck),
CLK(NULL, "mcbsp4_fck", &mcbsp4_fck),
CLK(NULL, "mcbsp5_fck", &mcbsp5_fck),
CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
CLK("etb", "emu_src_ck", &emu_src_ck),
CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
......
......@@ -34,7 +34,6 @@ static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "omap_96m_alwon_fck", "omap_96m_alwon_fck"),
DT_CLK("etb", "emu_core_alwon_ck", "emu_core_alwon_ck"),
DT_CLK(NULL, "sys_altclk", "sys_altclk"),
DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"),
DT_CLK(NULL, "sys_clkout1", "sys_clkout1"),
DT_CLK(NULL, "dpll1_ck", "dpll1_ck"),
DT_CLK(NULL, "dpll1_x2_ck", "dpll1_x2_ck"),
......@@ -82,8 +81,6 @@ static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "i2c3_fck", "i2c3_fck"),
DT_CLK(NULL, "i2c2_fck", "i2c2_fck"),
DT_CLK(NULL, "i2c1_fck", "i2c1_fck"),
DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"),
DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"),
DT_CLK(NULL, "core_48m_fck", "core_48m_fck"),
DT_CLK(NULL, "mcspi4_fck", "mcspi4_fck"),
DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"),
......@@ -122,10 +119,6 @@ static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "uart1_ick", "uart1_ick"),
DT_CLK(NULL, "gpt11_ick", "gpt11_ick"),
DT_CLK(NULL, "gpt10_ick", "gpt10_ick"),
DT_CLK("omap-mcbsp.5", "ick", "mcbsp5_ick"),
DT_CLK("omap-mcbsp.1", "ick", "mcbsp1_ick"),
DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"),
DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"),
DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"),
DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"),
DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"),
......@@ -179,15 +172,17 @@ static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "gpt4_ick", "gpt4_ick"),
DT_CLK(NULL, "gpt3_ick", "gpt3_ick"),
DT_CLK(NULL, "gpt2_ick", "gpt2_ick"),
DT_CLK("omap-mcbsp.2", "ick", "mcbsp2_ick"),
DT_CLK("omap-mcbsp.3", "ick", "mcbsp3_ick"),
DT_CLK("omap-mcbsp.4", "ick", "mcbsp4_ick"),
DT_CLK(NULL, "mcbsp4_ick", "mcbsp2_ick"),
DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"),
DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"),
DT_CLK(NULL, "mcbsp2_ick", "mcbsp2_ick"),
DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"),
DT_CLK(NULL, "mcbsp2_ick", "mcbsp4_ick"),
DT_CLK(NULL, "mcbsp4_ick", "mcbsp4_ick"),
DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"),
DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"),
DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"),
DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"),
DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"),
DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"),
DT_CLK("etb", "emu_src_ck", "emu_src_ck"),
DT_CLK(NULL, "emu_src_ck", "emu_src_ck"),
DT_CLK(NULL, "pclk_fck", "pclk_fck"),
......
......@@ -249,17 +249,6 @@ static struct ti_dt_clk omap44xx_clks[] = {
DT_CLK("usbhs_tll", "usbtll_fck", "dummy_ck"),
DT_CLK("omap_wdt", "ick", "dummy_ck"),
DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
DT_CLK("omap_timer.1", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("omap_timer.2", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("omap_timer.3", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("omap_timer.4", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("omap_timer.9", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("omap_timer.10", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("omap_timer.11", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("omap_timer.5", "timer_sys_ck", "syc_clk_div_ck"),
DT_CLK("omap_timer.6", "timer_sys_ck", "syc_clk_div_ck"),
DT_CLK("omap_timer.7", "timer_sys_ck", "syc_clk_div_ck"),
DT_CLK("omap_timer.8", "timer_sys_ck", "syc_clk_div_ck"),
DT_CLK("4a318000.timer", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin_ck"),
DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin_ck"),
......
......@@ -208,17 +208,17 @@ static struct ti_dt_clk omap54xx_clks[] = {
DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"),
DT_CLK("omap_wdt", "ick", "dummy_ck"),
DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
DT_CLK("omap_timer.1", "sys_ck", "sys_clkin"),
DT_CLK("omap_timer.2", "sys_ck", "sys_clkin"),
DT_CLK("omap_timer.3", "sys_ck", "sys_clkin"),
DT_CLK("omap_timer.4", "sys_ck", "sys_clkin"),
DT_CLK("omap_timer.9", "sys_ck", "sys_clkin"),
DT_CLK("omap_timer.10", "sys_ck", "sys_clkin"),
DT_CLK("omap_timer.11", "sys_ck", "sys_clkin"),
DT_CLK("omap_timer.5", "sys_ck", "dss_syc_gfclk_div"),
DT_CLK("omap_timer.6", "sys_ck", "dss_syc_gfclk_div"),
DT_CLK("omap_timer.7", "sys_ck", "dss_syc_gfclk_div"),
DT_CLK("omap_timer.8", "sys_ck", "dss_syc_gfclk_div"),
DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin"),
DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin"),
DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin"),
DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin"),
DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin"),
DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin"),
DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin"),
DT_CLK("40138000.timer", "timer_sys_ck", "dss_syc_gfclk_div"),
DT_CLK("4013a000.timer", "timer_sys_ck", "dss_syc_gfclk_div"),
DT_CLK("4013c000.timer", "timer_sys_ck", "dss_syc_gfclk_div"),
DT_CLK("4013e000.timer", "timer_sys_ck", "dss_syc_gfclk_div"),
{ .node_name = NULL },
};
......
......@@ -289,17 +289,21 @@ static struct ti_dt_clk dra7xx_clks[] = {
DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"),
DT_CLK("omap_wdt", "ick", "dummy_ck"),
DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin2"),
DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin2"),
DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin2"),
DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin2"),
DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin2"),
DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin2"),
DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin2"),
DT_CLK("4ae18000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48032000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48034000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48036000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("4803e000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48086000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48088000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48820000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48822000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48824000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48826000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("48828000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("4882a000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("4882c000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("4882e000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK(NULL, "sys_clkin", "sys_clkin1"),
{ .node_name = NULL },
};
......
......@@ -103,7 +103,8 @@ int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
* @index: register index from the clock node
*
* Builds clock register address from device tree information. This
* is a struct of type clk_omap_reg.
* is a struct of type clk_omap_reg. Returns a pointer to the register
* address, or a pointer error value in failure.
*/
void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index)
{
......@@ -121,14 +122,14 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index)
if (i == CLK_MAX_MEMMAPS) {
pr_err("clk-provider not found for %s!\n", node->name);
return NULL;
return ERR_PTR(-ENOENT);
}
reg->index = i;
if (of_property_read_u32_index(node, "reg", index, &val)) {
pr_err("%s must have reg[%d]!\n", node->name, index);
return NULL;
return ERR_PTR(-EINVAL);
}
reg->offset = val;
......
......@@ -530,8 +530,8 @@ static int __init ti_clk_divider_populate(struct device_node *node,
u32 val;
*reg = ti_clk_get_reg_addr(node, 0);
if (!*reg)
return -EINVAL;
if (IS_ERR(*reg))
return PTR_ERR(*reg);
if (!of_property_read_u32(node, "ti,bit-shift", &val))
*shift = val;
......
......@@ -390,18 +390,18 @@ static void __init of_ti_dpll_setup(struct device_node *node,
#endif
} else {
dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
if (!dd->idlest_reg)
if (IS_ERR(dd->idlest_reg))
goto cleanup;
dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);
}
if (!dd->control_reg || !dd->mult_div1_reg)
if (IS_ERR(dd->control_reg) || IS_ERR(dd->mult_div1_reg))
goto cleanup;
if (dd->autoidle_mask) {
dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
if (!dd->autoidle_reg)
if (IS_ERR(dd->autoidle_reg))
goto cleanup;
}
......
......@@ -11,19 +11,27 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
#include <asm/div64.h>
/* FAPLL Control Register PLL_CTRL */
#define FAPLL_MAIN_MULT_N_SHIFT 16
#define FAPLL_MAIN_DIV_P_SHIFT 8
#define FAPLL_MAIN_LOCK BIT(7)
#define FAPLL_MAIN_PLLEN BIT(3)
#define FAPLL_MAIN_BP BIT(2)
#define FAPLL_MAIN_LOC_CTL BIT(0)
#define FAPLL_MAIN_MAX_MULT_N 0xffff
#define FAPLL_MAIN_MAX_DIV_P 0xff
#define FAPLL_MAIN_CLEAR_MASK \
((FAPLL_MAIN_MAX_MULT_N << FAPLL_MAIN_MULT_N_SHIFT) | \
(FAPLL_MAIN_DIV_P_SHIFT << FAPLL_MAIN_DIV_P_SHIFT) | \
FAPLL_MAIN_LOC_CTL)
/* FAPLL powerdown register PWD */
#define FAPLL_PWD_OFFSET 4
......@@ -49,6 +57,10 @@
/* Synthesizer frequency register */
#define SYNTH_LDFREQ BIT(31)
#define SYNTH_PHASE_K 8
#define SYNTH_MAX_INT_DIV 0xf
#define SYNTH_MAX_DIV_M 0xff
struct fapll_data {
struct clk_hw hw;
void __iomem *base;
......@@ -79,6 +91,48 @@ static bool ti_fapll_clock_is_bypass(struct fapll_data *fd)
return !!(v & FAPLL_MAIN_BP);
}
static void ti_fapll_set_bypass(struct fapll_data *fd)
{
u32 v = readl_relaxed(fd->base);
if (fd->bypass_bit_inverted)
v &= ~FAPLL_MAIN_BP;
else
v |= FAPLL_MAIN_BP;
writel_relaxed(v, fd->base);
}
static void ti_fapll_clear_bypass(struct fapll_data *fd)
{
u32 v = readl_relaxed(fd->base);
if (fd->bypass_bit_inverted)
v |= FAPLL_MAIN_BP;
else
v &= ~FAPLL_MAIN_BP;
writel_relaxed(v, fd->base);
}
static int ti_fapll_wait_lock(struct fapll_data *fd)
{
int retries = FAPLL_MAX_RETRIES;
u32 v;
while ((v = readl_relaxed(fd->base))) {
if (v & FAPLL_MAIN_LOCK)
return 0;
if (retries-- <= 0)
break;
udelay(1);
}
pr_err("%s failed to lock\n", fd->name);
return -ETIMEDOUT;
}
static int ti_fapll_enable(struct clk_hw *hw)
{
struct fapll_data *fd = to_fapll(hw);
......@@ -86,6 +140,7 @@ static int ti_fapll_enable(struct clk_hw *hw)
v |= FAPLL_MAIN_PLLEN;
writel_relaxed(v, fd->base);
ti_fapll_wait_lock(fd);
return 0;
}
......@@ -141,12 +196,85 @@ static u8 ti_fapll_get_parent(struct clk_hw *hw)
return 0;
}
static int ti_fapll_set_div_mult(unsigned long rate,
unsigned long parent_rate,
u32 *pre_div_p, u32 *mult_n)
{
/*
* So far no luck getting decent clock with PLL divider,
* PLL does not seem to lock and the signal does not look
* right. It seems the divider can only be used together
* with the multiplier?
*/
if (rate < parent_rate) {
pr_warn("FAPLL main divider rates unsupported\n");
return -EINVAL;
}
*mult_n = rate / parent_rate;
if (*mult_n > FAPLL_MAIN_MAX_MULT_N)
return -EINVAL;
*pre_div_p = 1;
return 0;
}
static long ti_fapll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
u32 pre_div_p, mult_n;
int error;
if (!rate)
return -EINVAL;
error = ti_fapll_set_div_mult(rate, *parent_rate,
&pre_div_p, &mult_n);
if (error)
return error;
rate = *parent_rate / pre_div_p;
rate *= mult_n;
return rate;
}
static int ti_fapll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct fapll_data *fd = to_fapll(hw);
u32 pre_div_p, mult_n, v;
int error;
if (!rate)
return -EINVAL;
error = ti_fapll_set_div_mult(rate, parent_rate,
&pre_div_p, &mult_n);
if (error)
return error;
ti_fapll_set_bypass(fd);
v = readl_relaxed(fd->base);
v &= ~FAPLL_MAIN_CLEAR_MASK;
v |= pre_div_p << FAPLL_MAIN_DIV_P_SHIFT;
v |= mult_n << FAPLL_MAIN_MULT_N_SHIFT;
writel_relaxed(v, fd->base);
if (ti_fapll_is_enabled(hw))
ti_fapll_wait_lock(fd);
ti_fapll_clear_bypass(fd);
return 0;
}
static struct clk_ops ti_fapll_ops = {
.enable = ti_fapll_enable,
.disable = ti_fapll_disable,
.is_enabled = ti_fapll_is_enabled,
.recalc_rate = ti_fapll_recalc_rate,
.get_parent = ti_fapll_get_parent,
.round_rate = ti_fapll_round_rate,
.set_rate = ti_fapll_set_rate,
};
static int ti_fapll_synth_enable(struct clk_hw *hw)
......@@ -204,7 +332,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
/*
* Synth frequency integer and fractional divider.
* Note that the phase output K is 8, so the result needs
* to be multiplied by 8.
* to be multiplied by SYNTH_PHASE_K.
*/
if (synth->freq) {
u32 v, synth_int_div, synth_frac_div, synth_div_freq;
......@@ -215,14 +343,138 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
rate *= 10000000;
do_div(rate, synth_div_freq);
rate *= 8;
rate *= SYNTH_PHASE_K;
}
/* Synth ost-divider M */
synth_div_m = readl_relaxed(synth->div) & 0xff;
do_div(rate, synth_div_m);
/* Synth post-divider M */
synth_div_m = readl_relaxed(synth->div) & SYNTH_MAX_DIV_M;
return rate;
return DIV_ROUND_UP_ULL(rate, synth_div_m);
}
static unsigned long ti_fapll_synth_get_frac_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct fapll_synth *synth = to_synth(hw);
unsigned long current_rate, frac_rate;
u32 post_div_m;
current_rate = ti_fapll_synth_recalc_rate(hw, parent_rate);
post_div_m = readl_relaxed(synth->div) & SYNTH_MAX_DIV_M;
frac_rate = current_rate * post_div_m;
return frac_rate;
}
static u32 ti_fapll_synth_set_frac_rate(struct fapll_synth *synth,
unsigned long rate,
unsigned long parent_rate)
{
u32 post_div_m, synth_int_div = 0, synth_frac_div = 0, v;
post_div_m = DIV_ROUND_UP_ULL((u64)parent_rate * SYNTH_PHASE_K, rate);
post_div_m = post_div_m / SYNTH_MAX_INT_DIV;
if (post_div_m > SYNTH_MAX_DIV_M)
return -EINVAL;
if (!post_div_m)
post_div_m = 1;
for (; post_div_m < SYNTH_MAX_DIV_M; post_div_m++) {
synth_int_div = DIV_ROUND_UP_ULL((u64)parent_rate *
SYNTH_PHASE_K *
10000000,
rate * post_div_m);
synth_frac_div = synth_int_div % 10000000;
synth_int_div /= 10000000;
if (synth_int_div <= SYNTH_MAX_INT_DIV)
break;
}
if (synth_int_div > SYNTH_MAX_INT_DIV)
return -EINVAL;
v = readl_relaxed(synth->freq);
v &= ~0x1fffffff;
v |= (synth_int_div & SYNTH_MAX_INT_DIV) << 24;
v |= (synth_frac_div & 0xffffff);
v |= SYNTH_LDFREQ;
writel_relaxed(v, synth->freq);
return post_div_m;
}
static long ti_fapll_synth_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct fapll_synth *synth = to_synth(hw);
struct fapll_data *fd = synth->fd;
unsigned long r;
if (ti_fapll_clock_is_bypass(fd) || !synth->div || !rate)
return -EINVAL;
/* Only post divider m available with no fractional divider? */
if (!synth->freq) {
unsigned long frac_rate;
u32 synth_post_div_m;
frac_rate = ti_fapll_synth_get_frac_rate(hw, *parent_rate);
synth_post_div_m = DIV_ROUND_UP(frac_rate, rate);
r = DIV_ROUND_UP(frac_rate, synth_post_div_m);
goto out;
}
r = *parent_rate * SYNTH_PHASE_K;
if (rate > r)
goto out;
r = DIV_ROUND_UP_ULL(r, SYNTH_MAX_INT_DIV * SYNTH_MAX_DIV_M);
if (rate < r)
goto out;
r = rate;
out:
return r;
}
static int ti_fapll_synth_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct fapll_synth *synth = to_synth(hw);
struct fapll_data *fd = synth->fd;
unsigned long frac_rate, post_rate = 0;
u32 post_div_m = 0, v;
if (ti_fapll_clock_is_bypass(fd) || !synth->div || !rate)
return -EINVAL;
/* Produce the rate with just post divider M? */
frac_rate = ti_fapll_synth_get_frac_rate(hw, parent_rate);
if (frac_rate < rate) {
if (!synth->freq)
return -EINVAL;
} else {
post_div_m = DIV_ROUND_UP(frac_rate, rate);
if (post_div_m && (post_div_m <= SYNTH_MAX_DIV_M))
post_rate = DIV_ROUND_UP(frac_rate, post_div_m);
if (!synth->freq && !post_rate)
return -EINVAL;
}
/* Need to recalculate the fractional divider? */
if ((post_rate != rate) && synth->freq)
post_div_m = ti_fapll_synth_set_frac_rate(synth,
rate,
parent_rate);
v = readl_relaxed(synth->div);
v &= ~SYNTH_MAX_DIV_M;
v |= post_div_m;
v |= SYNTH_LDMDIV1;
writel_relaxed(v, synth->div);
return 0;
}
static struct clk_ops ti_fapll_synt_ops = {
......@@ -230,6 +482,8 @@ static struct clk_ops ti_fapll_synt_ops = {
.disable = ti_fapll_synth_disable,
.is_enabled = ti_fapll_synth_is_enabled,
.recalc_rate = ti_fapll_synth_recalc_rate,
.round_rate = ti_fapll_synth_round_rate,
.set_rate = ti_fapll_synth_set_rate,
};
static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
......
......@@ -225,7 +225,7 @@ static void __init _of_ti_gate_clk_setup(struct device_node *node,
if (ops != &omap_gate_clkdm_clk_ops) {
reg = ti_clk_get_reg_addr(node, 0);
if (!reg)
if (IS_ERR(reg))
return;
if (!of_property_read_u32(node, "ti,bit-shift", &val))
......@@ -264,7 +264,7 @@ _of_ti_composite_gate_clk_setup(struct device_node *node,
return;
gate->enable_reg = ti_clk_get_reg_addr(node, 0);
if (!gate->enable_reg)
if (IS_ERR(gate->enable_reg))
goto cleanup;
of_property_read_u32(node, "ti,bit-shift", &val);
......
......@@ -111,7 +111,7 @@ static void __init _of_ti_interface_clk_setup(struct device_node *node,
u32 val;
reg = ti_clk_get_reg_addr(node, 0);
if (!reg)
if (IS_ERR(reg))
return;
if (!of_property_read_u32(node, "ti,bit-shift", &val))
......
......@@ -210,7 +210,7 @@ static void of_mux_clk_setup(struct device_node *node)
reg = ti_clk_get_reg_addr(node, 0);
if (!reg)
if (IS_ERR(reg))
goto cleanup;
of_property_read_u32(node, "ti,bit-shift", &shift);
......@@ -283,7 +283,7 @@ static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
mux->reg = ti_clk_get_reg_addr(node, 0);
if (!mux->reg)
if (IS_ERR(mux->reg))
goto cleanup;
if (!of_property_read_u32(node, "ti,bit-shift", &val))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment