diff options
Diffstat (limited to 'arch/arm/mach-imx/clk-pllv3.c')
-rw-r--r-- | arch/arm/mach-imx/clk-pllv3.c | 326 |
1 files changed, 0 insertions, 326 deletions
diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c deleted file mode 100644 index e38dcdfdaa..0000000000 --- a/arch/arm/mach-imx/clk-pllv3.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <common.h> -#include <init.h> -#include <driver.h> -#include <linux/clk.h> -#include <io.h> -#include <linux/clkdev.h> -#include <linux/err.h> -#include <malloc.h> -#include <clock.h> -#include <asm-generic/div64.h> - -#include "clk.h" - -#define PLL_NUM_OFFSET 0x10 -#define PLL_DENOM_OFFSET 0x20 - -#define BM_PLL_POWER (0x1 << 12) -#define BM_PLL_ENABLE (0x1 << 13) -#define BM_PLL_BYPASS (0x1 << 16) -#define BM_PLL_LOCK (0x1 << 31) - -struct clk_pllv3 { - struct clk clk; - void __iomem *base; - bool powerup_set; - u32 div_mask; - const char *parent; -}; - -#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk) - -static int clk_pllv3_enable(struct clk *clk) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 val; - int timeout = 10000; - - val = readl(pll->base); - val &= ~BM_PLL_BYPASS; - if (pll->powerup_set) - val |= BM_PLL_POWER; - else - val &= ~BM_PLL_POWER; - writel(val, pll->base); - - /* Wait for PLL to lock */ - while (timeout--) { - if (readl(pll->base) & BM_PLL_LOCK) - break; - } - - if (!timeout) - return -ETIMEDOUT; - - val = readl(pll->base); - val |= BM_PLL_ENABLE; - writel(val, pll->base); - - return 0; -} - -static void clk_pllv3_disable(struct clk *clk) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 val; - - val = readl(pll->base); - val &= ~BM_PLL_ENABLE; - writel(val, pll->base); - - val |= BM_PLL_BYPASS; - if (pll->powerup_set) - val &= ~BM_PLL_POWER; - else - val |= BM_PLL_POWER; - writel(val, pll->base); -} - -static unsigned long clk_pllv3_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 div = readl(pll->base) & pll->div_mask; - - return (div == 1) ? parent_rate * 22 : parent_rate * 20; -} - -static long clk_pllv3_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - - return (rate >= parent_rate * 22) ? parent_rate * 22 : - parent_rate * 20; -} - -static int clk_pllv3_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 val, div; - - if (rate == parent_rate * 22) - div = 1; - else if (rate == parent_rate * 20) - div = 0; - else - return -EINVAL; - - val = readl(pll->base); - val &= ~pll->div_mask; - val |= div; - writel(val, pll->base); - - return 0; -} - -static const struct clk_ops clk_pllv3_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_recalc_rate, - .round_rate = clk_pllv3_round_rate, - .set_rate = clk_pllv3_set_rate, -}; - -static unsigned long clk_pllv3_sys_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 div = readl(pll->base) & pll->div_mask; - - return parent_rate * div / 2; -} - -static long clk_pllv3_sys_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - unsigned long min_rate = parent_rate * 54 / 2; - unsigned long max_rate = parent_rate * 108 / 2; - u32 div; - - if (rate > max_rate) - rate = max_rate; - else if (rate < min_rate) - rate = min_rate; - div = rate * 2 / parent_rate; - - return parent_rate * div / 2; -} - -static int clk_pllv3_sys_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - unsigned long min_rate = parent_rate * 54 / 2; - unsigned long max_rate = parent_rate * 108 / 2; - u32 val, div; - - if (rate < min_rate || rate > max_rate) - return -EINVAL; - - div = rate * 2 / parent_rate; - val = readl(pll->base); - val &= ~pll->div_mask; - val |= div; - writel(val, pll->base); - - return 0; -} - -static const struct clk_ops clk_pllv3_sys_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_sys_recalc_rate, - .round_rate = clk_pllv3_sys_round_rate, - .set_rate = clk_pllv3_sys_set_rate, -}; - -static unsigned long clk_pllv3_av_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - u32 mfn = readl(pll->base + PLL_NUM_OFFSET); - u32 mfd = readl(pll->base + PLL_DENOM_OFFSET); - u32 div = readl(pll->base) & pll->div_mask; - - return (parent_rate * div) + ((parent_rate / mfd) * mfn); -} - -static long clk_pllv3_av_round_rate(struct clk *clk, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - unsigned long min_rate = parent_rate * 27; - unsigned long max_rate = parent_rate * 54; - u32 div; - u32 mfn, mfd = 1000000; - u64 temp64; - - if (rate > max_rate) - rate = max_rate; - else if (rate < min_rate) - rate = min_rate; - - div = rate / parent_rate; - temp64 = (u64) (rate - div * parent_rate); - temp64 *= mfd; - do_div(temp64, parent_rate); - mfn = temp64; - - return parent_rate * div + parent_rate / mfd * mfn; -} - -static int clk_pllv3_av_set_rate(struct clk *clk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_pllv3 *pll = to_clk_pllv3(clk); - unsigned long min_rate = parent_rate * 27; - unsigned long max_rate = parent_rate * 54; - u32 val, div; - u32 mfn, mfd = 1000000; - u64 temp64; - - if (rate < min_rate || rate > max_rate) - return -EINVAL; - - div = rate / parent_rate; - temp64 = (u64) (rate - div * parent_rate); - temp64 *= mfd; - do_div(temp64, parent_rate); - mfn = temp64; - - val = readl(pll->base); - val &= ~pll->div_mask; - val |= div; - writel(val, pll->base); - writel(mfn, pll->base + PLL_NUM_OFFSET); - writel(mfd, pll->base + PLL_DENOM_OFFSET); - - return 0; -} - -static const struct clk_ops clk_pllv3_av_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_av_recalc_rate, - .round_rate = clk_pllv3_av_round_rate, - .set_rate = clk_pllv3_av_set_rate, -}; - -static unsigned long clk_pllv3_enet_recalc_rate(struct clk *clk, - unsigned long parent_rate) -{ - return 500000000; -} - -static const struct clk_ops clk_pllv3_enet_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, - .recalc_rate = clk_pllv3_enet_recalc_rate, -}; - -static const struct clk_ops clk_pllv3_mlb_ops = { - .enable = clk_pllv3_enable, - .disable = clk_pllv3_disable, -}; - -struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, - const char *parent, void __iomem *base, - u32 div_mask) -{ - struct clk_pllv3 *pll; - const struct clk_ops *ops; - int ret; - - pll = xzalloc(sizeof(*pll)); - - switch (type) { - case IMX_PLLV3_SYS: - ops = &clk_pllv3_sys_ops; - break; - case IMX_PLLV3_USB: - ops = &clk_pllv3_ops; - pll->powerup_set = true; - break; - case IMX_PLLV3_AV: - ops = &clk_pllv3_av_ops; - break; - case IMX_PLLV3_ENET: - ops = &clk_pllv3_enet_ops; - break; - case IMX_PLLV3_MLB: - ops = &clk_pllv3_mlb_ops; - break; - default: - ops = &clk_pllv3_ops; - } - pll->base = base; - pll->div_mask = div_mask; - pll->parent = parent; - pll->clk.ops = ops; - pll->clk.name = name; - pll->clk.parent_names = &pll->parent; - pll->clk.num_parents = 1; - - ret = clk_register(&pll->clk); - if (ret) { - free(pll); - return ERR_PTR(ret); - } - - return &pll->clk; -} |