diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-11-12 21:45:19 +0100 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-11-12 21:45:19 +0100 |
commit | 1bf0bc1e050fc425cc776b10d3ce8754389aabbe (patch) | |
tree | 317dceabcdd661bebfb829c4ba4440dc2ae2adf2 /drivers/sh | |
parent | b68c50d836517cf662145b2e7d5cdf40a38b24f1 (diff) | |
parent | 2944628607f76e4755660cd710f22a4748ef88d8 (diff) | |
download | op-kernel-dev-1bf0bc1e050fc425cc776b10d3ce8754389aabbe.zip op-kernel-dev-1bf0bc1e050fc425cc776b10d3ce8754389aabbe.tar.gz |
Merge branch 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas into next/soc
From Simon Horman <horms@verge.net.au>:
This series is based on the renesas/soc branch of the arm-soc tree.
There will be a subquent 'SoC2' pull request which is based on this
pull-request and a pull-request for boards.
* 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas:
ARM: shmobile: add fsi external clock sh7372
ARM: shmobile: add fsi external clock on r8a7740
ARM: shmobile: r8a7740: add FSI-DVI clocks
ARM: shmobile: sh7372: use sh_clk_fsidiv_register() for FSI-DIV clocks
ARM: shmobile: sh7372: sh7372_fsidivX_clk become non-global
sh: clkfwk: add sh_clk_fsidiv_register()
ARM: shmobile: r8a7779: add USB OHCI clock support
ARM: shmobile: r8a7779: add USB EHCI clock support
ARM: shmobile: r8a7740: add USB24 clock explain
ARM: shmobile: r8a7779: PFC rename PENCx -> USB_PENCx
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/clk/cpg.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 07e9fb4..b3dc441 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -361,3 +361,89 @@ int __init sh_clk_div4_reparent_register(struct clk *clks, int nr, return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div4_reparent_clk_ops); } + +/* FSI-DIV */ +static unsigned long fsidiv_recalc(struct clk *clk) +{ + u32 value; + + value = __raw_readl(clk->mapping->base); + + value >>= 16; + if (value < 2) + return clk->parent->rate; + + return clk->parent->rate / value; +} + +static long fsidiv_round_rate(struct clk *clk, unsigned long rate) +{ + return clk_rate_div_range_round(clk, 1, 0xffff, rate); +} + +static void fsidiv_disable(struct clk *clk) +{ + __raw_writel(0, clk->mapping->base); +} + +static int fsidiv_enable(struct clk *clk) +{ + u32 value; + + value = __raw_readl(clk->mapping->base) >> 16; + if (value < 2) + return 0; + + __raw_writel((value << 16) | 0x3, clk->mapping->base); + + return 0; +} + +static int fsidiv_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val; + int idx; + + idx = (clk->parent->rate / rate) & 0xffff; + if (idx < 2) + __raw_writel(0, clk->mapping->base); + else + __raw_writel(idx << 16, clk->mapping->base); + + return 0; +} + +static struct sh_clk_ops fsidiv_clk_ops = { + .recalc = fsidiv_recalc, + .round_rate = fsidiv_round_rate, + .set_rate = fsidiv_set_rate, + .enable = fsidiv_enable, + .disable = fsidiv_disable, +}; + +int __init sh_clk_fsidiv_register(struct clk *clks, int nr) +{ + struct clk_mapping *map; + int i; + + for (i = 0; i < nr; i++) { + + map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL); + if (!map) { + pr_err("%s: unable to alloc memory\n", __func__); + return -ENOMEM; + } + + /* clks[i].enable_reg came from SH_CLK_FSIDIV() */ + map->phys = (phys_addr_t)clks[i].enable_reg; + map->len = 8; + + clks[i].enable_reg = 0; /* remove .enable_reg */ + clks[i].ops = &fsidiv_clk_ops; + clks[i].mapping = map; + + clk_register(&clks[i]); + } + + return 0; +} |