From: Davide Bonfanti <[email protected]>

    Clockout2 is added as a child of pll1_sysclk9, because they have
    the same pll divisor.
    Added dm365_clkout2_set_rate to properly set clockout2 frequency.
    Modified the davinci_set_sysclk_rate function in order
    to get the right ancestor.

    This patch has been developed against the
    http://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git
    git tree and tested on bmx board.

Signed-off-by: Davide Bonfanti <[email protected]>
Signed-off-by: Raffaele Recalcati <[email protected]>
---
 arch/arm/mach-davinci/clock.c              |   32 ++++++++++++----
 arch/arm/mach-davinci/clock.h              |    5 ++
 arch/arm/mach-davinci/dm365.c              |   57 ++++++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/dm365.h |    1 +
 4 files changed, 87 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index f29a526..6e45808 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -254,7 +254,15 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
        u32 v, plldiv;
        struct pll_data *pll;
        unsigned long rate = clk->rate;
+       struct clk *parent = clk;
 
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+       while (parent->parent->parent)
+               parent = parent->parent;
+
+       if (parent == clk)
+               return -EPERM;
        /* If this is the PLL base clock, no more calculations needed */
        if (clk->pll_data)
                return rate;
@@ -262,13 +270,13 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
        if (WARN_ON(!clk->parent))
                return rate;
 
-       rate = clk->parent->rate;
+       rate = parent->rate;
+
 
        /* Otherwise, the parent must be a PLL */
-       if (WARN_ON(!clk->parent->pll_data))
+       if (WARN_ON(!parent->pll_data))
                return rate;
-
-       pll = clk->parent->pll_data;
+       pll = parent->pll_data;
 
        /* If pre-PLL, source clock is before the multiplier and divider(s) */
        if (clk->flags & PRE_PLL)
@@ -293,26 +301,33 @@ int davinci_set_sysclk_rate(struct clk *clk, unsigned 
long rate)
        struct pll_data *pll;
        unsigned long input;
        unsigned ratio = 0;
+       struct clk *parent = clk;
+
+       /* searching the right ancestor (pll1_clk or pll2_clk) */
+       while (parent->parent->parent)
+               parent = parent->parent;
+       if (parent == clk)
+               return -EPERM;
 
        /* If this is the PLL base clock, wrong function to call */
        if (clk->pll_data)
                return 0;
 
        /* There must be a parent... */
-       if (WARN_ON(!clk->parent))
+       if (WARN_ON(!parent))
                return 0;
 
        /* ... the parent must be a PLL... */
-       if (WARN_ON(!clk->parent->pll_data))
+       if (WARN_ON(!parent->pll_data))
                return 0;
 
        /* ... and this clock must have a divider. */
        if (WARN_ON(!clk->div_reg))
                return 0;
 
-       pll = clk->parent->pll_data;
+       pll = parent->pll_data;
 
-       input = clk->parent->rate;
+       input = parent->rate;
 
        /* If pre-PLL, source clock is before the multiplier and divider(s) */
        if (clk->flags & PRE_PLL)
@@ -343,6 +358,7 @@ int davinci_set_sysclk_rate(struct clk *clk, unsigned long 
rate)
 
        return 0;
 }
+EXPORT_SYMBOL(davinci_set_sysclk_rate);
 
 static unsigned long clk_leafclk_recalc(struct clk *clk)
 {
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index a717d98..df36d73 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -50,6 +50,11 @@
 #define PLLDIV_EN       BIT(15)
 #define PLLDIV_RATIO_MASK 0x1f
 
+#define PERI_CLKCTL    0x48
+#define CLOCKOUT2EN    2
+#define CLOCKOUT1EN    1
+#define CLOCKOUT0EN    0
+
 /*
  * OMAP-L138 system reference guide recommends a wait for 4 OSCIN/CLKIN
  * cycles to ensure that the PLLC has switched to bypass mode. Delay of 1us
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 42fd4a4..56a425f 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -40,6 +40,11 @@
 #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
 
 static struct pll_data pll1_data = {
        .num            = 1,
@@ -124,6 +129,7 @@ static struct clk pll1_sysclk6 = {
        .parent         = &pll1_clk,
        .flags          = CLK_PLL,
        .div_reg        = PLLDIV6,
+       .set_rate       = davinci_set_sysclk_rate,
 };
 
 static struct clk pll1_sysclk7 = {
@@ -147,6 +153,14 @@ static struct clk pll1_sysclk9 = {
        .div_reg        = PLLDIV9,
 };
 
+static struct clk clkout2_clk = {
+       .name           = "clkout2",
+       .parent         = &pll1_sysclk9,
+       .flags          = CLK_PLL,
+       .div_reg        = PLLDIV9,
+       .set_rate       = davinci_set_sysclk_rate,
+};
+
 static struct clk pll2_clk = {
        .name           = "pll2",
        .parent         = &ref_clk,
@@ -421,6 +435,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),
@@ -657,6 +672,48 @@ static struct resource dm365_spi0_resources[] = {
        },
 };
 
+int dm365_clkout2_set_rate(unsigned long rate)
+{
+       int ret = -EINVAL;
+       int i, err, min_err, i_min_err;
+       u32 regval;
+       struct clk *clk;
+       static void __iomem *system_module_base;
+
+       clk = &clkout2_clk;
+       system_module_base = ioremap(DAVINCI_SYSTEM_MODULE_BASE, SZ_4K);
+       regval = __raw_readl(system_module_base + PERI_CLKCTL);
+
+       /* check all possibilities to get best fitting for the required freq */
+       i_min_err = min_err = INT_MAX;
+       for (i = 0x0F; i > 0; i--) {
+               if (clk->set_rate) {
+                       ret = clk_set_rate(clk, rate * i) ;
+                       err = clk_get_rate(clk) - rate * i;
+                       if (min_err > abs(err)) {
+                               min_err = abs(err);
+                               i_min_err = i;
+                       }
+               }
+       }
+       ret = clk_set_rate(clk, rate * i_min_err) ;
+       if (ret)
+               return ret;
+
+       /* setup DIV1 value */
+       regval &= ~(0x0F << 3);
+       regval |= (i_min_err - 1) << 3;
+
+       /* to make changes work stop CLOCKOUT & start it again */
+       regval |= 1 << CLOCKOUT2EN;
+       __raw_writel(regval, system_module_base + PERI_CLKCTL);
+       regval &= ~(1 << CLOCKOUT2EN);
+       __raw_writel(regval, system_module_base + PERI_CLKCTL);
+
+       return ret;
+}
+EXPORT_SYMBOL(dm365_clkout2_set_rate);
+
 static struct platform_device dm365_spi0_device = {
        .name = "spi_davinci",
        .id = 0,
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h 
b/arch/arm/mach-davinci/include/mach/dm365.h
index ea5df3b..f59741f 100644
--- a/arch/arm/mach-davinci/include/mach/dm365.h
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -49,4 +49,5 @@ void dm365_init_spi0(unsigned chipselect_mask,
                        struct spi_board_info *info, unsigned len);
 
 void dm365_set_vpfe_config(struct vpfe_config *cfg);
+int dm365_clkout2_set_rate(unsigned long rate);
 #endif /* __ASM_ARCH_DM365_H */
-- 
1.7.0.4

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to