From: Davide Bonfanti <davide.bonfa...@bticino.it> Clockout2 is added as a child of pll1_sysclk9. A new dm365_clkout2_set_rate is used to set clockout2 frequency.
Signed-off-by: Davide Bonfanti <davide.bonfa...@bticino.it> Signed-off-by: Raffaele Recalcati <raffaele.recalc...@bticino.it> --- This patch has been developed against http://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git and has been tested for dm365 cpu on BMX board. This patch depends on the following one submitted to the mailing list: https://patchwork.kernel.org/patch/112994 TODO LIST -The clkout2 management needs a recalc function, but I by now I don't know how to point to it from davinci_clk_init. -The unmapping of system_module_base has to be checked. -Solving a possible race when writing PERI_CLKCTL, see Nori Sekhar explanation: "Looks like the same register supports setting clocks for voice codec and keyscan module as well. This can cause a race if those clocks are modified in a different context. Can you extend this function to cover those clocks as well? May be clk->lpsc can be used to determine if div1, div2 or div3 need to be changed. This way you can serialize the setting up of these clocks." A fine tuning of clkout2 is possible using the function below (it is possible to do something similar with Nori Sekhar work about DIV_ROUND_CLOSEST() in the davinci_set_sysclk_rate() function (max_rate has to be passed). static int clkout2_fine_setting(unsigned long rate) { struct clk *pll1_sysclk9; struct clk *clkout2; int i, err, min_err, i_min_err; int ret = -EINVAL; pll1_sysclk9 = clk_get(NULL, "pll1_sysclk9"); if (IS_ERR(pll1_sysclk9)) { printk(KERN_ERR "Could not get pll1_sysclk9\n"); return -ENODEV; } clk_enable(pll1_sysclk9); /* check all possibilities to get best fitting for the required freq */ i_min_err = min_err = INT_MAX; for (i = 0x0F; i > 0; i--) { ret = clk_set_rate(pll1_sysclk9, rate * i); err = clk_get_rate(pll1_sysclk9) - rate * i; if (min_err > abs(err)) { min_err = abs(err); i_min_err = i; } } /* setting the best one to pll1_sysclk9 */ ret = clk_set_rate(pll1_sysclk9, rate * i_min_err); if (ret) return ret; /* setting the best one to clkout2 */ clkout2 = clk_get(NULL, "clkout2"); if (IS_ERR(clkout2)) { printk(KERN_ERR "Could not get clkout2\n"); return -ENODEV; } clk_enable(clkout2); clk_set_rate(clkout2,rate); return 0; } arch/arm/mach-davinci/dm365.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 42 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 42fd4a4..0101a6c 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -40,6 +40,40 @@ #include "mux.h" #define DM365_REF_FREQ 24000000 /* 24 MHz on the DM365 EVM */ +#define DIV1_MASK 0x78 /* DIV1 mask in PERI_CLKCTL */ +#define PERI_CLKCTL 0x48 +#define CLOCKOUT2EN 2 + +int dm365_clkout2_set_rate(struct clk *clk, unsigned long rate) +{ + int i; + unsigned long input; + unsigned ratio; + unsigned regval; + void __iomem *system_module_base; + + /* There must be a parent... */ + if (WARN_ON(!clk->parent)) + return -EINVAL; + + input = clk->parent->rate; + + if (input > rate) + ratio = DIV_ROUND_UP(input, rate) - 1; + + system_module_base = ioremap(DAVINCI_SYSTEM_MODULE_BASE, SZ_4K); + regval = __raw_readl(system_module_base + PERI_CLKCTL); + regval &= ~DIV1_MASK; + regval |= ratio << 3; + + /* to make changes work stop CLOCKOUT & start it again */ + regval |= BIT(CLOCKOUT2EN); + __raw_writel(regval, system_module_base + PERI_CLKCTL); + regval &= ~(1 << CLOCKOUT2EN); + __raw_writel(regval, system_module_base + PERI_CLKCTL); + iounmap(system_module_base); + return 0; +} static struct pll_data pll1_data = { .num = 1, @@ -145,6 +179,13 @@ static struct clk pll1_sysclk9 = { .parent = &pll1_clk, .flags = CLK_PLL, .div_reg = PLLDIV9, + .set_rate = davinci_set_sysclk_rate, +}; + +static struct clk clkout2_clk = { + .name = "clkout2", + .parent = &pll1_sysclk9, + .set_rate = dm365_clkout2_set_rate, }; static struct clk pll2_clk = { @@ -421,6 +462,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), -- 1.7.0.4 _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source