@@ -144,6 +144,68 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL(clk_set_rate);
+
+int clkout_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long flags;
+ int ret = -EINVAL;
+ int i, err, min_err, i_min_err;
+ u32 regval;
+ struct pll_data *pll;
+
+
+ if (clk == NULL || IS_ERR(clk))
+ return ret;
+ pll = clk->parent->pll_data;
+ regval = __raw_readl(IO_ADDRESS(clk->sec_div_reg));
+
+ if (clk->sec_div_reg)
+ {
+ i_min_err = min_err = INT_MAX;
+ for (i=clk->sec_div_reg_max; i>0; i--)
+ {
+ if (clk->set_rate)
+ {
+ ret = clk_set_rate(clk, rate * i) ;
+ err = clk_get_rate(clk) - rate * i;
+ if (abs(min_err) > abs(err))
+ {
+ min_err = err;
+ i_min_err = i;
+ }
+ }
+ }
+ i = i_min_err;
+ ret = clk->set_rate(clk, rate * i) ;
+
+ regval &= ~(clk->sec_div_reg_max << clk->sec_div_reg_shift);
+ regval |= (i-1) << clk->sec_div_reg_shift;
+ __raw_writel(regval, IO_ADDRESS(clk->sec_div_reg));
+ regval = __raw_readl( IO_ADDRESS(clk->out_enable_reg));
+ regval |= 1 << clk->out_enable_bit;
+ __raw_writel(regval, IO_ADDRESS(clk->out_enable_reg));
+ rate *= i;
+ }
+ else
+ {
+ if (clk->set_rate)
+ ret = clk->set_rate(clk, rate);
+ }
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (ret == 0) {
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+ propagate_rate(clk);
+ regval &= ~(1 << clk->out_enable_bit);
+ __raw_writel(regval, IO_ADDRESS(clk->out_enable_reg));
+ }
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(clkout_set_rate);
+
int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
@@ -95,6 +95,12 @@ struct clk {
struct list_head childnode; /* parent's child list node */
struct pll_data *pll_data;
u32 div_reg;
+ u32 sec_div_reg;
+ u32 sec_div_reg_max;
+ u32 sec_div_reg_shift;
+ u32 out_enable_reg;
+ u32 out_enable_bit;
+
unsigned long (*recalc) (struct clk *);
int (*set_rate) (struct clk *clk, unsigned long rate);
int (*round_rate) (struct clk *clk, unsigned long rate);
@@ -40,6 +40,21 @@
#include "mux.h"
#define DM365_REF_FREQ 24000000 /* 24 MHz on the DM365 EVM */
+#define PINMUX0 0x00
+#define PINMUX1 0x04
+#define PINMUX2 0x08
+#define PINMUX3 0x0c
+#define PINMUX4 0x10
+#define INTMUX 0x18
+#define EVTMUX 0x1c
+#define PERI_CLKCTL 0x48
+#define CLOCKOUT2EN 2
+#define CLOCKOUT1EN 1
+#define CLOCKOUT0EN 0
+
+
+int dm365_set_pll1_rate(struct clk *clk, unsigned long rate);
+
static struct pll_data pll1_data = {
.num = 1,
@@ -147,6 +162,20 @@ static struct clk pll1_sysclk9 = {
.div_reg = PLLDIV9,
};
+static struct clk clkout2_clk = {
+ .name = "clkout2",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV9,
+ .sec_div_reg = DAVINCI_SYSTEM_MODULE_BASE + PERI_CLKCTL,
+ .sec_div_reg_max = 0x0F,
+ .sec_div_reg_shift = 3,
+ .out_enable_reg = DAVINCI_SYSTEM_MODULE_BASE + PERI_CLKCTL,
+ .out_enable_bit = CLOCKOUT2EN,
+ .set_rate = dm365_set_pll1_rate,
+};
+
+
static struct clk pll2_clk = {
.name = "pll2",
.parent = &ref_clk,
@@ -421,6 +450,7 @@ static struct clk_lookup dm365_clks[] = {
CLK(NULL, "pll1_sysclk7", &pll1_sysclk7),
CLK(NULL, "pll1_sysclk8", &pll1_sysclk8),
CLK(NULL, "pll1_sysclk9", &pll1_sysclk9),
+ CLK(NULL, "clkout2", &clkout2_clk),
CLK(NULL, "pll2", &pll2_clk),
CLK(NULL, "pll2_aux", &pll2_aux_clk),
CLK(NULL, "clkout1", &clkout1_clk),
@@ -467,9 +497,6 @@ static struct clk_lookup dm365_clks[] = {
/*----------------------------------------------------------------------*/
-#define INTMUX 0x18
-#define EVTMUX 0x1c
-
static const struct mux_config dm365_pins[] = {
#ifdef CONFIG_DAVINCI_MUX
@@ -657,6 +684,31 @@ static struct resource dm365_spi0_resources[] = {
},
};
+int dm365_set_pll1_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned int prediv, mult, postdiv;
+ u32 clk_freq_min, clk_freq_max, plldiv;
+
+ prediv = ioread32(IO_ADDRESS(DAVINCI_PLL1_BASE + PREDIV)) & 0x1F;
+ mult = ioread32(IO_ADDRESS(DAVINCI_PLL1_BASE + PLLM)) & 0x3FF;
+ postdiv = ioread32(IO_ADDRESS(DAVINCI_PLL1_BASE + POSTDIV)) & 0x1F;
+
+ clk_freq_max = DM365_REF_FREQ * 2 * mult / ( (prediv + 1) * (postdiv +
1) );
+ clk_freq_min = clk_freq_max / 0x20;
+
+ if ( (rate < clk_freq_min) || (rate > clk_freq_max) )
+ return -EINVAL;
+
+ plldiv = clk_freq_max / rate ;
+ if ( (clk_freq_max % rate) < (rate/2))
+ plldiv--;
+ iowrite32(plldiv & 0x1F, IO_ADDRESS(DAVINCI_PLL1_BASE + clk->div_reg));
+ iowrite32(plldiv | 0x8000, IO_ADDRESS(DAVINCI_PLL1_BASE +
clk->div_reg));
+ clk->rate = rate;
+
+ return 0;
+}
+
static struct platform_device dm365_spi0_device = {
.name = "spi_davinci",
.id = 0,
b/arch/arm/mach-davinci/include/mach/clock.h
@@ -18,4 +18,7 @@ struct clk;
extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk);
+int clkout_set_rate(struct clk *clk, unsigned long rate);
+
+
#endif