18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2017-2018 NXP.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/bits.h>
78c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "clk.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define GNRL_CTL	0x0
188c2ecf20Sopenharmony_ci#define DIV_CTL		0x4
198c2ecf20Sopenharmony_ci#define LOCK_STATUS	BIT(31)
208c2ecf20Sopenharmony_ci#define LOCK_SEL_MASK	BIT(29)
218c2ecf20Sopenharmony_ci#define CLKE_MASK	BIT(11)
228c2ecf20Sopenharmony_ci#define RST_MASK	BIT(9)
238c2ecf20Sopenharmony_ci#define BYPASS_MASK	BIT(4)
248c2ecf20Sopenharmony_ci#define MDIV_SHIFT	12
258c2ecf20Sopenharmony_ci#define MDIV_MASK	GENMASK(21, 12)
268c2ecf20Sopenharmony_ci#define PDIV_SHIFT	4
278c2ecf20Sopenharmony_ci#define PDIV_MASK	GENMASK(9, 4)
288c2ecf20Sopenharmony_ci#define SDIV_SHIFT	0
298c2ecf20Sopenharmony_ci#define SDIV_MASK	GENMASK(2, 0)
308c2ecf20Sopenharmony_ci#define KDIV_SHIFT	0
318c2ecf20Sopenharmony_ci#define KDIV_MASK	GENMASK(15, 0)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define LOCK_TIMEOUT_US		10000
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct clk_pll14xx {
368c2ecf20Sopenharmony_ci	struct clk_hw			hw;
378c2ecf20Sopenharmony_ci	void __iomem			*base;
388c2ecf20Sopenharmony_ci	enum imx_pll14xx_type		type;
398c2ecf20Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate_table;
408c2ecf20Sopenharmony_ci	int rate_count;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = {
468c2ecf20Sopenharmony_ci	PLL_1416X_RATE(1800000000U, 225, 3, 0),
478c2ecf20Sopenharmony_ci	PLL_1416X_RATE(1600000000U, 200, 3, 0),
488c2ecf20Sopenharmony_ci	PLL_1416X_RATE(1500000000U, 375, 3, 1),
498c2ecf20Sopenharmony_ci	PLL_1416X_RATE(1400000000U, 350, 3, 1),
508c2ecf20Sopenharmony_ci	PLL_1416X_RATE(1200000000U, 300, 3, 1),
518c2ecf20Sopenharmony_ci	PLL_1416X_RATE(1000000000U, 250, 3, 1),
528c2ecf20Sopenharmony_ci	PLL_1416X_RATE(800000000U,  200, 3, 1),
538c2ecf20Sopenharmony_ci	PLL_1416X_RATE(750000000U,  250, 2, 2),
548c2ecf20Sopenharmony_ci	PLL_1416X_RATE(700000000U,  350, 3, 2),
558c2ecf20Sopenharmony_ci	PLL_1416X_RATE(600000000U,  300, 3, 2),
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {
598c2ecf20Sopenharmony_ci	PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384),
608c2ecf20Sopenharmony_ci	PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
618c2ecf20Sopenharmony_ci	PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
628c2ecf20Sopenharmony_ci	PLL_1443X_RATE(519750000U, 173, 2, 2, 16384),
638c2ecf20Sopenharmony_ci	PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
648c2ecf20Sopenharmony_ci	PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistruct imx_pll14xx_clk imx_1443x_pll = {
688c2ecf20Sopenharmony_ci	.type = PLL_1443X,
698c2ecf20Sopenharmony_ci	.rate_table = imx_pll1443x_tbl,
708c2ecf20Sopenharmony_ci	.rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1443x_pll);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistruct imx_pll14xx_clk imx_1443x_dram_pll = {
758c2ecf20Sopenharmony_ci	.type = PLL_1443X,
768c2ecf20Sopenharmony_ci	.rate_table = imx_pll1443x_tbl,
778c2ecf20Sopenharmony_ci	.rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
788c2ecf20Sopenharmony_ci	.flags = CLK_GET_RATE_NOCACHE,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1443x_dram_pll);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistruct imx_pll14xx_clk imx_1416x_pll = {
838c2ecf20Sopenharmony_ci	.type = PLL_1416X,
848c2ecf20Sopenharmony_ci	.rate_table = imx_pll1416x_tbl,
858c2ecf20Sopenharmony_ci	.rate_count = ARRAY_SIZE(imx_pll1416x_tbl),
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1416x_pll);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic const struct imx_pll14xx_rate_table *imx_get_pll_settings(
908c2ecf20Sopenharmony_ci		struct clk_pll14xx *pll, unsigned long rate)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
938c2ecf20Sopenharmony_ci	int i;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++)
968c2ecf20Sopenharmony_ci		if (rate == rate_table[i].rate)
978c2ecf20Sopenharmony_ci			return &rate_table[i];
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return NULL;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic long clk_pll14xx_round_rate(struct clk_hw *hw, unsigned long rate,
1038c2ecf20Sopenharmony_ci			unsigned long *prate)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
1068c2ecf20Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
1078c2ecf20Sopenharmony_ci	int i;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* Assumming rate_table is in descending order */
1108c2ecf20Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++)
1118c2ecf20Sopenharmony_ci		if (rate >= rate_table[i].rate)
1128c2ecf20Sopenharmony_ci			return rate_table[i].rate;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* return minimum supported value */
1158c2ecf20Sopenharmony_ci	return rate_table[i - 1].rate;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic unsigned long clk_pll1416x_recalc_rate(struct clk_hw *hw,
1198c2ecf20Sopenharmony_ci						  unsigned long parent_rate)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
1228c2ecf20Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_div;
1238c2ecf20Sopenharmony_ci	u64 fvco = parent_rate;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	pll_div = readl_relaxed(pll->base + 4);
1268c2ecf20Sopenharmony_ci	mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
1278c2ecf20Sopenharmony_ci	pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
1288c2ecf20Sopenharmony_ci	sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	fvco *= mdiv;
1318c2ecf20Sopenharmony_ci	do_div(fvco, pdiv << sdiv);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return fvco;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
1378c2ecf20Sopenharmony_ci						  unsigned long parent_rate)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
1408c2ecf20Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
1418c2ecf20Sopenharmony_ci	short int kdiv;
1428c2ecf20Sopenharmony_ci	u64 fvco = parent_rate;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	pll_div_ctl0 = readl_relaxed(pll->base + 4);
1458c2ecf20Sopenharmony_ci	pll_div_ctl1 = readl_relaxed(pll->base + 8);
1468c2ecf20Sopenharmony_ci	mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
1478c2ecf20Sopenharmony_ci	pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
1488c2ecf20Sopenharmony_ci	sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
1498c2ecf20Sopenharmony_ci	kdiv = pll_div_ctl1 & KDIV_MASK;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
1528c2ecf20Sopenharmony_ci	fvco *= (mdiv * 65536 + kdiv);
1538c2ecf20Sopenharmony_ci	pdiv *= 65536;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	do_div(fvco, pdiv << sdiv);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return fvco;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate,
1618c2ecf20Sopenharmony_ci					  u32 pll_div)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	u32 old_mdiv, old_pdiv;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
1668c2ecf20Sopenharmony_ci	old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	u32 val;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return readl_poll_timeout(pll->base, val, val & LOCK_STATUS, 0,
1768c2ecf20Sopenharmony_ci			LOCK_TIMEOUT_US);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
1808c2ecf20Sopenharmony_ci				 unsigned long prate)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
1838c2ecf20Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate;
1848c2ecf20Sopenharmony_ci	u32 tmp, div_val;
1858c2ecf20Sopenharmony_ci	int ret;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	rate = imx_get_pll_settings(pll, drate);
1888c2ecf20Sopenharmony_ci	if (!rate) {
1898c2ecf20Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1908c2ecf20Sopenharmony_ci		       drate, clk_hw_get_name(hw));
1918c2ecf20Sopenharmony_ci		return -EINVAL;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	tmp = readl_relaxed(pll->base + 4);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (!clk_pll14xx_mp_change(rate, tmp)) {
1978c2ecf20Sopenharmony_ci		tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
1988c2ecf20Sopenharmony_ci		tmp |= rate->sdiv << SDIV_SHIFT;
1998c2ecf20Sopenharmony_ci		writel_relaxed(tmp, pll->base + 4);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		return 0;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* Bypass clock and set lock to pll output lock */
2058c2ecf20Sopenharmony_ci	tmp = readl_relaxed(pll->base);
2068c2ecf20Sopenharmony_ci	tmp |= LOCK_SEL_MASK;
2078c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* Enable RST */
2108c2ecf20Sopenharmony_ci	tmp &= ~RST_MASK;
2118c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/* Enable BYPASS */
2148c2ecf20Sopenharmony_ci	tmp |= BYPASS_MASK;
2158c2ecf20Sopenharmony_ci	writel(tmp, pll->base);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
2188c2ecf20Sopenharmony_ci		(rate->sdiv << SDIV_SHIFT);
2198c2ecf20Sopenharmony_ci	writel_relaxed(div_val, pll->base + 0x4);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * According to SPEC, t3 - t2 need to be greater than
2238c2ecf20Sopenharmony_ci	 * 1us and 1/FREF, respectively.
2248c2ecf20Sopenharmony_ci	 * FREF is FIN / Prediv, the prediv is [1, 63], so choose
2258c2ecf20Sopenharmony_ci	 * 3us.
2268c2ecf20Sopenharmony_ci	 */
2278c2ecf20Sopenharmony_ci	udelay(3);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* Disable RST */
2308c2ecf20Sopenharmony_ci	tmp |= RST_MASK;
2318c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* Wait Lock */
2348c2ecf20Sopenharmony_ci	ret = clk_pll14xx_wait_lock(pll);
2358c2ecf20Sopenharmony_ci	if (ret)
2368c2ecf20Sopenharmony_ci		return ret;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Bypass */
2398c2ecf20Sopenharmony_ci	tmp &= ~BYPASS_MASK;
2408c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	return 0;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
2468c2ecf20Sopenharmony_ci				 unsigned long prate)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
2498c2ecf20Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate;
2508c2ecf20Sopenharmony_ci	u32 tmp, div_val;
2518c2ecf20Sopenharmony_ci	int ret;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	rate = imx_get_pll_settings(pll, drate);
2548c2ecf20Sopenharmony_ci	if (!rate) {
2558c2ecf20Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
2568c2ecf20Sopenharmony_ci			drate, clk_hw_get_name(hw));
2578c2ecf20Sopenharmony_ci		return -EINVAL;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	tmp = readl_relaxed(pll->base + 4);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (!clk_pll14xx_mp_change(rate, tmp)) {
2638c2ecf20Sopenharmony_ci		tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
2648c2ecf20Sopenharmony_ci		tmp |= rate->sdiv << SDIV_SHIFT;
2658c2ecf20Sopenharmony_ci		writel_relaxed(tmp, pll->base + 4);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		tmp = rate->kdiv << KDIV_SHIFT;
2688c2ecf20Sopenharmony_ci		writel_relaxed(tmp, pll->base + 8);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		return 0;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* Enable RST */
2748c2ecf20Sopenharmony_ci	tmp = readl_relaxed(pll->base);
2758c2ecf20Sopenharmony_ci	tmp &= ~RST_MASK;
2768c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	/* Enable BYPASS */
2798c2ecf20Sopenharmony_ci	tmp |= BYPASS_MASK;
2808c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
2838c2ecf20Sopenharmony_ci		(rate->sdiv << SDIV_SHIFT);
2848c2ecf20Sopenharmony_ci	writel_relaxed(div_val, pll->base + 0x4);
2858c2ecf20Sopenharmony_ci	writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/*
2888c2ecf20Sopenharmony_ci	 * According to SPEC, t3 - t2 need to be greater than
2898c2ecf20Sopenharmony_ci	 * 1us and 1/FREF, respectively.
2908c2ecf20Sopenharmony_ci	 * FREF is FIN / Prediv, the prediv is [1, 63], so choose
2918c2ecf20Sopenharmony_ci	 * 3us.
2928c2ecf20Sopenharmony_ci	 */
2938c2ecf20Sopenharmony_ci	udelay(3);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* Disable RST */
2968c2ecf20Sopenharmony_ci	tmp |= RST_MASK;
2978c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/* Wait Lock*/
3008c2ecf20Sopenharmony_ci	ret = clk_pll14xx_wait_lock(pll);
3018c2ecf20Sopenharmony_ci	if (ret)
3028c2ecf20Sopenharmony_ci		return ret;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* Bypass */
3058c2ecf20Sopenharmony_ci	tmp &= ~BYPASS_MASK;
3068c2ecf20Sopenharmony_ci	writel_relaxed(tmp, pll->base);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return 0;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int clk_pll14xx_prepare(struct clk_hw *hw)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
3148c2ecf20Sopenharmony_ci	u32 val;
3158c2ecf20Sopenharmony_ci	int ret;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/*
3188c2ecf20Sopenharmony_ci	 * RESETB = 1 from 0, PLL starts its normal
3198c2ecf20Sopenharmony_ci	 * operation after lock time
3208c2ecf20Sopenharmony_ci	 */
3218c2ecf20Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
3228c2ecf20Sopenharmony_ci	if (val & RST_MASK)
3238c2ecf20Sopenharmony_ci		return 0;
3248c2ecf20Sopenharmony_ci	val |= BYPASS_MASK;
3258c2ecf20Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
3268c2ecf20Sopenharmony_ci	val |= RST_MASK;
3278c2ecf20Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	ret = clk_pll14xx_wait_lock(pll);
3308c2ecf20Sopenharmony_ci	if (ret)
3318c2ecf20Sopenharmony_ci		return ret;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	val &= ~BYPASS_MASK;
3348c2ecf20Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return 0;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int clk_pll14xx_is_prepared(struct clk_hw *hw)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
3428c2ecf20Sopenharmony_ci	u32 val;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return (val & RST_MASK) ? 1 : 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic void clk_pll14xx_unprepare(struct clk_hw *hw)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
3528c2ecf20Sopenharmony_ci	u32 val;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/*
3558c2ecf20Sopenharmony_ci	 * Set RST to 0, power down mode is enabled and
3568c2ecf20Sopenharmony_ci	 * every digital block is reset
3578c2ecf20Sopenharmony_ci	 */
3588c2ecf20Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
3598c2ecf20Sopenharmony_ci	val &= ~RST_MASK;
3608c2ecf20Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic const struct clk_ops clk_pll1416x_ops = {
3648c2ecf20Sopenharmony_ci	.prepare	= clk_pll14xx_prepare,
3658c2ecf20Sopenharmony_ci	.unprepare	= clk_pll14xx_unprepare,
3668c2ecf20Sopenharmony_ci	.is_prepared	= clk_pll14xx_is_prepared,
3678c2ecf20Sopenharmony_ci	.recalc_rate	= clk_pll1416x_recalc_rate,
3688c2ecf20Sopenharmony_ci	.round_rate	= clk_pll14xx_round_rate,
3698c2ecf20Sopenharmony_ci	.set_rate	= clk_pll1416x_set_rate,
3708c2ecf20Sopenharmony_ci};
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic const struct clk_ops clk_pll1416x_min_ops = {
3738c2ecf20Sopenharmony_ci	.recalc_rate	= clk_pll1416x_recalc_rate,
3748c2ecf20Sopenharmony_ci};
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic const struct clk_ops clk_pll1443x_ops = {
3778c2ecf20Sopenharmony_ci	.prepare	= clk_pll14xx_prepare,
3788c2ecf20Sopenharmony_ci	.unprepare	= clk_pll14xx_unprepare,
3798c2ecf20Sopenharmony_ci	.is_prepared	= clk_pll14xx_is_prepared,
3808c2ecf20Sopenharmony_ci	.recalc_rate	= clk_pll1443x_recalc_rate,
3818c2ecf20Sopenharmony_ci	.round_rate	= clk_pll14xx_round_rate,
3828c2ecf20Sopenharmony_ci	.set_rate	= clk_pll1443x_set_rate,
3838c2ecf20Sopenharmony_ci};
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistruct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
3868c2ecf20Sopenharmony_ci				const char *parent_name, void __iomem *base,
3878c2ecf20Sopenharmony_ci				const struct imx_pll14xx_clk *pll_clk)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct clk_pll14xx *pll;
3908c2ecf20Sopenharmony_ci	struct clk_hw *hw;
3918c2ecf20Sopenharmony_ci	struct clk_init_data init;
3928c2ecf20Sopenharmony_ci	int ret;
3938c2ecf20Sopenharmony_ci	u32 val;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
3968c2ecf20Sopenharmony_ci	if (!pll)
3978c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	init.name = name;
4008c2ecf20Sopenharmony_ci	init.flags = pll_clk->flags;
4018c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
4028c2ecf20Sopenharmony_ci	init.num_parents = 1;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	switch (pll_clk->type) {
4058c2ecf20Sopenharmony_ci	case PLL_1416X:
4068c2ecf20Sopenharmony_ci		if (!pll_clk->rate_table)
4078c2ecf20Sopenharmony_ci			init.ops = &clk_pll1416x_min_ops;
4088c2ecf20Sopenharmony_ci		else
4098c2ecf20Sopenharmony_ci			init.ops = &clk_pll1416x_ops;
4108c2ecf20Sopenharmony_ci		break;
4118c2ecf20Sopenharmony_ci	case PLL_1443X:
4128c2ecf20Sopenharmony_ci		init.ops = &clk_pll1443x_ops;
4138c2ecf20Sopenharmony_ci		break;
4148c2ecf20Sopenharmony_ci	default:
4158c2ecf20Sopenharmony_ci		pr_err("%s: Unknown pll type for pll clk %s\n",
4168c2ecf20Sopenharmony_ci		       __func__, name);
4178c2ecf20Sopenharmony_ci		kfree(pll);
4188c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
4198c2ecf20Sopenharmony_ci	};
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	pll->base = base;
4228c2ecf20Sopenharmony_ci	pll->hw.init = &init;
4238c2ecf20Sopenharmony_ci	pll->type = pll_clk->type;
4248c2ecf20Sopenharmony_ci	pll->rate_table = pll_clk->rate_table;
4258c2ecf20Sopenharmony_ci	pll->rate_count = pll_clk->rate_count;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
4288c2ecf20Sopenharmony_ci	val &= ~BYPASS_MASK;
4298c2ecf20Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	hw = &pll->hw;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	ret = clk_hw_register(dev, hw);
4348c2ecf20Sopenharmony_ci	if (ret) {
4358c2ecf20Sopenharmony_ci		pr_err("%s: failed to register pll %s %d\n",
4368c2ecf20Sopenharmony_ci			__func__, name, ret);
4378c2ecf20Sopenharmony_ci		kfree(pll);
4388c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return hw;
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx);
444