xref: /linux/drivers/clk/zynq/pll.c (revision 8a3492cd)
1dc1a8bc1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23682af46SSoren Brinkmann /*
33682af46SSoren Brinkmann  * Zynq PLL driver
43682af46SSoren Brinkmann  *
53682af46SSoren Brinkmann  *  Copyright (C) 2013 Xilinx
63682af46SSoren Brinkmann  *
73682af46SSoren Brinkmann  *  Sören Brinkmann <soren.brinkmann@xilinx.com>
83682af46SSoren Brinkmann  */
93682af46SSoren Brinkmann #include <linux/clk/zynq.h>
103682af46SSoren Brinkmann #include <linux/clk-provider.h>
113682af46SSoren Brinkmann #include <linux/slab.h>
123682af46SSoren Brinkmann #include <linux/io.h>
133682af46SSoren Brinkmann 
143682af46SSoren Brinkmann /**
15*8a3492cdSShubhrajyoti Datta  * struct zynq_pll - pll clock
163682af46SSoren Brinkmann  * @hw:		Handle between common and hardware-specific interfaces
173682af46SSoren Brinkmann  * @pll_ctrl:	PLL control register
183682af46SSoren Brinkmann  * @pll_status:	PLL status register
193682af46SSoren Brinkmann  * @lock:	Register lock
203682af46SSoren Brinkmann  * @lockbit:	Indicates the associated PLL_LOCKED bit in the PLL status
213682af46SSoren Brinkmann  *		register.
223682af46SSoren Brinkmann  */
233682af46SSoren Brinkmann struct zynq_pll {
243682af46SSoren Brinkmann 	struct clk_hw	hw;
253682af46SSoren Brinkmann 	void __iomem	*pll_ctrl;
263682af46SSoren Brinkmann 	void __iomem	*pll_status;
273682af46SSoren Brinkmann 	spinlock_t	*lock;
283682af46SSoren Brinkmann 	u8		lockbit;
293682af46SSoren Brinkmann };
303682af46SSoren Brinkmann #define to_zynq_pll(_hw)	container_of(_hw, struct zynq_pll, hw)
313682af46SSoren Brinkmann 
323682af46SSoren Brinkmann /* Register bitfield defines */
333682af46SSoren Brinkmann #define PLLCTRL_FBDIV_MASK	0x7f000
343682af46SSoren Brinkmann #define PLLCTRL_FBDIV_SHIFT	12
353682af46SSoren Brinkmann #define PLLCTRL_BPQUAL_MASK	(1 << 3)
363682af46SSoren Brinkmann #define PLLCTRL_PWRDWN_MASK	2
373682af46SSoren Brinkmann #define PLLCTRL_PWRDWN_SHIFT	1
383682af46SSoren Brinkmann #define PLLCTRL_RESET_MASK	1
393682af46SSoren Brinkmann #define PLLCTRL_RESET_SHIFT	0
403682af46SSoren Brinkmann 
41353dc6c4SSoren Brinkmann #define PLL_FBDIV_MIN	13
42353dc6c4SSoren Brinkmann #define PLL_FBDIV_MAX	66
43353dc6c4SSoren Brinkmann 
443682af46SSoren Brinkmann /**
453682af46SSoren Brinkmann  * zynq_pll_round_rate() - Round a clock frequency
463682af46SSoren Brinkmann  * @hw:		Handle between common and hardware-specific interfaces
473682af46SSoren Brinkmann  * @rate:	Desired clock frequency
483682af46SSoren Brinkmann  * @prate:	Clock frequency of parent clock
49*8a3492cdSShubhrajyoti Datta  * Return:	frequency closest to @rate the hardware can generate.
503682af46SSoren Brinkmann  */
zynq_pll_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)513682af46SSoren Brinkmann static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate,
523682af46SSoren Brinkmann 		unsigned long *prate)
533682af46SSoren Brinkmann {
543682af46SSoren Brinkmann 	u32 fbdiv;
553682af46SSoren Brinkmann 
563682af46SSoren Brinkmann 	fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
57353dc6c4SSoren Brinkmann 	if (fbdiv < PLL_FBDIV_MIN)
58353dc6c4SSoren Brinkmann 		fbdiv = PLL_FBDIV_MIN;
59353dc6c4SSoren Brinkmann 	else if (fbdiv > PLL_FBDIV_MAX)
60353dc6c4SSoren Brinkmann 		fbdiv = PLL_FBDIV_MAX;
613682af46SSoren Brinkmann 
623682af46SSoren Brinkmann 	return *prate * fbdiv;
633682af46SSoren Brinkmann }
643682af46SSoren Brinkmann 
653682af46SSoren Brinkmann /**
663682af46SSoren Brinkmann  * zynq_pll_recalc_rate() - Recalculate clock frequency
673682af46SSoren Brinkmann  * @hw:			Handle between common and hardware-specific interfaces
683682af46SSoren Brinkmann  * @parent_rate:	Clock frequency of parent clock
69*8a3492cdSShubhrajyoti Datta  * Return:		current clock frequency.
703682af46SSoren Brinkmann  */
zynq_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)713682af46SSoren Brinkmann static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw,
723682af46SSoren Brinkmann 		unsigned long parent_rate)
733682af46SSoren Brinkmann {
743682af46SSoren Brinkmann 	struct zynq_pll *clk = to_zynq_pll(hw);
753682af46SSoren Brinkmann 	u32 fbdiv;
763682af46SSoren Brinkmann 
773682af46SSoren Brinkmann 	/*
783682af46SSoren Brinkmann 	 * makes probably sense to redundantly save fbdiv in the struct
793682af46SSoren Brinkmann 	 * zynq_pll to save the IO access.
803682af46SSoren Brinkmann 	 */
815834fd75SJonas Gorski 	fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
823682af46SSoren Brinkmann 			PLLCTRL_FBDIV_SHIFT;
833682af46SSoren Brinkmann 
843682af46SSoren Brinkmann 	return parent_rate * fbdiv;
853682af46SSoren Brinkmann }
863682af46SSoren Brinkmann 
873682af46SSoren Brinkmann /**
883682af46SSoren Brinkmann  * zynq_pll_is_enabled - Check if a clock is enabled
893682af46SSoren Brinkmann  * @hw:		Handle between common and hardware-specific interfaces
90*8a3492cdSShubhrajyoti Datta  * Return:	1 if the clock is enabled, 0 otherwise.
913682af46SSoren Brinkmann  *
923682af46SSoren Brinkmann  * Not sure this is a good idea, but since disabled means bypassed for
933682af46SSoren Brinkmann  * this clock implementation we say we are always enabled.
943682af46SSoren Brinkmann  */
zynq_pll_is_enabled(struct clk_hw * hw)953682af46SSoren Brinkmann static int zynq_pll_is_enabled(struct clk_hw *hw)
963682af46SSoren Brinkmann {
973682af46SSoren Brinkmann 	unsigned long flags = 0;
983682af46SSoren Brinkmann 	u32 reg;
993682af46SSoren Brinkmann 	struct zynq_pll *clk = to_zynq_pll(hw);
1003682af46SSoren Brinkmann 
1013682af46SSoren Brinkmann 	spin_lock_irqsave(clk->lock, flags);
1023682af46SSoren Brinkmann 
1035834fd75SJonas Gorski 	reg = readl(clk->pll_ctrl);
1043682af46SSoren Brinkmann 
1053682af46SSoren Brinkmann 	spin_unlock_irqrestore(clk->lock, flags);
1063682af46SSoren Brinkmann 
1073682af46SSoren Brinkmann 	return !(reg & (PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK));
1083682af46SSoren Brinkmann }
1093682af46SSoren Brinkmann 
1103682af46SSoren Brinkmann /**
1113682af46SSoren Brinkmann  * zynq_pll_enable - Enable clock
1123682af46SSoren Brinkmann  * @hw:		Handle between common and hardware-specific interfaces
113*8a3492cdSShubhrajyoti Datta  * Return: 0 on success
1143682af46SSoren Brinkmann  */
zynq_pll_enable(struct clk_hw * hw)1153682af46SSoren Brinkmann static int zynq_pll_enable(struct clk_hw *hw)
1163682af46SSoren Brinkmann {
1173682af46SSoren Brinkmann 	unsigned long flags = 0;
1183682af46SSoren Brinkmann 	u32 reg;
1193682af46SSoren Brinkmann 	struct zynq_pll *clk = to_zynq_pll(hw);
1203682af46SSoren Brinkmann 
1213682af46SSoren Brinkmann 	if (zynq_pll_is_enabled(hw))
1223682af46SSoren Brinkmann 		return 0;
1233682af46SSoren Brinkmann 
1243682af46SSoren Brinkmann 	pr_info("PLL: enable\n");
1253682af46SSoren Brinkmann 
1263682af46SSoren Brinkmann 	/* Power up PLL and wait for lock */
1273682af46SSoren Brinkmann 	spin_lock_irqsave(clk->lock, flags);
1283682af46SSoren Brinkmann 
1295834fd75SJonas Gorski 	reg = readl(clk->pll_ctrl);
1303682af46SSoren Brinkmann 	reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK);
1315834fd75SJonas Gorski 	writel(reg, clk->pll_ctrl);
1325834fd75SJonas Gorski 	while (!(readl(clk->pll_status) & (1 << clk->lockbit)))
1333682af46SSoren Brinkmann 		;
1343682af46SSoren Brinkmann 
1353682af46SSoren Brinkmann 	spin_unlock_irqrestore(clk->lock, flags);
1363682af46SSoren Brinkmann 
1373682af46SSoren Brinkmann 	return 0;
1383682af46SSoren Brinkmann }
1393682af46SSoren Brinkmann 
1403682af46SSoren Brinkmann /**
1413682af46SSoren Brinkmann  * zynq_pll_disable - Disable clock
1423682af46SSoren Brinkmann  * @hw:		Handle between common and hardware-specific interfaces
1433682af46SSoren Brinkmann  * Returns 0 on success
1443682af46SSoren Brinkmann  */
zynq_pll_disable(struct clk_hw * hw)1453682af46SSoren Brinkmann static void zynq_pll_disable(struct clk_hw *hw)
1463682af46SSoren Brinkmann {
1473682af46SSoren Brinkmann 	unsigned long flags = 0;
1483682af46SSoren Brinkmann 	u32 reg;
1493682af46SSoren Brinkmann 	struct zynq_pll *clk = to_zynq_pll(hw);
1503682af46SSoren Brinkmann 
1513682af46SSoren Brinkmann 	if (!zynq_pll_is_enabled(hw))
1523682af46SSoren Brinkmann 		return;
1533682af46SSoren Brinkmann 
1543682af46SSoren Brinkmann 	pr_info("PLL: shutdown\n");
1553682af46SSoren Brinkmann 
1563682af46SSoren Brinkmann 	/* shut down PLL */
1573682af46SSoren Brinkmann 	spin_lock_irqsave(clk->lock, flags);
1583682af46SSoren Brinkmann 
1595834fd75SJonas Gorski 	reg = readl(clk->pll_ctrl);
1603682af46SSoren Brinkmann 	reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK;
1615834fd75SJonas Gorski 	writel(reg, clk->pll_ctrl);
1623682af46SSoren Brinkmann 
1633682af46SSoren Brinkmann 	spin_unlock_irqrestore(clk->lock, flags);
1643682af46SSoren Brinkmann }
1653682af46SSoren Brinkmann 
1663682af46SSoren Brinkmann static const struct clk_ops zynq_pll_ops = {
1673682af46SSoren Brinkmann 	.enable = zynq_pll_enable,
1683682af46SSoren Brinkmann 	.disable = zynq_pll_disable,
1693682af46SSoren Brinkmann 	.is_enabled = zynq_pll_is_enabled,
1703682af46SSoren Brinkmann 	.round_rate = zynq_pll_round_rate,
1713682af46SSoren Brinkmann 	.recalc_rate = zynq_pll_recalc_rate
1723682af46SSoren Brinkmann };
1733682af46SSoren Brinkmann 
1743682af46SSoren Brinkmann /**
1753682af46SSoren Brinkmann  * clk_register_zynq_pll() - Register PLL with the clock framework
176bc22d596SLee Jones  * @name:	PLL name
177bc22d596SLee Jones  * @parent:	Parent clock name
178bc22d596SLee Jones  * @pll_ctrl:	Pointer to PLL control register
179bc22d596SLee Jones  * @pll_status:	Pointer to PLL status register
180bc22d596SLee Jones  * @lock_index:	Bit index to this PLL's lock status bit in @pll_status
181bc22d596SLee Jones  * @lock:	Register lock
182*8a3492cdSShubhrajyoti Datta  * Return:	handle to the registered clock.
1833682af46SSoren Brinkmann  */
clk_register_zynq_pll(const char * name,const char * parent,void __iomem * pll_ctrl,void __iomem * pll_status,u8 lock_index,spinlock_t * lock)1843682af46SSoren Brinkmann struct clk *clk_register_zynq_pll(const char *name, const char *parent,
1853682af46SSoren Brinkmann 		void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index,
1863682af46SSoren Brinkmann 		spinlock_t *lock)
1873682af46SSoren Brinkmann {
1883682af46SSoren Brinkmann 	struct zynq_pll *pll;
1893682af46SSoren Brinkmann 	struct clk *clk;
1903682af46SSoren Brinkmann 	u32 reg;
1913682af46SSoren Brinkmann 	const char *parent_arr[1] = {parent};
1923682af46SSoren Brinkmann 	unsigned long flags = 0;
1933682af46SSoren Brinkmann 	struct clk_init_data initd = {
1943682af46SSoren Brinkmann 		.name = name,
1953682af46SSoren Brinkmann 		.parent_names = parent_arr,
1963682af46SSoren Brinkmann 		.ops = &zynq_pll_ops,
1973682af46SSoren Brinkmann 		.num_parents = 1,
1983682af46SSoren Brinkmann 		.flags = 0
1993682af46SSoren Brinkmann 	};
2003682af46SSoren Brinkmann 
2013682af46SSoren Brinkmann 	pll = kmalloc(sizeof(*pll), GFP_KERNEL);
20288cebf5eSSoren Brinkmann 	if (!pll)
2033682af46SSoren Brinkmann 		return ERR_PTR(-ENOMEM);
2043682af46SSoren Brinkmann 
2053682af46SSoren Brinkmann 	/* Populate the struct */
2063682af46SSoren Brinkmann 	pll->hw.init = &initd;
2073682af46SSoren Brinkmann 	pll->pll_ctrl = pll_ctrl;
2083682af46SSoren Brinkmann 	pll->pll_status = pll_status;
2093682af46SSoren Brinkmann 	pll->lockbit = lock_index;
2103682af46SSoren Brinkmann 	pll->lock = lock;
2113682af46SSoren Brinkmann 
2123682af46SSoren Brinkmann 	spin_lock_irqsave(pll->lock, flags);
2133682af46SSoren Brinkmann 
2145834fd75SJonas Gorski 	reg = readl(pll->pll_ctrl);
2153682af46SSoren Brinkmann 	reg &= ~PLLCTRL_BPQUAL_MASK;
2165834fd75SJonas Gorski 	writel(reg, pll->pll_ctrl);
2173682af46SSoren Brinkmann 
2183682af46SSoren Brinkmann 	spin_unlock_irqrestore(pll->lock, flags);
2193682af46SSoren Brinkmann 
2203682af46SSoren Brinkmann 	clk = clk_register(NULL, &pll->hw);
2213682af46SSoren Brinkmann 	if (WARN_ON(IS_ERR(clk)))
2223682af46SSoren Brinkmann 		goto free_pll;
2233682af46SSoren Brinkmann 
2243682af46SSoren Brinkmann 	return clk;
2253682af46SSoren Brinkmann 
2263682af46SSoren Brinkmann free_pll:
2273682af46SSoren Brinkmann 	kfree(pll);
2283682af46SSoren Brinkmann 
2293682af46SSoren Brinkmann 	return clk;
2303682af46SSoren Brinkmann }
231