123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /*
- * Zynq PLL driver
- *
- * Copyright (C) 2013 Xilinx
- *
- * Sören Brinkmann <soren.brinkmann@xilinx.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2 as published by
- * the Free Software Foundation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include <linux/clk/zynq.h>
- #include <linux/clk-provider.h>
- #include <linux/slab.h>
- #include <linux/io.h>
- /**
- * struct zynq_pll
- * @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
- * Returns 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
- * Returns 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 = (clk_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
- * Returns 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 = clk_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
- * Returns 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 = clk_readl(clk->pll_ctrl);
- reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK);
- clk_writel(reg, clk->pll_ctrl);
- while (!(clk_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 = clk_readl(clk->pll_ctrl);
- reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK;
- clk_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
- * Returns 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 = clk_readl(pll->pll_ctrl);
- reg &= ~PLLCTRL_BPQUAL_MASK;
- clk_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;
- }
|