Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | // SPDX-License-Identifier: GPL-2.0-only /* * Zynq PLL driver * * Copyright (C) 2013 Xilinx * * Sören Brinkmann <soren.brinkmann@xilinx.com> */ #include <linux/clk/zynq.h> #include <linux/clk-provider.h> #include <linux/slab.h> #include <linux/io.h> /** * struct zynq_pll - pll clock * @hw: Handle between common and hardware-specific interfaces * @pll_ctrl: PLL control register * @pll_status: PLL status register * @lock: Register lock * @lockbit: Indicates the associated PLL_LOCKED bit in the PLL status * register. */ struct zynq_pll { struct clk_hw hw; void __iomem *pll_ctrl; void __iomem *pll_status; spinlock_t *lock; u8 lockbit; }; #define to_zynq_pll(_hw) container_of(_hw, struct zynq_pll, hw) /* Register bitfield defines */ #define PLLCTRL_FBDIV_MASK 0x7f000 #define PLLCTRL_FBDIV_SHIFT 12 #define PLLCTRL_BPQUAL_MASK (1 << 3) #define PLLCTRL_PWRDWN_MASK 2 #define PLLCTRL_PWRDWN_SHIFT 1 #define PLLCTRL_RESET_MASK 1 #define PLLCTRL_RESET_SHIFT 0 #define PLL_FBDIV_MIN 13 #define PLL_FBDIV_MAX 66 /** * zynq_pll_round_rate() - Round a clock frequency * @hw: Handle between common and hardware-specific interfaces * @rate: Desired clock frequency * @prate: Clock frequency of parent clock * Return: frequency closest to @rate the hardware can generate. */ static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { u32 fbdiv; fbdiv = DIV_ROUND_CLOSEST(rate, *prate); if (fbdiv < PLL_FBDIV_MIN) fbdiv = PLL_FBDIV_MIN; else if (fbdiv > PLL_FBDIV_MAX) fbdiv = PLL_FBDIV_MAX; return *prate * fbdiv; } /** * zynq_pll_recalc_rate() - Recalculate clock frequency * @hw: Handle between common and hardware-specific interfaces * @parent_rate: Clock frequency of parent clock * Return: current clock frequency. */ static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct zynq_pll *clk = to_zynq_pll(hw); u32 fbdiv; /* * makes probably sense to redundantly save fbdiv in the struct * zynq_pll to save the IO access. */ fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; return parent_rate * fbdiv; } /** * zynq_pll_is_enabled - Check if a clock is enabled * @hw: Handle between common and hardware-specific interfaces * Return: 1 if the clock is enabled, 0 otherwise. * * Not sure this is a good idea, but since disabled means bypassed for * this clock implementation we say we are always enabled. */ static int zynq_pll_is_enabled(struct clk_hw *hw) { unsigned long flags = 0; u32 reg; struct zynq_pll *clk = to_zynq_pll(hw); spin_lock_irqsave(clk->lock, flags); reg = readl(clk->pll_ctrl); spin_unlock_irqrestore(clk->lock, flags); return !(reg & (PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK)); } /** * zynq_pll_enable - Enable clock * @hw: Handle between common and hardware-specific interfaces * Return: 0 on success */ static int zynq_pll_enable(struct clk_hw *hw) { unsigned long flags = 0; u32 reg; struct zynq_pll *clk = to_zynq_pll(hw); if (zynq_pll_is_enabled(hw)) return 0; pr_info("PLL: enable\n"); /* Power up PLL and wait for lock */ spin_lock_irqsave(clk->lock, flags); reg = readl(clk->pll_ctrl); reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK); writel(reg, clk->pll_ctrl); while (!(readl(clk->pll_status) & (1 << clk->lockbit))) ; spin_unlock_irqrestore(clk->lock, flags); return 0; } /** * zynq_pll_disable - Disable clock * @hw: Handle between common and hardware-specific interfaces * Returns 0 on success */ static void zynq_pll_disable(struct clk_hw *hw) { unsigned long flags = 0; u32 reg; struct zynq_pll *clk = to_zynq_pll(hw); if (!zynq_pll_is_enabled(hw)) return; pr_info("PLL: shutdown\n"); /* shut down PLL */ spin_lock_irqsave(clk->lock, flags); reg = readl(clk->pll_ctrl); reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK; writel(reg, clk->pll_ctrl); spin_unlock_irqrestore(clk->lock, flags); } static const struct clk_ops zynq_pll_ops = { .enable = zynq_pll_enable, .disable = zynq_pll_disable, .is_enabled = zynq_pll_is_enabled, .round_rate = zynq_pll_round_rate, .recalc_rate = zynq_pll_recalc_rate }; /** * clk_register_zynq_pll() - Register PLL with the clock framework * @name: PLL name * @parent: Parent clock name * @pll_ctrl: Pointer to PLL control register * @pll_status: Pointer to PLL status register * @lock_index: Bit index to this PLL's lock status bit in @pll_status * @lock: Register lock * Return: handle to the registered clock. */ struct clk *clk_register_zynq_pll(const char *name, const char *parent, void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, spinlock_t *lock) { struct zynq_pll *pll; struct clk *clk; u32 reg; const char *parent_arr[1] = {parent}; unsigned long flags = 0; struct clk_init_data initd = { .name = name, .parent_names = parent_arr, .ops = &zynq_pll_ops, .num_parents = 1, .flags = 0 }; pll = kmalloc(sizeof(*pll), GFP_KERNEL); if (!pll) return ERR_PTR(-ENOMEM); /* Populate the struct */ pll->hw.init = &initd; pll->pll_ctrl = pll_ctrl; pll->pll_status = pll_status; pll->lockbit = lock_index; pll->lock = lock; spin_lock_irqsave(pll->lock, flags); reg = readl(pll->pll_ctrl); reg &= ~PLLCTRL_BPQUAL_MASK; writel(reg, pll->pll_ctrl); spin_unlock_irqrestore(pll->lock, flags); clk = clk_register(NULL, &pll->hw); if (WARN_ON(IS_ERR(clk))) goto free_pll; return clk; free_pll: kfree(pll); return clk; } |