162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2021 NXP
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/bitfield.h>
762306a36Sopenharmony_ci#include <linux/clk-provider.h>
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/iopoll.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <asm/div64.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "clk.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define PLL_CTRL		0x0
1862306a36Sopenharmony_ci#define HW_CTRL_SEL		BIT(16)
1962306a36Sopenharmony_ci#define CLKMUX_BYPASS		BIT(2)
2062306a36Sopenharmony_ci#define CLKMUX_EN		BIT(1)
2162306a36Sopenharmony_ci#define POWERUP_MASK		BIT(0)
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define PLL_ANA_PRG		0x10
2462306a36Sopenharmony_ci#define PLL_SPREAD_SPECTRUM	0x30
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define PLL_NUMERATOR		0x40
2762306a36Sopenharmony_ci#define PLL_MFN_MASK		GENMASK(31, 2)
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define PLL_DENOMINATOR		0x50
3062306a36Sopenharmony_ci#define PLL_MFD_MASK		GENMASK(29, 0)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define PLL_DIV			0x60
3362306a36Sopenharmony_ci#define PLL_MFI_MASK		GENMASK(24, 16)
3462306a36Sopenharmony_ci#define PLL_RDIV_MASK		GENMASK(15, 13)
3562306a36Sopenharmony_ci#define PLL_ODIV_MASK		GENMASK(7, 0)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define PLL_DFS_CTRL(x)		(0x70 + (x) * 0x10)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define PLL_STATUS		0xF0
4062306a36Sopenharmony_ci#define LOCK_STATUS		BIT(0)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define DFS_STATUS		0xF4
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define LOCK_TIMEOUT_US		200
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv)	\
4762306a36Sopenharmony_ci	{							\
4862306a36Sopenharmony_ci		.rate	=	(_rate),			\
4962306a36Sopenharmony_ci		.mfi	=	(_mfi),				\
5062306a36Sopenharmony_ci		.mfn	=	(_mfn),				\
5162306a36Sopenharmony_ci		.mfd	=	(_mfd),				\
5262306a36Sopenharmony_ci		.rdiv	=	(_rdiv),			\
5362306a36Sopenharmony_ci		.odiv	=	(_odiv),			\
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv)		\
5762306a36Sopenharmony_ci	{							\
5862306a36Sopenharmony_ci		.rate	=	(_rate),			\
5962306a36Sopenharmony_ci		.mfi	=	(_mfi),				\
6062306a36Sopenharmony_ci		.mfn	=	0,				\
6162306a36Sopenharmony_ci		.mfd	=	0,				\
6262306a36Sopenharmony_ci		.rdiv	=	(_rdiv),			\
6362306a36Sopenharmony_ci		.odiv	=	(_odiv),			\
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistruct clk_fracn_gppll {
6762306a36Sopenharmony_ci	struct clk_hw			hw;
6862306a36Sopenharmony_ci	void __iomem			*base;
6962306a36Sopenharmony_ci	const struct imx_fracn_gppll_rate_table *rate_table;
7062306a36Sopenharmony_ci	int rate_count;
7162306a36Sopenharmony_ci	u32 flags;
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * Fvco = (Fref / rdiv) * (MFI + MFN / MFD)
7662306a36Sopenharmony_ci * Fout = Fvco / odiv
7762306a36Sopenharmony_ci * The (Fref / rdiv) should be in range 20MHz to 40MHz
7862306a36Sopenharmony_ci * The Fvco should be in range 2.5Ghz to 5Ghz
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_cistatic const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
8162306a36Sopenharmony_ci	PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6),
8262306a36Sopenharmony_ci	PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8),
8362306a36Sopenharmony_ci	PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6),
8462306a36Sopenharmony_ci	PLL_FRACN_GP(519750000U, 173, 25, 100, 1, 8),
8562306a36Sopenharmony_ci	PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8),
8662306a36Sopenharmony_ci	PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6),
8762306a36Sopenharmony_ci	PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
8862306a36Sopenharmony_ci	PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
8962306a36Sopenharmony_ci	PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
9062306a36Sopenharmony_ci	PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistruct imx_fracn_gppll_clk imx_fracn_gppll = {
9462306a36Sopenharmony_ci	.rate_table = fracn_tbl,
9562306a36Sopenharmony_ci	.rate_count = ARRAY_SIZE(fracn_tbl),
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_fracn_gppll);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/*
10062306a36Sopenharmony_ci * Fvco = (Fref / rdiv) * MFI
10162306a36Sopenharmony_ci * Fout = Fvco / odiv
10262306a36Sopenharmony_ci * The (Fref / rdiv) should be in range 20MHz to 40MHz
10362306a36Sopenharmony_ci * The Fvco should be in range 2.5Ghz to 5Ghz
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_cistatic const struct imx_fracn_gppll_rate_table int_tbl[] = {
10662306a36Sopenharmony_ci	PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2),
10762306a36Sopenharmony_ci	PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3),
10862306a36Sopenharmony_ci	PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4),
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct imx_fracn_gppll_clk imx_fracn_gppll_integer = {
11262306a36Sopenharmony_ci	.rate_table = int_tbl,
11362306a36Sopenharmony_ci	.rate_count = ARRAY_SIZE(int_tbl),
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_fracn_gppll_integer);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	return container_of(hw, struct clk_fracn_gppll, hw);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const struct imx_fracn_gppll_rate_table *
12362306a36Sopenharmony_ciimx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
12662306a36Sopenharmony_ci	int i;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++)
12962306a36Sopenharmony_ci		if (rate == rate_table[i].rate)
13062306a36Sopenharmony_ci			return &rate_table[i];
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return NULL;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate,
13662306a36Sopenharmony_ci				       unsigned long *prate)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
13962306a36Sopenharmony_ci	const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
14062306a36Sopenharmony_ci	int i;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Assuming rate_table is in descending order */
14362306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++)
14462306a36Sopenharmony_ci		if (rate >= rate_table[i].rate)
14562306a36Sopenharmony_ci			return rate_table[i].rate;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/* return minimum supported value */
14862306a36Sopenharmony_ci	return rate_table[pll->rate_count - 1].rate;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
15462306a36Sopenharmony_ci	const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
15562306a36Sopenharmony_ci	u32 pll_numerator, pll_denominator, pll_div;
15662306a36Sopenharmony_ci	u32 mfi, mfn, mfd, rdiv, odiv;
15762306a36Sopenharmony_ci	u64 fvco = parent_rate;
15862306a36Sopenharmony_ci	long rate = 0;
15962306a36Sopenharmony_ci	int i;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
16262306a36Sopenharmony_ci	mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
16562306a36Sopenharmony_ci	mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	pll_div = readl_relaxed(pll->base + PLL_DIV);
16862306a36Sopenharmony_ci	mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
17162306a36Sopenharmony_ci	odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/*
17462306a36Sopenharmony_ci	 * Sometimes, the recalculated rate has deviation due to
17562306a36Sopenharmony_ci	 * the frac part. So find the accurate pll rate from the table
17662306a36Sopenharmony_ci	 * first, if no match rate in the table, use the rate calculated
17762306a36Sopenharmony_ci	 * from the equation below.
17862306a36Sopenharmony_ci	 */
17962306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++) {
18062306a36Sopenharmony_ci		if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi &&
18162306a36Sopenharmony_ci		    rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv &&
18262306a36Sopenharmony_ci		    rate_table[i].odiv == odiv)
18362306a36Sopenharmony_ci			rate = rate_table[i].rate;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (rate)
18762306a36Sopenharmony_ci		return (unsigned long)rate;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (!rdiv)
19062306a36Sopenharmony_ci		rdiv = rdiv + 1;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	switch (odiv) {
19362306a36Sopenharmony_ci	case 0:
19462306a36Sopenharmony_ci		odiv = 2;
19562306a36Sopenharmony_ci		break;
19662306a36Sopenharmony_ci	case 1:
19762306a36Sopenharmony_ci		odiv = 3;
19862306a36Sopenharmony_ci		break;
19962306a36Sopenharmony_ci	default:
20062306a36Sopenharmony_ci		break;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (pll->flags & CLK_FRACN_GPPLL_INTEGER) {
20462306a36Sopenharmony_ci		/* Fvco = (Fref / rdiv) * MFI */
20562306a36Sopenharmony_ci		fvco = fvco * mfi;
20662306a36Sopenharmony_ci		do_div(fvco, rdiv * odiv);
20762306a36Sopenharmony_ci	} else {
20862306a36Sopenharmony_ci		/* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */
20962306a36Sopenharmony_ci		fvco = fvco * mfi * mfd + fvco * mfn;
21062306a36Sopenharmony_ci		do_div(fvco, mfd * rdiv * odiv);
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return (unsigned long)fvco;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	u32 val;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return readl_poll_timeout(pll->base + PLL_STATUS, val,
22162306a36Sopenharmony_ci				  val & LOCK_STATUS, 0, LOCK_TIMEOUT_US);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
22562306a36Sopenharmony_ci				    unsigned long prate)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
22862306a36Sopenharmony_ci	const struct imx_fracn_gppll_rate_table *rate;
22962306a36Sopenharmony_ci	u32 tmp, pll_div, ana_mfn;
23062306a36Sopenharmony_ci	int ret;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	rate = imx_get_pll_settings(pll, drate);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Hardware control select disable. PLL is control by register */
23562306a36Sopenharmony_ci	tmp = readl_relaxed(pll->base + PLL_CTRL);
23662306a36Sopenharmony_ci	tmp &= ~HW_CTRL_SEL;
23762306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + PLL_CTRL);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Disable output */
24062306a36Sopenharmony_ci	tmp = readl_relaxed(pll->base + PLL_CTRL);
24162306a36Sopenharmony_ci	tmp &= ~CLKMUX_EN;
24262306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + PLL_CTRL);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/* Power Down */
24562306a36Sopenharmony_ci	tmp &= ~POWERUP_MASK;
24662306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + PLL_CTRL);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* Disable BYPASS */
24962306a36Sopenharmony_ci	tmp &= ~CLKMUX_BYPASS;
25062306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + PLL_CTRL);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
25362306a36Sopenharmony_ci		FIELD_PREP(PLL_MFI_MASK, rate->mfi);
25462306a36Sopenharmony_ci	writel_relaxed(pll_div, pll->base + PLL_DIV);
25562306a36Sopenharmony_ci	if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
25662306a36Sopenharmony_ci		writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
25762306a36Sopenharmony_ci		writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* Wait for 5us according to fracn mode pll doc */
26162306a36Sopenharmony_ci	udelay(5);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Enable Powerup */
26462306a36Sopenharmony_ci	tmp |= POWERUP_MASK;
26562306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + PLL_CTRL);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/* Wait Lock */
26862306a36Sopenharmony_ci	ret = clk_fracn_gppll_wait_lock(pll);
26962306a36Sopenharmony_ci	if (ret)
27062306a36Sopenharmony_ci		return ret;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Enable output */
27362306a36Sopenharmony_ci	tmp |= CLKMUX_EN;
27462306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + PLL_CTRL);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	ana_mfn = readl_relaxed(pll->base + PLL_STATUS);
27762306a36Sopenharmony_ci	ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n");
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return 0;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic int clk_fracn_gppll_prepare(struct clk_hw *hw)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
28762306a36Sopenharmony_ci	u32 val;
28862306a36Sopenharmony_ci	int ret;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CTRL);
29162306a36Sopenharmony_ci	if (val & POWERUP_MASK)
29262306a36Sopenharmony_ci		return 0;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	val |= CLKMUX_BYPASS;
29562306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CTRL);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	val |= POWERUP_MASK;
29862306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CTRL);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	val |= CLKMUX_EN;
30162306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CTRL);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ret = clk_fracn_gppll_wait_lock(pll);
30462306a36Sopenharmony_ci	if (ret)
30562306a36Sopenharmony_ci		return ret;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	val &= ~CLKMUX_BYPASS;
30862306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CTRL);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return 0;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic int clk_fracn_gppll_is_prepared(struct clk_hw *hw)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
31662306a36Sopenharmony_ci	u32 val;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CTRL);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return (val & POWERUP_MASK) ? 1 : 0;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic void clk_fracn_gppll_unprepare(struct clk_hw *hw)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
32662306a36Sopenharmony_ci	u32 val;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CTRL);
32962306a36Sopenharmony_ci	val &= ~POWERUP_MASK;
33062306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CTRL);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic const struct clk_ops clk_fracn_gppll_ops = {
33462306a36Sopenharmony_ci	.prepare	= clk_fracn_gppll_prepare,
33562306a36Sopenharmony_ci	.unprepare	= clk_fracn_gppll_unprepare,
33662306a36Sopenharmony_ci	.is_prepared	= clk_fracn_gppll_is_prepared,
33762306a36Sopenharmony_ci	.recalc_rate	= clk_fracn_gppll_recalc_rate,
33862306a36Sopenharmony_ci	.round_rate	= clk_fracn_gppll_round_rate,
33962306a36Sopenharmony_ci	.set_rate	= clk_fracn_gppll_set_rate,
34062306a36Sopenharmony_ci};
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name,
34362306a36Sopenharmony_ci					   void __iomem *base,
34462306a36Sopenharmony_ci					   const struct imx_fracn_gppll_clk *pll_clk,
34562306a36Sopenharmony_ci					   u32 pll_flags)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct clk_fracn_gppll *pll;
34862306a36Sopenharmony_ci	struct clk_hw *hw;
34962306a36Sopenharmony_ci	struct clk_init_data init;
35062306a36Sopenharmony_ci	int ret;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
35362306a36Sopenharmony_ci	if (!pll)
35462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	init.name = name;
35762306a36Sopenharmony_ci	init.flags = pll_clk->flags;
35862306a36Sopenharmony_ci	init.parent_names = &parent_name;
35962306a36Sopenharmony_ci	init.num_parents = 1;
36062306a36Sopenharmony_ci	init.ops = &clk_fracn_gppll_ops;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	pll->base = base;
36362306a36Sopenharmony_ci	pll->hw.init = &init;
36462306a36Sopenharmony_ci	pll->rate_table = pll_clk->rate_table;
36562306a36Sopenharmony_ci	pll->rate_count = pll_clk->rate_count;
36662306a36Sopenharmony_ci	pll->flags = pll_flags;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	hw = &pll->hw;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ret = clk_hw_register(NULL, hw);
37162306a36Sopenharmony_ci	if (ret) {
37262306a36Sopenharmony_ci		pr_err("%s: failed to register pll %s %d\n", __func__, name, ret);
37362306a36Sopenharmony_ci		kfree(pll);
37462306a36Sopenharmony_ci		return ERR_PTR(ret);
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return hw;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistruct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
38162306a36Sopenharmony_ci				   const struct imx_fracn_gppll_clk *pll_clk)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_clk_fracn_gppll);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistruct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
38862306a36Sopenharmony_ci					   void __iomem *base,
38962306a36Sopenharmony_ci					   const struct imx_fracn_gppll_clk *pll_clk)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer);
394