162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2013 Samsung Electronics Co., Ltd.
462306a36Sopenharmony_ci * Copyright (c) 2013 Linaro Ltd.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This file contains the utility functions to register the pll clocks.
762306a36Sopenharmony_ci*/
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/hrtimer.h>
1162306a36Sopenharmony_ci#include <linux/iopoll.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/timekeeping.h>
1562306a36Sopenharmony_ci#include <linux/clk-provider.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci#include "clk.h"
1862306a36Sopenharmony_ci#include "clk-pll.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define PLL_TIMEOUT_US		20000U
2162306a36Sopenharmony_ci#define PLL_TIMEOUT_LOOPS	1000000U
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct samsung_clk_pll {
2462306a36Sopenharmony_ci	struct clk_hw		hw;
2562306a36Sopenharmony_ci	void __iomem		*lock_reg;
2662306a36Sopenharmony_ci	void __iomem		*con_reg;
2762306a36Sopenharmony_ci	/* PLL enable control bit offset in @con_reg register */
2862306a36Sopenharmony_ci	unsigned short		enable_offs;
2962306a36Sopenharmony_ci	/* PLL lock status bit offset in @con_reg register */
3062306a36Sopenharmony_ci	unsigned short		lock_offs;
3162306a36Sopenharmony_ci	enum samsung_pll_type	type;
3262306a36Sopenharmony_ci	unsigned int		rate_count;
3362306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate_table;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic const struct samsung_pll_rate_table *samsung_get_pll_settings(
3962306a36Sopenharmony_ci				struct samsung_clk_pll *pll, unsigned long rate)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	const struct samsung_pll_rate_table  *rate_table = pll->rate_table;
4262306a36Sopenharmony_ci	int i;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++) {
4562306a36Sopenharmony_ci		if (rate == rate_table[i].rate)
4662306a36Sopenharmony_ci			return &rate_table[i];
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return NULL;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic long samsung_pll_round_rate(struct clk_hw *hw,
5362306a36Sopenharmony_ci			unsigned long drate, unsigned long *prate)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
5662306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate_table = pll->rate_table;
5762306a36Sopenharmony_ci	int i;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* Assumming rate_table is in descending order */
6062306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++) {
6162306a36Sopenharmony_ci		if (drate >= rate_table[i].rate)
6262306a36Sopenharmony_ci			return rate_table[i].rate;
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/* return minimum supported value */
6662306a36Sopenharmony_ci	return rate_table[i - 1].rate;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic bool pll_early_timeout = true;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int __init samsung_pll_disable_early_timeout(void)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	pll_early_timeout = false;
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ciarch_initcall(samsung_pll_disable_early_timeout);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* Wait until the PLL is locked */
7962306a36Sopenharmony_cistatic int samsung_pll_lock_wait(struct samsung_clk_pll *pll,
8062306a36Sopenharmony_ci				 unsigned int reg_mask)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	int i, ret;
8362306a36Sopenharmony_ci	u32 val;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/*
8662306a36Sopenharmony_ci	 * This function might be called when the timekeeping API can't be used
8762306a36Sopenharmony_ci	 * to detect timeouts. One situation is when the clocksource is not yet
8862306a36Sopenharmony_ci	 * initialized, another when the timekeeping is suspended. udelay() also
8962306a36Sopenharmony_ci	 * cannot be used when the clocksource is not running on arm64, since
9062306a36Sopenharmony_ci	 * the current timer is used as cycle counter. So a simple busy loop
9162306a36Sopenharmony_ci	 * is used here in that special cases. The limit of iterations has been
9262306a36Sopenharmony_ci	 * derived from experimental measurements of various PLLs on multiple
9362306a36Sopenharmony_ci	 * Exynos SoC variants. Single register read time was usually in range
9462306a36Sopenharmony_ci	 * 0.4...1.5 us, never less than 0.4 us.
9562306a36Sopenharmony_ci	 */
9662306a36Sopenharmony_ci	if (pll_early_timeout || timekeeping_suspended) {
9762306a36Sopenharmony_ci		i = PLL_TIMEOUT_LOOPS;
9862306a36Sopenharmony_ci		while (i-- > 0) {
9962306a36Sopenharmony_ci			if (readl_relaxed(pll->con_reg) & reg_mask)
10062306a36Sopenharmony_ci				return 0;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci			cpu_relax();
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci		ret = -ETIMEDOUT;
10562306a36Sopenharmony_ci	} else {
10662306a36Sopenharmony_ci		ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val,
10762306a36Sopenharmony_ci					val & reg_mask, 0, PLL_TIMEOUT_US);
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (ret < 0)
11162306a36Sopenharmony_ci		pr_err("Could not lock PLL %s\n", clk_hw_get_name(&pll->hw));
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return ret;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int samsung_pll3xxx_enable(struct clk_hw *hw)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
11962306a36Sopenharmony_ci	u32 tmp;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	tmp = readl_relaxed(pll->con_reg);
12262306a36Sopenharmony_ci	tmp |= BIT(pll->enable_offs);
12362306a36Sopenharmony_ci	writel_relaxed(tmp, pll->con_reg);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void samsung_pll3xxx_disable(struct clk_hw *hw)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
13162306a36Sopenharmony_ci	u32 tmp;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	tmp = readl_relaxed(pll->con_reg);
13462306a36Sopenharmony_ci	tmp &= ~BIT(pll->enable_offs);
13562306a36Sopenharmony_ci	writel_relaxed(tmp, pll->con_reg);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * PLL2126 Clock Type
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#define PLL2126_MDIV_MASK	(0xff)
14362306a36Sopenharmony_ci#define PLL2126_PDIV_MASK	(0x3f)
14462306a36Sopenharmony_ci#define PLL2126_SDIV_MASK	(0x3)
14562306a36Sopenharmony_ci#define PLL2126_MDIV_SHIFT	(16)
14662306a36Sopenharmony_ci#define PLL2126_PDIV_SHIFT	(8)
14762306a36Sopenharmony_ci#define PLL2126_SDIV_SHIFT	(0)
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
15062306a36Sopenharmony_ci				unsigned long parent_rate)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
15362306a36Sopenharmony_ci	u32 pll_con, mdiv, pdiv, sdiv;
15462306a36Sopenharmony_ci	u64 fvco = parent_rate;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	pll_con = readl_relaxed(pll->con_reg);
15762306a36Sopenharmony_ci	mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK;
15862306a36Sopenharmony_ci	pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK;
15962306a36Sopenharmony_ci	sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	fvco *= (mdiv + 8);
16262306a36Sopenharmony_ci	do_div(fvco, (pdiv + 2) << sdiv);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	return (unsigned long)fvco;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2126_clk_ops = {
16862306a36Sopenharmony_ci	.recalc_rate = samsung_pll2126_recalc_rate,
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/*
17262306a36Sopenharmony_ci * PLL3000 Clock Type
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#define PLL3000_MDIV_MASK	(0xff)
17662306a36Sopenharmony_ci#define PLL3000_PDIV_MASK	(0x3)
17762306a36Sopenharmony_ci#define PLL3000_SDIV_MASK	(0x3)
17862306a36Sopenharmony_ci#define PLL3000_MDIV_SHIFT	(16)
17962306a36Sopenharmony_ci#define PLL3000_PDIV_SHIFT	(8)
18062306a36Sopenharmony_ci#define PLL3000_SDIV_SHIFT	(0)
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
18362306a36Sopenharmony_ci				unsigned long parent_rate)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
18662306a36Sopenharmony_ci	u32 pll_con, mdiv, pdiv, sdiv;
18762306a36Sopenharmony_ci	u64 fvco = parent_rate;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	pll_con = readl_relaxed(pll->con_reg);
19062306a36Sopenharmony_ci	mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK;
19162306a36Sopenharmony_ci	pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK;
19262306a36Sopenharmony_ci	sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	fvco *= (2 * (mdiv + 8));
19562306a36Sopenharmony_ci	do_div(fvco, pdiv << sdiv);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return (unsigned long)fvco;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic const struct clk_ops samsung_pll3000_clk_ops = {
20162306a36Sopenharmony_ci	.recalc_rate = samsung_pll3000_recalc_rate,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/*
20562306a36Sopenharmony_ci * PLL35xx Clock Type
20662306a36Sopenharmony_ci */
20762306a36Sopenharmony_ci/* Maximum lock time can be 270 * PDIV cycles */
20862306a36Sopenharmony_ci#define PLL35XX_LOCK_FACTOR	(270)
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci#define PLL35XX_MDIV_MASK       (0x3FF)
21162306a36Sopenharmony_ci#define PLL35XX_PDIV_MASK       (0x3F)
21262306a36Sopenharmony_ci#define PLL35XX_SDIV_MASK       (0x7)
21362306a36Sopenharmony_ci#define PLL35XX_MDIV_SHIFT      (16)
21462306a36Sopenharmony_ci#define PLL35XX_PDIV_SHIFT      (8)
21562306a36Sopenharmony_ci#define PLL35XX_SDIV_SHIFT      (0)
21662306a36Sopenharmony_ci#define PLL35XX_LOCK_STAT_SHIFT	(29)
21762306a36Sopenharmony_ci#define PLL35XX_ENABLE_SHIFT	(31)
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
22062306a36Sopenharmony_ci				unsigned long parent_rate)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
22362306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con;
22462306a36Sopenharmony_ci	u64 fvco = parent_rate;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	pll_con = readl_relaxed(pll->con_reg);
22762306a36Sopenharmony_ci	mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
22862306a36Sopenharmony_ci	pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
22962306a36Sopenharmony_ci	sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	fvco *= mdiv;
23262306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return (unsigned long)fvco;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic inline bool samsung_pll35xx_mp_change(
23862306a36Sopenharmony_ci		const struct samsung_pll_rate_table *rate, u32 pll_con)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	u32 old_mdiv, old_pdiv;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
24362306a36Sopenharmony_ci	old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
24962306a36Sopenharmony_ci					unsigned long prate)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
25262306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
25362306a36Sopenharmony_ci	u32 tmp;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* Get required rate settings from table */
25662306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
25762306a36Sopenharmony_ci	if (!rate) {
25862306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
25962306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
26062306a36Sopenharmony_ci		return -EINVAL;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	tmp = readl_relaxed(pll->con_reg);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (!(samsung_pll35xx_mp_change(rate, tmp))) {
26662306a36Sopenharmony_ci		/* If only s change, change just s value only*/
26762306a36Sopenharmony_ci		tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
26862306a36Sopenharmony_ci		tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT;
26962306a36Sopenharmony_ci		writel_relaxed(tmp, pll->con_reg);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		return 0;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* Set PLL lock time. */
27562306a36Sopenharmony_ci	writel_relaxed(rate->pdiv * PLL35XX_LOCK_FACTOR,
27662306a36Sopenharmony_ci			pll->lock_reg);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* Change PLL PMS values */
27962306a36Sopenharmony_ci	tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
28062306a36Sopenharmony_ci			(PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) |
28162306a36Sopenharmony_ci			(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT));
28262306a36Sopenharmony_ci	tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) |
28362306a36Sopenharmony_ci			(rate->pdiv << PLL35XX_PDIV_SHIFT) |
28462306a36Sopenharmony_ci			(rate->sdiv << PLL35XX_SDIV_SHIFT);
28562306a36Sopenharmony_ci	writel_relaxed(tmp, pll->con_reg);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Wait for PLL lock if the PLL is enabled */
28862306a36Sopenharmony_ci	if (tmp & BIT(pll->enable_offs))
28962306a36Sopenharmony_ci		return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll35xx_clk_ops = {
29562306a36Sopenharmony_ci	.recalc_rate = samsung_pll35xx_recalc_rate,
29662306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
29762306a36Sopenharmony_ci	.set_rate = samsung_pll35xx_set_rate,
29862306a36Sopenharmony_ci	.enable = samsung_pll3xxx_enable,
29962306a36Sopenharmony_ci	.disable = samsung_pll3xxx_disable,
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic const struct clk_ops samsung_pll35xx_clk_min_ops = {
30362306a36Sopenharmony_ci	.recalc_rate = samsung_pll35xx_recalc_rate,
30462306a36Sopenharmony_ci};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/*
30762306a36Sopenharmony_ci * PLL36xx Clock Type
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_ci/* Maximum lock time can be 3000 * PDIV cycles */
31062306a36Sopenharmony_ci#define PLL36XX_LOCK_FACTOR    (3000)
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci#define PLL36XX_KDIV_MASK	(0xFFFF)
31362306a36Sopenharmony_ci#define PLL36XX_MDIV_MASK	(0x1FF)
31462306a36Sopenharmony_ci#define PLL36XX_PDIV_MASK	(0x3F)
31562306a36Sopenharmony_ci#define PLL36XX_SDIV_MASK	(0x7)
31662306a36Sopenharmony_ci#define PLL36XX_MDIV_SHIFT	(16)
31762306a36Sopenharmony_ci#define PLL36XX_PDIV_SHIFT	(8)
31862306a36Sopenharmony_ci#define PLL36XX_SDIV_SHIFT	(0)
31962306a36Sopenharmony_ci#define PLL36XX_KDIV_SHIFT	(0)
32062306a36Sopenharmony_ci#define PLL36XX_LOCK_STAT_SHIFT	(29)
32162306a36Sopenharmony_ci#define PLL36XX_ENABLE_SHIFT	(31)
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
32462306a36Sopenharmony_ci				unsigned long parent_rate)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
32762306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
32862306a36Sopenharmony_ci	s16 kdiv;
32962306a36Sopenharmony_ci	u64 fvco = parent_rate;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	pll_con0 = readl_relaxed(pll->con_reg);
33262306a36Sopenharmony_ci	pll_con1 = readl_relaxed(pll->con_reg + 4);
33362306a36Sopenharmony_ci	mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
33462306a36Sopenharmony_ci	pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
33562306a36Sopenharmony_ci	sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
33662306a36Sopenharmony_ci	kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	fvco *= (mdiv << 16) + kdiv;
33962306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
34062306a36Sopenharmony_ci	fvco >>= 16;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return (unsigned long)fvco;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic inline bool samsung_pll36xx_mpk_change(
34662306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	u32 old_mdiv, old_pdiv, old_kdiv;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
35162306a36Sopenharmony_ci	old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
35262306a36Sopenharmony_ci	old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
35562306a36Sopenharmony_ci		rate->kdiv != old_kdiv);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
35962306a36Sopenharmony_ci					unsigned long parent_rate)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
36262306a36Sopenharmony_ci	u32 pll_con0, pll_con1;
36362306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
36662306a36Sopenharmony_ci	if (!rate) {
36762306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
36862306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
36962306a36Sopenharmony_ci		return -EINVAL;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	pll_con0 = readl_relaxed(pll->con_reg);
37362306a36Sopenharmony_ci	pll_con1 = readl_relaxed(pll->con_reg + 4);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
37662306a36Sopenharmony_ci		/* If only s change, change just s value only*/
37762306a36Sopenharmony_ci		pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
37862306a36Sopenharmony_ci		pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
37962306a36Sopenharmony_ci		writel_relaxed(pll_con0, pll->con_reg);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		return 0;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/* Set PLL lock time. */
38562306a36Sopenharmony_ci	writel_relaxed(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	 /* Change PLL PMS values */
38862306a36Sopenharmony_ci	pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
38962306a36Sopenharmony_ci			(PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
39062306a36Sopenharmony_ci			(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
39162306a36Sopenharmony_ci	pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
39262306a36Sopenharmony_ci			(rate->pdiv << PLL36XX_PDIV_SHIFT) |
39362306a36Sopenharmony_ci			(rate->sdiv << PLL36XX_SDIV_SHIFT);
39462306a36Sopenharmony_ci	writel_relaxed(pll_con0, pll->con_reg);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
39762306a36Sopenharmony_ci	pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
39862306a36Sopenharmony_ci	writel_relaxed(pll_con1, pll->con_reg + 4);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (pll_con0 & BIT(pll->enable_offs))
40162306a36Sopenharmony_ci		return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll36xx_clk_ops = {
40762306a36Sopenharmony_ci	.recalc_rate = samsung_pll36xx_recalc_rate,
40862306a36Sopenharmony_ci	.set_rate = samsung_pll36xx_set_rate,
40962306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
41062306a36Sopenharmony_ci	.enable = samsung_pll3xxx_enable,
41162306a36Sopenharmony_ci	.disable = samsung_pll3xxx_disable,
41262306a36Sopenharmony_ci};
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll36xx_clk_min_ops = {
41562306a36Sopenharmony_ci	.recalc_rate = samsung_pll36xx_recalc_rate,
41662306a36Sopenharmony_ci};
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci/*
41962306a36Sopenharmony_ci * PLL0822x Clock Type
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_ci/* Maximum lock time can be 150 * PDIV cycles */
42262306a36Sopenharmony_ci#define PLL0822X_LOCK_FACTOR		(150)
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci#define PLL0822X_MDIV_MASK		(0x3FF)
42562306a36Sopenharmony_ci#define PLL0822X_PDIV_MASK		(0x3F)
42662306a36Sopenharmony_ci#define PLL0822X_SDIV_MASK		(0x7)
42762306a36Sopenharmony_ci#define PLL0822X_MDIV_SHIFT		(16)
42862306a36Sopenharmony_ci#define PLL0822X_PDIV_SHIFT		(8)
42962306a36Sopenharmony_ci#define PLL0822X_SDIV_SHIFT		(0)
43062306a36Sopenharmony_ci#define PLL0822X_LOCK_STAT_SHIFT	(29)
43162306a36Sopenharmony_ci#define PLL0822X_ENABLE_SHIFT		(31)
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw,
43462306a36Sopenharmony_ci						  unsigned long parent_rate)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
43762306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con3;
43862306a36Sopenharmony_ci	u64 fvco = parent_rate;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	pll_con3 = readl_relaxed(pll->con_reg);
44162306a36Sopenharmony_ci	mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK;
44262306a36Sopenharmony_ci	pdiv = (pll_con3 >> PLL0822X_PDIV_SHIFT) & PLL0822X_PDIV_MASK;
44362306a36Sopenharmony_ci	sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	fvco *= mdiv;
44662306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return (unsigned long)fvco;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate,
45262306a36Sopenharmony_ci				     unsigned long prate)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
45562306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
45662306a36Sopenharmony_ci	u32 pll_con3;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* Get required rate settings from table */
45962306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
46062306a36Sopenharmony_ci	if (!rate) {
46162306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
46262306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
46362306a36Sopenharmony_ci		return -EINVAL;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* Change PLL PMS values */
46762306a36Sopenharmony_ci	pll_con3 = readl_relaxed(pll->con_reg);
46862306a36Sopenharmony_ci	pll_con3 &= ~((PLL0822X_MDIV_MASK << PLL0822X_MDIV_SHIFT) |
46962306a36Sopenharmony_ci			(PLL0822X_PDIV_MASK << PLL0822X_PDIV_SHIFT) |
47062306a36Sopenharmony_ci			(PLL0822X_SDIV_MASK << PLL0822X_SDIV_SHIFT));
47162306a36Sopenharmony_ci	pll_con3 |= (rate->mdiv << PLL0822X_MDIV_SHIFT) |
47262306a36Sopenharmony_ci			(rate->pdiv << PLL0822X_PDIV_SHIFT) |
47362306a36Sopenharmony_ci			(rate->sdiv << PLL0822X_SDIV_SHIFT);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* Set PLL lock time */
47662306a36Sopenharmony_ci	writel_relaxed(rate->pdiv * PLL0822X_LOCK_FACTOR,
47762306a36Sopenharmony_ci			pll->lock_reg);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Write PMS values */
48062306a36Sopenharmony_ci	writel_relaxed(pll_con3, pll->con_reg);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* Wait for PLL lock if the PLL is enabled */
48362306a36Sopenharmony_ci	if (pll_con3 & BIT(pll->enable_offs))
48462306a36Sopenharmony_ci		return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return 0;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0822x_clk_ops = {
49062306a36Sopenharmony_ci	.recalc_rate = samsung_pll0822x_recalc_rate,
49162306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
49262306a36Sopenharmony_ci	.set_rate = samsung_pll0822x_set_rate,
49362306a36Sopenharmony_ci	.enable = samsung_pll3xxx_enable,
49462306a36Sopenharmony_ci	.disable = samsung_pll3xxx_disable,
49562306a36Sopenharmony_ci};
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0822x_clk_min_ops = {
49862306a36Sopenharmony_ci	.recalc_rate = samsung_pll0822x_recalc_rate,
49962306a36Sopenharmony_ci};
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/*
50262306a36Sopenharmony_ci * PLL0831x Clock Type
50362306a36Sopenharmony_ci */
50462306a36Sopenharmony_ci/* Maximum lock time can be 500 * PDIV cycles */
50562306a36Sopenharmony_ci#define PLL0831X_LOCK_FACTOR		(500)
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci#define PLL0831X_KDIV_MASK		(0xFFFF)
50862306a36Sopenharmony_ci#define PLL0831X_MDIV_MASK		(0x1FF)
50962306a36Sopenharmony_ci#define PLL0831X_PDIV_MASK		(0x3F)
51062306a36Sopenharmony_ci#define PLL0831X_SDIV_MASK		(0x7)
51162306a36Sopenharmony_ci#define PLL0831X_MDIV_SHIFT		(16)
51262306a36Sopenharmony_ci#define PLL0831X_PDIV_SHIFT		(8)
51362306a36Sopenharmony_ci#define PLL0831X_SDIV_SHIFT		(0)
51462306a36Sopenharmony_ci#define PLL0831X_KDIV_SHIFT		(0)
51562306a36Sopenharmony_ci#define PLL0831X_LOCK_STAT_SHIFT	(29)
51662306a36Sopenharmony_ci#define PLL0831X_ENABLE_SHIFT		(31)
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic unsigned long samsung_pll0831x_recalc_rate(struct clk_hw *hw,
51962306a36Sopenharmony_ci						  unsigned long parent_rate)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
52262306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con3, pll_con5;
52362306a36Sopenharmony_ci	s16 kdiv;
52462306a36Sopenharmony_ci	u64 fvco = parent_rate;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	pll_con3 = readl_relaxed(pll->con_reg);
52762306a36Sopenharmony_ci	pll_con5 = readl_relaxed(pll->con_reg + 8);
52862306a36Sopenharmony_ci	mdiv = (pll_con3 >> PLL0831X_MDIV_SHIFT) & PLL0831X_MDIV_MASK;
52962306a36Sopenharmony_ci	pdiv = (pll_con3 >> PLL0831X_PDIV_SHIFT) & PLL0831X_PDIV_MASK;
53062306a36Sopenharmony_ci	sdiv = (pll_con3 >> PLL0831X_SDIV_SHIFT) & PLL0831X_SDIV_MASK;
53162306a36Sopenharmony_ci	kdiv = (s16)((pll_con5 >> PLL0831X_KDIV_SHIFT) & PLL0831X_KDIV_MASK);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	fvco *= (mdiv << 16) + kdiv;
53462306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
53562306a36Sopenharmony_ci	fvco >>= 16;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return (unsigned long)fvco;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic int samsung_pll0831x_set_rate(struct clk_hw *hw, unsigned long drate,
54162306a36Sopenharmony_ci				     unsigned long parent_rate)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
54462306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
54562306a36Sopenharmony_ci	u32 pll_con3, pll_con5;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* Get required rate settings from table */
54862306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
54962306a36Sopenharmony_ci	if (!rate) {
55062306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
55162306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
55262306a36Sopenharmony_ci		return -EINVAL;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	pll_con3 = readl_relaxed(pll->con_reg);
55662306a36Sopenharmony_ci	pll_con5 = readl_relaxed(pll->con_reg + 8);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/* Change PLL PMSK values */
55962306a36Sopenharmony_ci	pll_con3 &= ~((PLL0831X_MDIV_MASK << PLL0831X_MDIV_SHIFT) |
56062306a36Sopenharmony_ci			(PLL0831X_PDIV_MASK << PLL0831X_PDIV_SHIFT) |
56162306a36Sopenharmony_ci			(PLL0831X_SDIV_MASK << PLL0831X_SDIV_SHIFT));
56262306a36Sopenharmony_ci	pll_con3 |= (rate->mdiv << PLL0831X_MDIV_SHIFT) |
56362306a36Sopenharmony_ci			(rate->pdiv << PLL0831X_PDIV_SHIFT) |
56462306a36Sopenharmony_ci			(rate->sdiv << PLL0831X_SDIV_SHIFT);
56562306a36Sopenharmony_ci	pll_con5 &= ~(PLL0831X_KDIV_MASK << PLL0831X_KDIV_SHIFT);
56662306a36Sopenharmony_ci	/*
56762306a36Sopenharmony_ci	 * kdiv is 16-bit 2's complement (s16), but stored as unsigned int.
56862306a36Sopenharmony_ci	 * Cast it to u16 to avoid leading 0xffff's in case of negative value.
56962306a36Sopenharmony_ci	 */
57062306a36Sopenharmony_ci	pll_con5 |= ((u16)rate->kdiv << PLL0831X_KDIV_SHIFT);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* Set PLL lock time */
57362306a36Sopenharmony_ci	writel_relaxed(rate->pdiv * PLL0831X_LOCK_FACTOR, pll->lock_reg);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* Write PMSK values */
57662306a36Sopenharmony_ci	writel_relaxed(pll_con3, pll->con_reg);
57762306a36Sopenharmony_ci	writel_relaxed(pll_con5, pll->con_reg + 8);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* Wait for PLL lock if the PLL is enabled */
58062306a36Sopenharmony_ci	if (pll_con3 & BIT(pll->enable_offs))
58162306a36Sopenharmony_ci		return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0831x_clk_ops = {
58762306a36Sopenharmony_ci	.recalc_rate = samsung_pll0831x_recalc_rate,
58862306a36Sopenharmony_ci	.set_rate = samsung_pll0831x_set_rate,
58962306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
59062306a36Sopenharmony_ci	.enable = samsung_pll3xxx_enable,
59162306a36Sopenharmony_ci	.disable = samsung_pll3xxx_disable,
59262306a36Sopenharmony_ci};
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0831x_clk_min_ops = {
59562306a36Sopenharmony_ci	.recalc_rate = samsung_pll0831x_recalc_rate,
59662306a36Sopenharmony_ci};
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci/*
59962306a36Sopenharmony_ci * PLL45xx Clock Type
60062306a36Sopenharmony_ci */
60162306a36Sopenharmony_ci#define PLL4502_LOCK_FACTOR	400
60262306a36Sopenharmony_ci#define PLL4508_LOCK_FACTOR	240
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci#define PLL45XX_MDIV_MASK	(0x3FF)
60562306a36Sopenharmony_ci#define PLL45XX_PDIV_MASK	(0x3F)
60662306a36Sopenharmony_ci#define PLL45XX_SDIV_MASK	(0x7)
60762306a36Sopenharmony_ci#define PLL45XX_AFC_MASK	(0x1F)
60862306a36Sopenharmony_ci#define PLL45XX_MDIV_SHIFT	(16)
60962306a36Sopenharmony_ci#define PLL45XX_PDIV_SHIFT	(8)
61062306a36Sopenharmony_ci#define PLL45XX_SDIV_SHIFT	(0)
61162306a36Sopenharmony_ci#define PLL45XX_AFC_SHIFT	(0)
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci#define PLL45XX_ENABLE		BIT(31)
61462306a36Sopenharmony_ci#define PLL45XX_LOCKED		BIT(29)
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
61762306a36Sopenharmony_ci				unsigned long parent_rate)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
62062306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con;
62162306a36Sopenharmony_ci	u64 fvco = parent_rate;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	pll_con = readl_relaxed(pll->con_reg);
62462306a36Sopenharmony_ci	mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
62562306a36Sopenharmony_ci	pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
62662306a36Sopenharmony_ci	sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (pll->type == pll_4508)
62962306a36Sopenharmony_ci		sdiv = sdiv - 1;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	fvco *= mdiv;
63262306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	return (unsigned long)fvco;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1,
63862306a36Sopenharmony_ci				const struct samsung_pll_rate_table *rate)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	u32 old_mdiv, old_pdiv, old_afc;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	old_mdiv = (pll_con0 >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
64362306a36Sopenharmony_ci	old_pdiv = (pll_con0 >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
64462306a36Sopenharmony_ci	old_afc = (pll_con1 >> PLL45XX_AFC_SHIFT) & PLL45XX_AFC_MASK;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
64762306a36Sopenharmony_ci		|| old_afc != rate->afc);
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
65162306a36Sopenharmony_ci					unsigned long prate)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
65462306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
65562306a36Sopenharmony_ci	u32 con0, con1;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* Get required rate settings from table */
65862306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
65962306a36Sopenharmony_ci	if (!rate) {
66062306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
66162306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
66262306a36Sopenharmony_ci		return -EINVAL;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	con0 = readl_relaxed(pll->con_reg);
66662306a36Sopenharmony_ci	con1 = readl_relaxed(pll->con_reg + 0x4);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	if (!(samsung_pll45xx_mp_change(con0, con1, rate))) {
66962306a36Sopenharmony_ci		/* If only s change, change just s value only*/
67062306a36Sopenharmony_ci		con0 &= ~(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT);
67162306a36Sopenharmony_ci		con0 |= rate->sdiv << PLL45XX_SDIV_SHIFT;
67262306a36Sopenharmony_ci		writel_relaxed(con0, pll->con_reg);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		return 0;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	/* Set PLL PMS values. */
67862306a36Sopenharmony_ci	con0 &= ~((PLL45XX_MDIV_MASK << PLL45XX_MDIV_SHIFT) |
67962306a36Sopenharmony_ci			(PLL45XX_PDIV_MASK << PLL45XX_PDIV_SHIFT) |
68062306a36Sopenharmony_ci			(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT));
68162306a36Sopenharmony_ci	con0 |= (rate->mdiv << PLL45XX_MDIV_SHIFT) |
68262306a36Sopenharmony_ci			(rate->pdiv << PLL45XX_PDIV_SHIFT) |
68362306a36Sopenharmony_ci			(rate->sdiv << PLL45XX_SDIV_SHIFT);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/* Set PLL AFC value. */
68662306a36Sopenharmony_ci	con1 = readl_relaxed(pll->con_reg + 0x4);
68762306a36Sopenharmony_ci	con1 &= ~(PLL45XX_AFC_MASK << PLL45XX_AFC_SHIFT);
68862306a36Sopenharmony_ci	con1 |= (rate->afc << PLL45XX_AFC_SHIFT);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/* Set PLL lock time. */
69162306a36Sopenharmony_ci	switch (pll->type) {
69262306a36Sopenharmony_ci	case pll_4502:
69362306a36Sopenharmony_ci		writel_relaxed(rate->pdiv * PLL4502_LOCK_FACTOR, pll->lock_reg);
69462306a36Sopenharmony_ci		break;
69562306a36Sopenharmony_ci	case pll_4508:
69662306a36Sopenharmony_ci		writel_relaxed(rate->pdiv * PLL4508_LOCK_FACTOR, pll->lock_reg);
69762306a36Sopenharmony_ci		break;
69862306a36Sopenharmony_ci	default:
69962306a36Sopenharmony_ci		break;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* Set new configuration. */
70362306a36Sopenharmony_ci	writel_relaxed(con1, pll->con_reg + 0x4);
70462306a36Sopenharmony_ci	writel_relaxed(con0, pll->con_reg);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Wait for PLL lock */
70762306a36Sopenharmony_ci	return samsung_pll_lock_wait(pll, PLL45XX_LOCKED);
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic const struct clk_ops samsung_pll45xx_clk_ops = {
71162306a36Sopenharmony_ci	.recalc_rate = samsung_pll45xx_recalc_rate,
71262306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
71362306a36Sopenharmony_ci	.set_rate = samsung_pll45xx_set_rate,
71462306a36Sopenharmony_ci};
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll45xx_clk_min_ops = {
71762306a36Sopenharmony_ci	.recalc_rate = samsung_pll45xx_recalc_rate,
71862306a36Sopenharmony_ci};
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci/*
72162306a36Sopenharmony_ci * PLL46xx Clock Type
72262306a36Sopenharmony_ci */
72362306a36Sopenharmony_ci#define PLL46XX_LOCK_FACTOR	3000
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci#define PLL46XX_VSEL_MASK	(1)
72662306a36Sopenharmony_ci#define PLL46XX_MDIV_MASK	(0x1FF)
72762306a36Sopenharmony_ci#define PLL1460X_MDIV_MASK	(0x3FF)
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci#define PLL46XX_PDIV_MASK	(0x3F)
73062306a36Sopenharmony_ci#define PLL46XX_SDIV_MASK	(0x7)
73162306a36Sopenharmony_ci#define PLL46XX_VSEL_SHIFT	(27)
73262306a36Sopenharmony_ci#define PLL46XX_MDIV_SHIFT	(16)
73362306a36Sopenharmony_ci#define PLL46XX_PDIV_SHIFT	(8)
73462306a36Sopenharmony_ci#define PLL46XX_SDIV_SHIFT	(0)
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci#define PLL46XX_KDIV_MASK	(0xFFFF)
73762306a36Sopenharmony_ci#define PLL4650C_KDIV_MASK	(0xFFF)
73862306a36Sopenharmony_ci#define PLL46XX_KDIV_SHIFT	(0)
73962306a36Sopenharmony_ci#define PLL46XX_MFR_MASK	(0x3F)
74062306a36Sopenharmony_ci#define PLL46XX_MRR_MASK	(0x1F)
74162306a36Sopenharmony_ci#define PLL46XX_KDIV_SHIFT	(0)
74262306a36Sopenharmony_ci#define PLL46XX_MFR_SHIFT	(16)
74362306a36Sopenharmony_ci#define PLL46XX_MRR_SHIFT	(24)
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci#define PLL46XX_ENABLE		BIT(31)
74662306a36Sopenharmony_ci#define PLL46XX_LOCKED		BIT(29)
74762306a36Sopenharmony_ci#define PLL46XX_VSEL		BIT(27)
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistatic unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
75062306a36Sopenharmony_ci				unsigned long parent_rate)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
75362306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
75462306a36Sopenharmony_ci	u64 fvco = parent_rate;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	pll_con0 = readl_relaxed(pll->con_reg);
75762306a36Sopenharmony_ci	pll_con1 = readl_relaxed(pll->con_reg + 4);
75862306a36Sopenharmony_ci	mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & ((pll->type == pll_1460x) ?
75962306a36Sopenharmony_ci				PLL1460X_MDIV_MASK : PLL46XX_MDIV_MASK);
76062306a36Sopenharmony_ci	pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
76162306a36Sopenharmony_ci	sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
76262306a36Sopenharmony_ci	kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
76362306a36Sopenharmony_ci					pll_con1 & PLL46XX_KDIV_MASK;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	shift = ((pll->type == pll_4600) || (pll->type == pll_1460x)) ? 16 : 10;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	fvco *= (mdiv << shift) + kdiv;
76862306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
76962306a36Sopenharmony_ci	fvco >>= shift;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	return (unsigned long)fvco;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1,
77562306a36Sopenharmony_ci				const struct samsung_pll_rate_table *rate)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	u32 old_mdiv, old_pdiv, old_kdiv;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
78062306a36Sopenharmony_ci	old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
78162306a36Sopenharmony_ci	old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
78462306a36Sopenharmony_ci		|| old_kdiv != rate->kdiv);
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
78862306a36Sopenharmony_ci					unsigned long prate)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
79162306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
79262306a36Sopenharmony_ci	u32 con0, con1, lock;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/* Get required rate settings from table */
79562306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
79662306a36Sopenharmony_ci	if (!rate) {
79762306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
79862306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
79962306a36Sopenharmony_ci		return -EINVAL;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	con0 = readl_relaxed(pll->con_reg);
80362306a36Sopenharmony_ci	con1 = readl_relaxed(pll->con_reg + 0x4);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) {
80662306a36Sopenharmony_ci		/* If only s change, change just s value only*/
80762306a36Sopenharmony_ci		con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
80862306a36Sopenharmony_ci		con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT;
80962306a36Sopenharmony_ci		writel_relaxed(con0, pll->con_reg);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci		return 0;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* Set PLL lock time. */
81562306a36Sopenharmony_ci	lock = rate->pdiv * PLL46XX_LOCK_FACTOR;
81662306a36Sopenharmony_ci	if (lock > 0xffff)
81762306a36Sopenharmony_ci		/* Maximum lock time bitfield is 16-bit. */
81862306a36Sopenharmony_ci		lock = 0xffff;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Set PLL PMS and VSEL values. */
82162306a36Sopenharmony_ci	if (pll->type == pll_1460x) {
82262306a36Sopenharmony_ci		con0 &= ~((PLL1460X_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
82362306a36Sopenharmony_ci			(PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
82462306a36Sopenharmony_ci			(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT));
82562306a36Sopenharmony_ci	} else {
82662306a36Sopenharmony_ci		con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
82762306a36Sopenharmony_ci			(PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
82862306a36Sopenharmony_ci			(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) |
82962306a36Sopenharmony_ci			(PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT));
83062306a36Sopenharmony_ci		con0 |=	rate->vsel << PLL46XX_VSEL_SHIFT;
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) |
83462306a36Sopenharmony_ci			(rate->pdiv << PLL46XX_PDIV_SHIFT) |
83562306a36Sopenharmony_ci			(rate->sdiv << PLL46XX_SDIV_SHIFT);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	/* Set PLL K, MFR and MRR values. */
83862306a36Sopenharmony_ci	con1 = readl_relaxed(pll->con_reg + 0x4);
83962306a36Sopenharmony_ci	con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) |
84062306a36Sopenharmony_ci			(PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) |
84162306a36Sopenharmony_ci			(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT));
84262306a36Sopenharmony_ci	con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) |
84362306a36Sopenharmony_ci			(rate->mfr << PLL46XX_MFR_SHIFT) |
84462306a36Sopenharmony_ci			(rate->mrr << PLL46XX_MRR_SHIFT);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	/* Write configuration to PLL */
84762306a36Sopenharmony_ci	writel_relaxed(lock, pll->lock_reg);
84862306a36Sopenharmony_ci	writel_relaxed(con0, pll->con_reg);
84962306a36Sopenharmony_ci	writel_relaxed(con1, pll->con_reg + 0x4);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* Wait for PLL lock */
85262306a36Sopenharmony_ci	return samsung_pll_lock_wait(pll, PLL46XX_LOCKED);
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic const struct clk_ops samsung_pll46xx_clk_ops = {
85662306a36Sopenharmony_ci	.recalc_rate = samsung_pll46xx_recalc_rate,
85762306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
85862306a36Sopenharmony_ci	.set_rate = samsung_pll46xx_set_rate,
85962306a36Sopenharmony_ci};
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_cistatic const struct clk_ops samsung_pll46xx_clk_min_ops = {
86262306a36Sopenharmony_ci	.recalc_rate = samsung_pll46xx_recalc_rate,
86362306a36Sopenharmony_ci};
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci/*
86662306a36Sopenharmony_ci * PLL6552 Clock Type
86762306a36Sopenharmony_ci */
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci#define PLL6552_MDIV_MASK	0x3ff
87062306a36Sopenharmony_ci#define PLL6552_PDIV_MASK	0x3f
87162306a36Sopenharmony_ci#define PLL6552_SDIV_MASK	0x7
87262306a36Sopenharmony_ci#define PLL6552_MDIV_SHIFT	16
87362306a36Sopenharmony_ci#define PLL6552_MDIV_SHIFT_2416	14
87462306a36Sopenharmony_ci#define PLL6552_PDIV_SHIFT	8
87562306a36Sopenharmony_ci#define PLL6552_PDIV_SHIFT_2416	5
87662306a36Sopenharmony_ci#define PLL6552_SDIV_SHIFT	0
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
87962306a36Sopenharmony_ci						unsigned long parent_rate)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
88262306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con;
88362306a36Sopenharmony_ci	u64 fvco = parent_rate;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	pll_con = readl_relaxed(pll->con_reg);
88662306a36Sopenharmony_ci	if (pll->type == pll_6552_s3c2416) {
88762306a36Sopenharmony_ci		mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
88862306a36Sopenharmony_ci		pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
88962306a36Sopenharmony_ci	} else {
89062306a36Sopenharmony_ci		mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
89162306a36Sopenharmony_ci		pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci	sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	fvco *= mdiv;
89662306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	return (unsigned long)fvco;
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistatic const struct clk_ops samsung_pll6552_clk_ops = {
90262306a36Sopenharmony_ci	.recalc_rate = samsung_pll6552_recalc_rate,
90362306a36Sopenharmony_ci};
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci/*
90662306a36Sopenharmony_ci * PLL6553 Clock Type
90762306a36Sopenharmony_ci */
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci#define PLL6553_MDIV_MASK	0xff
91062306a36Sopenharmony_ci#define PLL6553_PDIV_MASK	0x3f
91162306a36Sopenharmony_ci#define PLL6553_SDIV_MASK	0x7
91262306a36Sopenharmony_ci#define PLL6553_KDIV_MASK	0xffff
91362306a36Sopenharmony_ci#define PLL6553_MDIV_SHIFT	16
91462306a36Sopenharmony_ci#define PLL6553_PDIV_SHIFT	8
91562306a36Sopenharmony_ci#define PLL6553_SDIV_SHIFT	0
91662306a36Sopenharmony_ci#define PLL6553_KDIV_SHIFT	0
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
91962306a36Sopenharmony_ci						unsigned long parent_rate)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
92262306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
92362306a36Sopenharmony_ci	u64 fvco = parent_rate;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	pll_con0 = readl_relaxed(pll->con_reg);
92662306a36Sopenharmony_ci	pll_con1 = readl_relaxed(pll->con_reg + 0x4);
92762306a36Sopenharmony_ci	mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
92862306a36Sopenharmony_ci	pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
92962306a36Sopenharmony_ci	sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
93062306a36Sopenharmony_ci	kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	fvco *= (mdiv << 16) + kdiv;
93362306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
93462306a36Sopenharmony_ci	fvco >>= 16;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	return (unsigned long)fvco;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic const struct clk_ops samsung_pll6553_clk_ops = {
94062306a36Sopenharmony_ci	.recalc_rate = samsung_pll6553_recalc_rate,
94162306a36Sopenharmony_ci};
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci/*
94462306a36Sopenharmony_ci * PLL2550x Clock Type
94562306a36Sopenharmony_ci */
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci#define PLL2550X_R_MASK       (0x1)
94862306a36Sopenharmony_ci#define PLL2550X_P_MASK       (0x3F)
94962306a36Sopenharmony_ci#define PLL2550X_M_MASK       (0x3FF)
95062306a36Sopenharmony_ci#define PLL2550X_S_MASK       (0x7)
95162306a36Sopenharmony_ci#define PLL2550X_R_SHIFT      (20)
95262306a36Sopenharmony_ci#define PLL2550X_P_SHIFT      (14)
95362306a36Sopenharmony_ci#define PLL2550X_M_SHIFT      (4)
95462306a36Sopenharmony_ci#define PLL2550X_S_SHIFT      (0)
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
95762306a36Sopenharmony_ci				unsigned long parent_rate)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
96062306a36Sopenharmony_ci	u32 r, p, m, s, pll_stat;
96162306a36Sopenharmony_ci	u64 fvco = parent_rate;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	pll_stat = readl_relaxed(pll->con_reg);
96462306a36Sopenharmony_ci	r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
96562306a36Sopenharmony_ci	if (!r)
96662306a36Sopenharmony_ci		return 0;
96762306a36Sopenharmony_ci	p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
96862306a36Sopenharmony_ci	m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
96962306a36Sopenharmony_ci	s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	fvco *= m;
97262306a36Sopenharmony_ci	do_div(fvco, (p << s));
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	return (unsigned long)fvco;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2550x_clk_ops = {
97862306a36Sopenharmony_ci	.recalc_rate = samsung_pll2550x_recalc_rate,
97962306a36Sopenharmony_ci};
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci/*
98262306a36Sopenharmony_ci * PLL2550xx Clock Type
98362306a36Sopenharmony_ci */
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci/* Maximum lock time can be 270 * PDIV cycles */
98662306a36Sopenharmony_ci#define PLL2550XX_LOCK_FACTOR 270
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci#define PLL2550XX_M_MASK		0x3FF
98962306a36Sopenharmony_ci#define PLL2550XX_P_MASK		0x3F
99062306a36Sopenharmony_ci#define PLL2550XX_S_MASK		0x7
99162306a36Sopenharmony_ci#define PLL2550XX_LOCK_STAT_MASK	0x1
99262306a36Sopenharmony_ci#define PLL2550XX_M_SHIFT		9
99362306a36Sopenharmony_ci#define PLL2550XX_P_SHIFT		3
99462306a36Sopenharmony_ci#define PLL2550XX_S_SHIFT		0
99562306a36Sopenharmony_ci#define PLL2550XX_LOCK_STAT_SHIFT	21
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
99862306a36Sopenharmony_ci				unsigned long parent_rate)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
100162306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con;
100262306a36Sopenharmony_ci	u64 fvco = parent_rate;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	pll_con = readl_relaxed(pll->con_reg);
100562306a36Sopenharmony_ci	mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
100662306a36Sopenharmony_ci	pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
100762306a36Sopenharmony_ci	sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	fvco *= mdiv;
101062306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	return (unsigned long)fvco;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	u32 old_mdiv, old_pdiv;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
102062306a36Sopenharmony_ci	old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	return mdiv != old_mdiv || pdiv != old_pdiv;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
102662306a36Sopenharmony_ci					unsigned long prate)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
102962306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
103062306a36Sopenharmony_ci	u32 tmp;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	/* Get required rate settings from table */
103362306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
103462306a36Sopenharmony_ci	if (!rate) {
103562306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
103662306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
103762306a36Sopenharmony_ci		return -EINVAL;
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	tmp = readl_relaxed(pll->con_reg);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
104362306a36Sopenharmony_ci		/* If only s change, change just s value only*/
104462306a36Sopenharmony_ci		tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
104562306a36Sopenharmony_ci		tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
104662306a36Sopenharmony_ci		writel_relaxed(tmp, pll->con_reg);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		return 0;
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* Set PLL lock time. */
105262306a36Sopenharmony_ci	writel_relaxed(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/* Change PLL PMS values */
105562306a36Sopenharmony_ci	tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
105662306a36Sopenharmony_ci			(PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
105762306a36Sopenharmony_ci			(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
105862306a36Sopenharmony_ci	tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
105962306a36Sopenharmony_ci			(rate->pdiv << PLL2550XX_P_SHIFT) |
106062306a36Sopenharmony_ci			(rate->sdiv << PLL2550XX_S_SHIFT);
106162306a36Sopenharmony_ci	writel_relaxed(tmp, pll->con_reg);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	/* Wait for PLL lock */
106462306a36Sopenharmony_ci	return samsung_pll_lock_wait(pll,
106562306a36Sopenharmony_ci			PLL2550XX_LOCK_STAT_MASK << PLL2550XX_LOCK_STAT_SHIFT);
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2550xx_clk_ops = {
106962306a36Sopenharmony_ci	.recalc_rate = samsung_pll2550xx_recalc_rate,
107062306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
107162306a36Sopenharmony_ci	.set_rate = samsung_pll2550xx_set_rate,
107262306a36Sopenharmony_ci};
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2550xx_clk_min_ops = {
107562306a36Sopenharmony_ci	.recalc_rate = samsung_pll2550xx_recalc_rate,
107662306a36Sopenharmony_ci};
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci/*
107962306a36Sopenharmony_ci * PLL2650x Clock Type
108062306a36Sopenharmony_ci */
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci/* Maximum lock time can be 3000 * PDIV cycles */
108362306a36Sopenharmony_ci#define PLL2650X_LOCK_FACTOR		3000
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci#define PLL2650X_M_MASK			0x1ff
108662306a36Sopenharmony_ci#define PLL2650X_P_MASK			0x3f
108762306a36Sopenharmony_ci#define PLL2650X_S_MASK			0x7
108862306a36Sopenharmony_ci#define PLL2650X_K_MASK			0xffff
108962306a36Sopenharmony_ci#define PLL2650X_LOCK_STAT_MASK		0x1
109062306a36Sopenharmony_ci#define PLL2650X_M_SHIFT		16
109162306a36Sopenharmony_ci#define PLL2650X_P_SHIFT		8
109262306a36Sopenharmony_ci#define PLL2650X_S_SHIFT		0
109362306a36Sopenharmony_ci#define PLL2650X_K_SHIFT		0
109462306a36Sopenharmony_ci#define PLL2650X_LOCK_STAT_SHIFT	29
109562306a36Sopenharmony_ci#define PLL2650X_PLL_ENABLE_SHIFT	31
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_cistatic unsigned long samsung_pll2650x_recalc_rate(struct clk_hw *hw,
109862306a36Sopenharmony_ci				unsigned long parent_rate)
109962306a36Sopenharmony_ci{
110062306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
110162306a36Sopenharmony_ci	u64 fout = parent_rate;
110262306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
110362306a36Sopenharmony_ci	s16 kdiv;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	pll_con0 = readl_relaxed(pll->con_reg);
110662306a36Sopenharmony_ci	mdiv = (pll_con0 >> PLL2650X_M_SHIFT) & PLL2650X_M_MASK;
110762306a36Sopenharmony_ci	pdiv = (pll_con0 >> PLL2650X_P_SHIFT) & PLL2650X_P_MASK;
110862306a36Sopenharmony_ci	sdiv = (pll_con0 >> PLL2650X_S_SHIFT) & PLL2650X_S_MASK;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	pll_con1 = readl_relaxed(pll->con_reg + 4);
111162306a36Sopenharmony_ci	kdiv = (s16)((pll_con1 >> PLL2650X_K_SHIFT) & PLL2650X_K_MASK);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	fout *= (mdiv << 16) + kdiv;
111462306a36Sopenharmony_ci	do_div(fout, (pdiv << sdiv));
111562306a36Sopenharmony_ci	fout >>= 16;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	return (unsigned long)fout;
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistatic int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate,
112162306a36Sopenharmony_ci					unsigned long prate)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
112462306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
112562306a36Sopenharmony_ci	u32 con0, con1;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	/* Get required rate settings from table */
112862306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
112962306a36Sopenharmony_ci	if (!rate) {
113062306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
113162306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
113262306a36Sopenharmony_ci		return -EINVAL;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	con0 = readl_relaxed(pll->con_reg);
113662306a36Sopenharmony_ci	con1 = readl_relaxed(pll->con_reg + 4);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/* Set PLL lock time. */
113962306a36Sopenharmony_ci	writel_relaxed(rate->pdiv * PLL2650X_LOCK_FACTOR, pll->lock_reg);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* Change PLL PMS values */
114262306a36Sopenharmony_ci	con0 &= ~((PLL2650X_M_MASK << PLL2650X_M_SHIFT) |
114362306a36Sopenharmony_ci			(PLL2650X_P_MASK << PLL2650X_P_SHIFT) |
114462306a36Sopenharmony_ci			(PLL2650X_S_MASK << PLL2650X_S_SHIFT));
114562306a36Sopenharmony_ci	con0 |= (rate->mdiv << PLL2650X_M_SHIFT) |
114662306a36Sopenharmony_ci			(rate->pdiv << PLL2650X_P_SHIFT) |
114762306a36Sopenharmony_ci			(rate->sdiv << PLL2650X_S_SHIFT);
114862306a36Sopenharmony_ci	con0 |= (1 << PLL2650X_PLL_ENABLE_SHIFT);
114962306a36Sopenharmony_ci	writel_relaxed(con0, pll->con_reg);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	con1 &= ~(PLL2650X_K_MASK << PLL2650X_K_SHIFT);
115262306a36Sopenharmony_ci	con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
115362306a36Sopenharmony_ci	writel_relaxed(con1, pll->con_reg + 4);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	/* Wait for PLL lock */
115662306a36Sopenharmony_ci	return samsung_pll_lock_wait(pll,
115762306a36Sopenharmony_ci			PLL2650X_LOCK_STAT_MASK << PLL2650X_LOCK_STAT_SHIFT);
115862306a36Sopenharmony_ci}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650x_clk_ops = {
116162306a36Sopenharmony_ci	.recalc_rate = samsung_pll2650x_recalc_rate,
116262306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
116362306a36Sopenharmony_ci	.set_rate = samsung_pll2650x_set_rate,
116462306a36Sopenharmony_ci};
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650x_clk_min_ops = {
116762306a36Sopenharmony_ci	.recalc_rate = samsung_pll2650x_recalc_rate,
116862306a36Sopenharmony_ci};
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci/*
117162306a36Sopenharmony_ci * PLL2650XX Clock Type
117262306a36Sopenharmony_ci */
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci/* Maximum lock time can be 3000 * PDIV cycles */
117562306a36Sopenharmony_ci#define PLL2650XX_LOCK_FACTOR 3000
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci#define PLL2650XX_MDIV_SHIFT		9
117862306a36Sopenharmony_ci#define PLL2650XX_PDIV_SHIFT		3
117962306a36Sopenharmony_ci#define PLL2650XX_SDIV_SHIFT		0
118062306a36Sopenharmony_ci#define PLL2650XX_KDIV_SHIFT		0
118162306a36Sopenharmony_ci#define PLL2650XX_MDIV_MASK		0x1ff
118262306a36Sopenharmony_ci#define PLL2650XX_PDIV_MASK		0x3f
118362306a36Sopenharmony_ci#define PLL2650XX_SDIV_MASK		0x7
118462306a36Sopenharmony_ci#define PLL2650XX_KDIV_MASK		0xffff
118562306a36Sopenharmony_ci#define PLL2650XX_PLL_ENABLE_SHIFT	23
118662306a36Sopenharmony_ci#define PLL2650XX_PLL_LOCKTIME_SHIFT	21
118762306a36Sopenharmony_ci#define PLL2650XX_PLL_FOUTMASK_SHIFT	31
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_cistatic unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
119062306a36Sopenharmony_ci				unsigned long parent_rate)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
119362306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
119462306a36Sopenharmony_ci	s16 kdiv;
119562306a36Sopenharmony_ci	u64 fvco = parent_rate;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	pll_con0 = readl_relaxed(pll->con_reg);
119862306a36Sopenharmony_ci	pll_con2 = readl_relaxed(pll->con_reg + 8);
119962306a36Sopenharmony_ci	mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
120062306a36Sopenharmony_ci	pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
120162306a36Sopenharmony_ci	sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
120262306a36Sopenharmony_ci	kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	fvco *= (mdiv << 16) + kdiv;
120562306a36Sopenharmony_ci	do_div(fvco, (pdiv << sdiv));
120662306a36Sopenharmony_ci	fvco >>= 16;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	return (unsigned long)fvco;
120962306a36Sopenharmony_ci}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cistatic int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
121262306a36Sopenharmony_ci					unsigned long parent_rate)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	struct samsung_clk_pll *pll = to_clk_pll(hw);
121562306a36Sopenharmony_ci	u32 pll_con0, pll_con2;
121662306a36Sopenharmony_ci	const struct samsung_pll_rate_table *rate;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	rate = samsung_get_pll_settings(pll, drate);
121962306a36Sopenharmony_ci	if (!rate) {
122062306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
122162306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
122262306a36Sopenharmony_ci		return -EINVAL;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	pll_con0 = readl_relaxed(pll->con_reg);
122662306a36Sopenharmony_ci	pll_con2 = readl_relaxed(pll->con_reg + 8);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	 /* Change PLL PMS values */
122962306a36Sopenharmony_ci	pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
123062306a36Sopenharmony_ci			PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
123162306a36Sopenharmony_ci			PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
123262306a36Sopenharmony_ci	pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
123362306a36Sopenharmony_ci	pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
123462306a36Sopenharmony_ci	pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
123562306a36Sopenharmony_ci	pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
123662306a36Sopenharmony_ci	pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
123962306a36Sopenharmony_ci	pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
124062306a36Sopenharmony_ci			<< PLL2650XX_KDIV_SHIFT;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	/* Set PLL lock time. */
124362306a36Sopenharmony_ci	writel_relaxed(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	writel_relaxed(pll_con0, pll->con_reg);
124662306a36Sopenharmony_ci	writel_relaxed(pll_con2, pll->con_reg + 8);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	return samsung_pll_lock_wait(pll, 0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650xx_clk_ops = {
125262306a36Sopenharmony_ci	.recalc_rate = samsung_pll2650xx_recalc_rate,
125362306a36Sopenharmony_ci	.set_rate = samsung_pll2650xx_set_rate,
125462306a36Sopenharmony_ci	.round_rate = samsung_pll_round_rate,
125562306a36Sopenharmony_ci};
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650xx_clk_min_ops = {
125862306a36Sopenharmony_ci	.recalc_rate = samsung_pll2650xx_recalc_rate,
125962306a36Sopenharmony_ci};
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
126262306a36Sopenharmony_ci				const struct samsung_pll_clock *pll_clk)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	struct samsung_clk_pll *pll;
126562306a36Sopenharmony_ci	struct clk_init_data init;
126662306a36Sopenharmony_ci	int ret, len;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
126962306a36Sopenharmony_ci	if (!pll) {
127062306a36Sopenharmony_ci		pr_err("%s: could not allocate pll clk %s\n",
127162306a36Sopenharmony_ci			__func__, pll_clk->name);
127262306a36Sopenharmony_ci		return;
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	init.name = pll_clk->name;
127662306a36Sopenharmony_ci	init.flags = pll_clk->flags;
127762306a36Sopenharmony_ci	init.parent_names = &pll_clk->parent_name;
127862306a36Sopenharmony_ci	init.num_parents = 1;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	if (pll_clk->rate_table) {
128162306a36Sopenharmony_ci		/* find count of rates in rate_table */
128262306a36Sopenharmony_ci		for (len = 0; pll_clk->rate_table[len].rate != 0; )
128362306a36Sopenharmony_ci			len++;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		pll->rate_count = len;
128662306a36Sopenharmony_ci		pll->rate_table = kmemdup(pll_clk->rate_table,
128762306a36Sopenharmony_ci					pll->rate_count *
128862306a36Sopenharmony_ci					sizeof(struct samsung_pll_rate_table),
128962306a36Sopenharmony_ci					GFP_KERNEL);
129062306a36Sopenharmony_ci		WARN(!pll->rate_table,
129162306a36Sopenharmony_ci			"%s: could not allocate rate table for %s\n",
129262306a36Sopenharmony_ci			__func__, pll_clk->name);
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	switch (pll_clk->type) {
129662306a36Sopenharmony_ci	case pll_2126:
129762306a36Sopenharmony_ci		init.ops = &samsung_pll2126_clk_ops;
129862306a36Sopenharmony_ci		break;
129962306a36Sopenharmony_ci	case pll_3000:
130062306a36Sopenharmony_ci		init.ops = &samsung_pll3000_clk_ops;
130162306a36Sopenharmony_ci		break;
130262306a36Sopenharmony_ci	/* clk_ops for 35xx and 2550 are similar */
130362306a36Sopenharmony_ci	case pll_35xx:
130462306a36Sopenharmony_ci	case pll_2550:
130562306a36Sopenharmony_ci	case pll_1450x:
130662306a36Sopenharmony_ci	case pll_1451x:
130762306a36Sopenharmony_ci	case pll_1452x:
130862306a36Sopenharmony_ci	case pll_142xx:
130962306a36Sopenharmony_ci		pll->enable_offs = PLL35XX_ENABLE_SHIFT;
131062306a36Sopenharmony_ci		pll->lock_offs = PLL35XX_LOCK_STAT_SHIFT;
131162306a36Sopenharmony_ci		if (!pll->rate_table)
131262306a36Sopenharmony_ci			init.ops = &samsung_pll35xx_clk_min_ops;
131362306a36Sopenharmony_ci		else
131462306a36Sopenharmony_ci			init.ops = &samsung_pll35xx_clk_ops;
131562306a36Sopenharmony_ci		break;
131662306a36Sopenharmony_ci	case pll_1417x:
131762306a36Sopenharmony_ci	case pll_0818x:
131862306a36Sopenharmony_ci	case pll_0822x:
131962306a36Sopenharmony_ci		pll->enable_offs = PLL0822X_ENABLE_SHIFT;
132062306a36Sopenharmony_ci		pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT;
132162306a36Sopenharmony_ci		if (!pll->rate_table)
132262306a36Sopenharmony_ci			init.ops = &samsung_pll0822x_clk_min_ops;
132362306a36Sopenharmony_ci		else
132462306a36Sopenharmony_ci			init.ops = &samsung_pll0822x_clk_ops;
132562306a36Sopenharmony_ci		break;
132662306a36Sopenharmony_ci	case pll_4500:
132762306a36Sopenharmony_ci		init.ops = &samsung_pll45xx_clk_min_ops;
132862306a36Sopenharmony_ci		break;
132962306a36Sopenharmony_ci	case pll_4502:
133062306a36Sopenharmony_ci	case pll_4508:
133162306a36Sopenharmony_ci		if (!pll->rate_table)
133262306a36Sopenharmony_ci			init.ops = &samsung_pll45xx_clk_min_ops;
133362306a36Sopenharmony_ci		else
133462306a36Sopenharmony_ci			init.ops = &samsung_pll45xx_clk_ops;
133562306a36Sopenharmony_ci		break;
133662306a36Sopenharmony_ci	/* clk_ops for 36xx and 2650 are similar */
133762306a36Sopenharmony_ci	case pll_36xx:
133862306a36Sopenharmony_ci	case pll_2650:
133962306a36Sopenharmony_ci		pll->enable_offs = PLL36XX_ENABLE_SHIFT;
134062306a36Sopenharmony_ci		pll->lock_offs = PLL36XX_LOCK_STAT_SHIFT;
134162306a36Sopenharmony_ci		if (!pll->rate_table)
134262306a36Sopenharmony_ci			init.ops = &samsung_pll36xx_clk_min_ops;
134362306a36Sopenharmony_ci		else
134462306a36Sopenharmony_ci			init.ops = &samsung_pll36xx_clk_ops;
134562306a36Sopenharmony_ci		break;
134662306a36Sopenharmony_ci	case pll_0831x:
134762306a36Sopenharmony_ci		pll->enable_offs = PLL0831X_ENABLE_SHIFT;
134862306a36Sopenharmony_ci		pll->lock_offs = PLL0831X_LOCK_STAT_SHIFT;
134962306a36Sopenharmony_ci		if (!pll->rate_table)
135062306a36Sopenharmony_ci			init.ops = &samsung_pll0831x_clk_min_ops;
135162306a36Sopenharmony_ci		else
135262306a36Sopenharmony_ci			init.ops = &samsung_pll0831x_clk_ops;
135362306a36Sopenharmony_ci		break;
135462306a36Sopenharmony_ci	case pll_6552:
135562306a36Sopenharmony_ci	case pll_6552_s3c2416:
135662306a36Sopenharmony_ci		init.ops = &samsung_pll6552_clk_ops;
135762306a36Sopenharmony_ci		break;
135862306a36Sopenharmony_ci	case pll_6553:
135962306a36Sopenharmony_ci		init.ops = &samsung_pll6553_clk_ops;
136062306a36Sopenharmony_ci		break;
136162306a36Sopenharmony_ci	case pll_4600:
136262306a36Sopenharmony_ci	case pll_4650:
136362306a36Sopenharmony_ci	case pll_4650c:
136462306a36Sopenharmony_ci	case pll_1460x:
136562306a36Sopenharmony_ci		if (!pll->rate_table)
136662306a36Sopenharmony_ci			init.ops = &samsung_pll46xx_clk_min_ops;
136762306a36Sopenharmony_ci		else
136862306a36Sopenharmony_ci			init.ops = &samsung_pll46xx_clk_ops;
136962306a36Sopenharmony_ci		break;
137062306a36Sopenharmony_ci	case pll_2550x:
137162306a36Sopenharmony_ci		init.ops = &samsung_pll2550x_clk_ops;
137262306a36Sopenharmony_ci		break;
137362306a36Sopenharmony_ci	case pll_2550xx:
137462306a36Sopenharmony_ci		if (!pll->rate_table)
137562306a36Sopenharmony_ci			init.ops = &samsung_pll2550xx_clk_min_ops;
137662306a36Sopenharmony_ci		else
137762306a36Sopenharmony_ci			init.ops = &samsung_pll2550xx_clk_ops;
137862306a36Sopenharmony_ci		break;
137962306a36Sopenharmony_ci	case pll_2650x:
138062306a36Sopenharmony_ci		if (!pll->rate_table)
138162306a36Sopenharmony_ci			init.ops = &samsung_pll2650x_clk_min_ops;
138262306a36Sopenharmony_ci		else
138362306a36Sopenharmony_ci			init.ops = &samsung_pll2650x_clk_ops;
138462306a36Sopenharmony_ci		break;
138562306a36Sopenharmony_ci	case pll_2650xx:
138662306a36Sopenharmony_ci		if (!pll->rate_table)
138762306a36Sopenharmony_ci			init.ops = &samsung_pll2650xx_clk_min_ops;
138862306a36Sopenharmony_ci		else
138962306a36Sopenharmony_ci			init.ops = &samsung_pll2650xx_clk_ops;
139062306a36Sopenharmony_ci		break;
139162306a36Sopenharmony_ci	default:
139262306a36Sopenharmony_ci		pr_warn("%s: Unknown pll type for pll clk %s\n",
139362306a36Sopenharmony_ci			__func__, pll_clk->name);
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	pll->hw.init = &init;
139762306a36Sopenharmony_ci	pll->type = pll_clk->type;
139862306a36Sopenharmony_ci	pll->lock_reg = ctx->reg_base + pll_clk->lock_offset;
139962306a36Sopenharmony_ci	pll->con_reg = ctx->reg_base + pll_clk->con_offset;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	ret = clk_hw_register(ctx->dev, &pll->hw);
140262306a36Sopenharmony_ci	if (ret) {
140362306a36Sopenharmony_ci		pr_err("%s: failed to register pll clock %s : %d\n",
140462306a36Sopenharmony_ci			__func__, pll_clk->name, ret);
140562306a36Sopenharmony_ci		kfree(pll->rate_table);
140662306a36Sopenharmony_ci		kfree(pll);
140762306a36Sopenharmony_ci		return;
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	samsung_clk_add_lookup(ctx, &pll->hw, pll_clk->id);
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_civoid __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
141462306a36Sopenharmony_ci			const struct samsung_pll_clock *pll_list,
141562306a36Sopenharmony_ci			unsigned int nr_pll)
141662306a36Sopenharmony_ci{
141762306a36Sopenharmony_ci	int cnt;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	for (cnt = 0; cnt < nr_pll; cnt++)
142062306a36Sopenharmony_ci		_samsung_clk_register_pll(ctx, &pll_list[cnt]);
142162306a36Sopenharmony_ci}
1422