linux/arch/arm/mach-imx/clk-pllv2.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/clk.h>
   3#include <linux/io.h>
   4#include <linux/errno.h>
   5#include <linux/delay.h>
   6#include <linux/slab.h>
   7#include <linux/err.h>
   8
   9#include <asm/div64.h>
  10
  11#include "clk.h"
  12
  13#define to_clk_pllv2(clk) (container_of(clk, struct clk_pllv2, clk))
  14
  15/* PLL Register Offsets */
  16#define MXC_PLL_DP_CTL                  0x00
  17#define MXC_PLL_DP_CONFIG               0x04
  18#define MXC_PLL_DP_OP                   0x08
  19#define MXC_PLL_DP_MFD                  0x0C
  20#define MXC_PLL_DP_MFN                  0x10
  21#define MXC_PLL_DP_MFNMINUS             0x14
  22#define MXC_PLL_DP_MFNPLUS              0x18
  23#define MXC_PLL_DP_HFS_OP               0x1C
  24#define MXC_PLL_DP_HFS_MFD              0x20
  25#define MXC_PLL_DP_HFS_MFN              0x24
  26#define MXC_PLL_DP_MFN_TOGC             0x28
  27#define MXC_PLL_DP_DESTAT               0x2c
  28
  29/* PLL Register Bit definitions */
  30#define MXC_PLL_DP_CTL_MUL_CTRL         0x2000
  31#define MXC_PLL_DP_CTL_DPDCK0_2_EN      0x1000
  32#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET  12
  33#define MXC_PLL_DP_CTL_ADE              0x800
  34#define MXC_PLL_DP_CTL_REF_CLK_DIV      0x400
  35#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8)
  36#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET       8
  37#define MXC_PLL_DP_CTL_HFSM             0x80
  38#define MXC_PLL_DP_CTL_PRE              0x40
  39#define MXC_PLL_DP_CTL_UPEN             0x20
  40#define MXC_PLL_DP_CTL_RST              0x10
  41#define MXC_PLL_DP_CTL_RCP              0x8
  42#define MXC_PLL_DP_CTL_PLM              0x4
  43#define MXC_PLL_DP_CTL_BRM0             0x2
  44#define MXC_PLL_DP_CTL_LRF              0x1
  45
  46#define MXC_PLL_DP_CONFIG_BIST          0x8
  47#define MXC_PLL_DP_CONFIG_SJC_CE        0x4
  48#define MXC_PLL_DP_CONFIG_AREN          0x2
  49#define MXC_PLL_DP_CONFIG_LDREQ         0x1
  50
  51#define MXC_PLL_DP_OP_MFI_OFFSET        4
  52#define MXC_PLL_DP_OP_MFI_MASK          (0xF << 4)
  53#define MXC_PLL_DP_OP_PDF_OFFSET        0
  54#define MXC_PLL_DP_OP_PDF_MASK          0xF
  55
  56#define MXC_PLL_DP_MFD_OFFSET           0
  57#define MXC_PLL_DP_MFD_MASK             0x07FFFFFF
  58
  59#define MXC_PLL_DP_MFN_OFFSET           0x0
  60#define MXC_PLL_DP_MFN_MASK             0x07FFFFFF
  61
  62#define MXC_PLL_DP_MFN_TOGC_TOG_DIS     (1 << 17)
  63#define MXC_PLL_DP_MFN_TOGC_TOG_EN      (1 << 16)
  64#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET  0x0
  65#define MXC_PLL_DP_MFN_TOGC_CNT_MASK    0xFFFF
  66
  67#define MXC_PLL_DP_DESTAT_TOG_SEL       (1 << 31)
  68#define MXC_PLL_DP_DESTAT_MFN           0x07FFFFFF
  69
  70#define MAX_DPLL_WAIT_TRIES     1000 /* 1000 * udelay(1) = 1ms */
  71
  72struct clk_pllv2 {
  73        struct clk_hw   hw;
  74        void __iomem    *base;
  75};
  76
  77static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
  78                u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn)
  79{
  80        long mfi, mfn, mfd, pdf, ref_clk, mfn_abs;
  81        unsigned long dbl;
  82        s64 temp;
  83
  84        dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
  85
  86        pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
  87        mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET;
  88        mfi = (mfi <= 5) ? 5 : mfi;
  89        mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
  90        mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK;
  91        /* Sign extend to 32-bits */
  92        if (mfn >= 0x04000000) {
  93                mfn |= 0xFC000000;
  94                mfn_abs = -mfn;
  95        }
  96
  97        ref_clk = 2 * parent_rate;
  98        if (dbl != 0)
  99                ref_clk *= 2;
 100
 101        ref_clk /= (pdf + 1);
 102        temp = (u64) ref_clk * mfn_abs;
 103        do_div(temp, mfd + 1);
 104        if (mfn < 0)
 105                temp = -temp;
 106        temp = (ref_clk * mfi) + temp;
 107
 108        return temp;
 109}
 110
 111static unsigned long clk_pllv2_recalc_rate(struct clk_hw *hw,
 112                unsigned long parent_rate)
 113{
 114        u32 dp_op, dp_mfd, dp_mfn, dp_ctl;
 115        void __iomem *pllbase;
 116        struct clk_pllv2 *pll = to_clk_pllv2(hw);
 117
 118        pllbase = pll->base;
 119
 120        dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
 121        dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);
 122        dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);
 123        dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);
 124
 125        return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn);
 126}
 127
 128static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,
 129                u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn)
 130{
 131        u32 reg;
 132        long mfi, pdf, mfn, mfd = 999999;
 133        s64 temp64;
 134        unsigned long quad_parent_rate;
 135
 136        quad_parent_rate = 4 * parent_rate;
 137        pdf = mfi = -1;
 138        while (++pdf < 16 && mfi < 5)
 139                mfi = rate * (pdf+1) / quad_parent_rate;
 140        if (mfi > 15)
 141                return -EINVAL;
 142        pdf--;
 143
 144        temp64 = rate * (pdf + 1) - quad_parent_rate * mfi;
 145        do_div(temp64, quad_parent_rate / 1000000);
 146        mfn = (long)temp64;
 147
 148        reg = mfi << 4 | pdf;
 149
 150        *dp_op = reg;
 151        *dp_mfd = mfd;
 152        *dp_mfn = mfn;
 153
 154        return 0;
 155}
 156
 157static int clk_pllv2_set_rate(struct clk_hw *hw, unsigned long rate,
 158                unsigned long parent_rate)
 159{
 160        struct clk_pllv2 *pll = to_clk_pllv2(hw);
 161        void __iomem *pllbase;
 162        u32 dp_ctl, dp_op, dp_mfd, dp_mfn;
 163        int ret;
 164
 165        pllbase = pll->base;
 166
 167
 168        ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn);
 169        if (ret)
 170                return ret;
 171
 172        dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
 173        /* use dpdck0_2 */
 174        __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL);
 175
 176        __raw_writel(dp_op, pllbase + MXC_PLL_DP_OP);
 177        __raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD);
 178        __raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN);
 179
 180        return 0;
 181}
 182
 183static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate,
 184                unsigned long *prate)
 185{
 186        u32 dp_op, dp_mfd, dp_mfn;
 187
 188        __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn);
 189        return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN,
 190                        dp_op, dp_mfd, dp_mfn);
 191}
 192
 193static int clk_pllv2_prepare(struct clk_hw *hw)
 194{
 195        struct clk_pllv2 *pll = to_clk_pllv2(hw);
 196        u32 reg;
 197        void __iomem *pllbase;
 198        int i = 0;
 199
 200        pllbase = pll->base;
 201        reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;
 202        __raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
 203
 204        /* Wait for lock */
 205        do {
 206                reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
 207                if (reg & MXC_PLL_DP_CTL_LRF)
 208                        break;
 209
 210                udelay(1);
 211        } while (++i < MAX_DPLL_WAIT_TRIES);
 212
 213        if (i == MAX_DPLL_WAIT_TRIES) {
 214                pr_err("MX5: pll locking failed\n");
 215                return -EINVAL;
 216        }
 217
 218        return 0;
 219}
 220
 221static void clk_pllv2_unprepare(struct clk_hw *hw)
 222{
 223        struct clk_pllv2 *pll = to_clk_pllv2(hw);
 224        u32 reg;
 225        void __iomem *pllbase;
 226
 227        pllbase = pll->base;
 228        reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN;
 229        __raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
 230}
 231
 232static struct clk_ops clk_pllv2_ops = {
 233        .prepare = clk_pllv2_prepare,
 234        .unprepare = clk_pllv2_unprepare,
 235        .recalc_rate = clk_pllv2_recalc_rate,
 236        .round_rate = clk_pllv2_round_rate,
 237        .set_rate = clk_pllv2_set_rate,
 238};
 239
 240struct clk *imx_clk_pllv2(const char *name, const char *parent,
 241                void __iomem *base)
 242{
 243        struct clk_pllv2 *pll;
 244        struct clk *clk;
 245        struct clk_init_data init;
 246
 247        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 248        if (!pll)
 249                return ERR_PTR(-ENOMEM);
 250
 251        pll->base = base;
 252
 253        init.name = name;
 254        init.ops = &clk_pllv2_ops;
 255        init.flags = 0;
 256        init.parent_names = &parent;
 257        init.num_parents = 1;
 258
 259        pll->hw.init = &init;
 260
 261        clk = clk_register(NULL, &pll->hw);
 262        if (IS_ERR(clk))
 263                kfree(pll);
 264
 265        return clk;
 266}
 267