18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2014 STMicroelectronics (R&D) Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/*
78c2ecf20Sopenharmony_ci * Authors:
88c2ecf20Sopenharmony_ci * Stephen Gallimore <stephen.gallimore@st.com>,
98c2ecf20Sopenharmony_ci * Pankaj Dev <pankaj.dev@st.com>.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/of_address.h>
148c2ecf20Sopenharmony_ci#include <linux/clk.h>
158c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
168c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "clkgen.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(clkgena_c32_odf_lock);
218c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(clkgen_a9_lock);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * PLL configuration register bits for PLL3200 C32
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci#define C32_NDIV_MASK (0xff)
278c2ecf20Sopenharmony_ci#define C32_IDF_MASK (0x7)
288c2ecf20Sopenharmony_ci#define C32_ODF_MASK (0x3f)
298c2ecf20Sopenharmony_ci#define C32_LDF_MASK (0x7f)
308c2ecf20Sopenharmony_ci#define C32_CP_MASK (0x1f)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define C32_MAX_ODFS (4)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/*
358c2ecf20Sopenharmony_ci * PLL configuration register bits for PLL4600 C28
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci#define C28_NDIV_MASK (0xff)
388c2ecf20Sopenharmony_ci#define C28_IDF_MASK (0x7)
398c2ecf20Sopenharmony_ci#define C28_ODF_MASK (0x3f)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistruct clkgen_pll_data {
428c2ecf20Sopenharmony_ci	struct clkgen_field pdn_status;
438c2ecf20Sopenharmony_ci	struct clkgen_field pdn_ctrl;
448c2ecf20Sopenharmony_ci	struct clkgen_field locked_status;
458c2ecf20Sopenharmony_ci	struct clkgen_field mdiv;
468c2ecf20Sopenharmony_ci	struct clkgen_field ndiv;
478c2ecf20Sopenharmony_ci	struct clkgen_field pdiv;
488c2ecf20Sopenharmony_ci	struct clkgen_field idf;
498c2ecf20Sopenharmony_ci	struct clkgen_field ldf;
508c2ecf20Sopenharmony_ci	struct clkgen_field cp;
518c2ecf20Sopenharmony_ci	unsigned int num_odfs;
528c2ecf20Sopenharmony_ci	struct clkgen_field odf[C32_MAX_ODFS];
538c2ecf20Sopenharmony_ci	struct clkgen_field odf_gate[C32_MAX_ODFS];
548c2ecf20Sopenharmony_ci	bool switch2pll_en;
558c2ecf20Sopenharmony_ci	struct clkgen_field switch2pll;
568c2ecf20Sopenharmony_ci	spinlock_t *lock;
578c2ecf20Sopenharmony_ci	const struct clk_ops *ops;
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic const struct clk_ops stm_pll3200c32_ops;
618c2ecf20Sopenharmony_cistatic const struct clk_ops stm_pll3200c32_a9_ops;
628c2ecf20Sopenharmony_cistatic const struct clk_ops stm_pll4600c28_ops;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic const struct clkgen_pll_data st_pll3200c32_cx_0 = {
658c2ecf20Sopenharmony_ci	/* 407 C0 PLL0 */
668c2ecf20Sopenharmony_ci	.pdn_status	= CLKGEN_FIELD(0x2a0,	0x1,			8),
678c2ecf20Sopenharmony_ci	.pdn_ctrl	= CLKGEN_FIELD(0x2a0,	0x1,			8),
688c2ecf20Sopenharmony_ci	.locked_status	= CLKGEN_FIELD(0x2a0,	0x1,			24),
698c2ecf20Sopenharmony_ci	.ndiv		= CLKGEN_FIELD(0x2a4,	C32_NDIV_MASK,		16),
708c2ecf20Sopenharmony_ci	.idf		= CLKGEN_FIELD(0x2a4,	C32_IDF_MASK,		0x0),
718c2ecf20Sopenharmony_ci	.num_odfs = 1,
728c2ecf20Sopenharmony_ci	.odf		= { CLKGEN_FIELD(0x2b4, C32_ODF_MASK,		0) },
738c2ecf20Sopenharmony_ci	.odf_gate	= { CLKGEN_FIELD(0x2b4, 0x1,			6) },
748c2ecf20Sopenharmony_ci	.ops		= &stm_pll3200c32_ops,
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic const struct clkgen_pll_data st_pll3200c32_cx_1 = {
788c2ecf20Sopenharmony_ci	/* 407 C0 PLL1 */
798c2ecf20Sopenharmony_ci	.pdn_status	= CLKGEN_FIELD(0x2c8,	0x1,			8),
808c2ecf20Sopenharmony_ci	.pdn_ctrl	= CLKGEN_FIELD(0x2c8,	0x1,			8),
818c2ecf20Sopenharmony_ci	.locked_status	= CLKGEN_FIELD(0x2c8,	0x1,			24),
828c2ecf20Sopenharmony_ci	.ndiv		= CLKGEN_FIELD(0x2cc,	C32_NDIV_MASK,		16),
838c2ecf20Sopenharmony_ci	.idf		= CLKGEN_FIELD(0x2cc,	C32_IDF_MASK,		0x0),
848c2ecf20Sopenharmony_ci	.num_odfs = 1,
858c2ecf20Sopenharmony_ci	.odf		= { CLKGEN_FIELD(0x2dc, C32_ODF_MASK,		0) },
868c2ecf20Sopenharmony_ci	.odf_gate	= { CLKGEN_FIELD(0x2dc, 0x1,			6) },
878c2ecf20Sopenharmony_ci	.ops		= &stm_pll3200c32_ops,
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic const struct clkgen_pll_data st_pll3200c32_407_a9 = {
918c2ecf20Sopenharmony_ci	/* 407 A9 */
928c2ecf20Sopenharmony_ci	.pdn_status	= CLKGEN_FIELD(0x1a8,	0x1,			0),
938c2ecf20Sopenharmony_ci	.pdn_ctrl	= CLKGEN_FIELD(0x1a8,	0x1,			0),
948c2ecf20Sopenharmony_ci	.locked_status	= CLKGEN_FIELD(0x87c,	0x1,			0),
958c2ecf20Sopenharmony_ci	.ndiv		= CLKGEN_FIELD(0x1b0,	C32_NDIV_MASK,		0),
968c2ecf20Sopenharmony_ci	.idf		= CLKGEN_FIELD(0x1a8,	C32_IDF_MASK,		25),
978c2ecf20Sopenharmony_ci	.num_odfs = 1,
988c2ecf20Sopenharmony_ci	.odf		= { CLKGEN_FIELD(0x1b0, C32_ODF_MASK,		8) },
998c2ecf20Sopenharmony_ci	.odf_gate	= { CLKGEN_FIELD(0x1ac, 0x1,			28) },
1008c2ecf20Sopenharmony_ci	.switch2pll_en	= true,
1018c2ecf20Sopenharmony_ci	.cp		= CLKGEN_FIELD(0x1a8,	C32_CP_MASK,		1),
1028c2ecf20Sopenharmony_ci	.switch2pll	= CLKGEN_FIELD(0x1a4,	0x1,			1),
1038c2ecf20Sopenharmony_ci	.lock = &clkgen_a9_lock,
1048c2ecf20Sopenharmony_ci	.ops		= &stm_pll3200c32_a9_ops,
1058c2ecf20Sopenharmony_ci};
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic struct clkgen_pll_data st_pll4600c28_418_a9 = {
1088c2ecf20Sopenharmony_ci	/* 418 A9 */
1098c2ecf20Sopenharmony_ci	.pdn_status	= CLKGEN_FIELD(0x1a8,	0x1,			0),
1108c2ecf20Sopenharmony_ci	.pdn_ctrl	= CLKGEN_FIELD(0x1a8,	0x1,			0),
1118c2ecf20Sopenharmony_ci	.locked_status	= CLKGEN_FIELD(0x87c,	0x1,			0),
1128c2ecf20Sopenharmony_ci	.ndiv		= CLKGEN_FIELD(0x1b0,	C28_NDIV_MASK,		0),
1138c2ecf20Sopenharmony_ci	.idf		= CLKGEN_FIELD(0x1a8,	C28_IDF_MASK,		25),
1148c2ecf20Sopenharmony_ci	.num_odfs = 1,
1158c2ecf20Sopenharmony_ci	.odf		= { CLKGEN_FIELD(0x1b0, C28_ODF_MASK,		8) },
1168c2ecf20Sopenharmony_ci	.odf_gate	= { CLKGEN_FIELD(0x1ac, 0x1,			28) },
1178c2ecf20Sopenharmony_ci	.switch2pll_en	= true,
1188c2ecf20Sopenharmony_ci	.switch2pll	= CLKGEN_FIELD(0x1a4,	0x1,			1),
1198c2ecf20Sopenharmony_ci	.lock		= &clkgen_a9_lock,
1208c2ecf20Sopenharmony_ci	.ops		= &stm_pll4600c28_ops,
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/**
1248c2ecf20Sopenharmony_ci * DOC: Clock Generated by PLL, rate set and enabled by bootloader
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci * Traits of this clock:
1278c2ecf20Sopenharmony_ci * prepare - clk_(un)prepare only ensures parent is (un)prepared
1288c2ecf20Sopenharmony_ci * enable - clk_enable/disable only ensures parent is enabled
1298c2ecf20Sopenharmony_ci * rate - rate is fixed. No clk_set_rate support
1308c2ecf20Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/**
1348c2ecf20Sopenharmony_ci * PLL clock that is integrated in the ClockGenA instances on the STiH415
1358c2ecf20Sopenharmony_ci * and STiH416.
1368c2ecf20Sopenharmony_ci *
1378c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces.
1388c2ecf20Sopenharmony_ci * @type: PLL instance type.
1398c2ecf20Sopenharmony_ci * @regs_base: base of the PLL configuration register(s).
1408c2ecf20Sopenharmony_ci *
1418c2ecf20Sopenharmony_ci */
1428c2ecf20Sopenharmony_cistruct clkgen_pll {
1438c2ecf20Sopenharmony_ci	struct clk_hw		hw;
1448c2ecf20Sopenharmony_ci	struct clkgen_pll_data	*data;
1458c2ecf20Sopenharmony_ci	void __iomem		*regs_base;
1468c2ecf20Sopenharmony_ci	spinlock_t	*lock;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	u32 ndiv;
1498c2ecf20Sopenharmony_ci	u32 idf;
1508c2ecf20Sopenharmony_ci	u32 odf;
1518c2ecf20Sopenharmony_ci	u32 cp;
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci#define to_clkgen_pll(_hw) container_of(_hw, struct clkgen_pll, hw)
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistruct stm_pll {
1578c2ecf20Sopenharmony_ci	unsigned long mdiv;
1588c2ecf20Sopenharmony_ci	unsigned long ndiv;
1598c2ecf20Sopenharmony_ci	unsigned long pdiv;
1608c2ecf20Sopenharmony_ci	unsigned long odf;
1618c2ecf20Sopenharmony_ci	unsigned long idf;
1628c2ecf20Sopenharmony_ci	unsigned long ldf;
1638c2ecf20Sopenharmony_ci	unsigned long cp;
1648c2ecf20Sopenharmony_ci};
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int clkgen_pll_is_locked(struct clk_hw *hw)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
1698c2ecf20Sopenharmony_ci	u32 locked = CLKGEN_READ(pll, locked_status);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return !!locked;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int clkgen_pll_is_enabled(struct clk_hw *hw)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
1778c2ecf20Sopenharmony_ci	u32 poweroff = CLKGEN_READ(pll, pdn_status);
1788c2ecf20Sopenharmony_ci	return !poweroff;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int __clkgen_pll_enable(struct clk_hw *hw)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
1848c2ecf20Sopenharmony_ci	void __iomem *base =  pll->regs_base;
1858c2ecf20Sopenharmony_ci	struct clkgen_field *field = &pll->data->locked_status;
1868c2ecf20Sopenharmony_ci	int ret = 0;
1878c2ecf20Sopenharmony_ci	u32 reg;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (clkgen_pll_is_enabled(hw))
1908c2ecf20Sopenharmony_ci		return 0;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, pdn_ctrl, 0);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	ret = readl_relaxed_poll_timeout(base + field->offset, reg,
1958c2ecf20Sopenharmony_ci			!!((reg >> field->shift) & field->mask),  0, 10000);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (!ret) {
1988c2ecf20Sopenharmony_ci		if (pll->data->switch2pll_en)
1998c2ecf20Sopenharmony_ci			CLKGEN_WRITE(pll, switch2pll, 0);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		pr_debug("%s:%s enabled\n", __clk_get_name(hw->clk), __func__);
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return ret;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic int clkgen_pll_enable(struct clk_hw *hw)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
2108c2ecf20Sopenharmony_ci	unsigned long flags = 0;
2118c2ecf20Sopenharmony_ci	int ret = 0;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (pll->lock)
2148c2ecf20Sopenharmony_ci		spin_lock_irqsave(pll->lock, flags);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	ret = __clkgen_pll_enable(hw);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (pll->lock)
2198c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pll->lock, flags);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return ret;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic void __clkgen_pll_disable(struct clk_hw *hw)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (!clkgen_pll_is_enabled(hw))
2298c2ecf20Sopenharmony_ci		return;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (pll->data->switch2pll_en)
2328c2ecf20Sopenharmony_ci		CLKGEN_WRITE(pll, switch2pll, 1);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, pdn_ctrl, 1);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	pr_debug("%s:%s disabled\n", __clk_get_name(hw->clk), __func__);
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic void clkgen_pll_disable(struct clk_hw *hw)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
2428c2ecf20Sopenharmony_ci	unsigned long flags = 0;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (pll->lock)
2458c2ecf20Sopenharmony_ci		spin_lock_irqsave(pll->lock, flags);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	__clkgen_pll_disable(hw);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (pll->lock)
2508c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pll->lock, flags);
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int clk_pll3200c32_get_params(unsigned long input, unsigned long output,
2548c2ecf20Sopenharmony_ci			  struct stm_pll *pll)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	unsigned long i, n;
2578c2ecf20Sopenharmony_ci	unsigned long deviation = ~0;
2588c2ecf20Sopenharmony_ci	unsigned long new_freq;
2598c2ecf20Sopenharmony_ci	long new_deviation;
2608c2ecf20Sopenharmony_ci	/* Charge pump table: highest ndiv value for cp=6 to 25 */
2618c2ecf20Sopenharmony_ci	static const unsigned char cp_table[] = {
2628c2ecf20Sopenharmony_ci		48, 56, 64, 72, 80, 88, 96, 104, 112, 120,
2638c2ecf20Sopenharmony_ci		128, 136, 144, 152, 160, 168, 176, 184, 192
2648c2ecf20Sopenharmony_ci	};
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/* Output clock range: 800Mhz to 1600Mhz */
2678c2ecf20Sopenharmony_ci	if (output < 800000000 || output > 1600000000)
2688c2ecf20Sopenharmony_ci		return -EINVAL;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	input /= 1000;
2718c2ecf20Sopenharmony_ci	output /= 1000;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	for (i = 1; i <= 7 && deviation; i++) {
2748c2ecf20Sopenharmony_ci		n = i * output / (2 * input);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		/* Checks */
2778c2ecf20Sopenharmony_ci		if (n < 8)
2788c2ecf20Sopenharmony_ci			continue;
2798c2ecf20Sopenharmony_ci		if (n > 200)
2808c2ecf20Sopenharmony_ci			break;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		new_freq = (input * 2 * n) / i;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		new_deviation = abs(new_freq - output);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		if (!new_deviation || new_deviation < deviation) {
2878c2ecf20Sopenharmony_ci			pll->idf  = i;
2888c2ecf20Sopenharmony_ci			pll->ndiv = n;
2898c2ecf20Sopenharmony_ci			deviation = new_deviation;
2908c2ecf20Sopenharmony_ci		}
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (deviation == ~0) /* No solution found */
2948c2ecf20Sopenharmony_ci		return -EINVAL;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Computing recommended charge pump value */
2978c2ecf20Sopenharmony_ci	for (pll->cp = 6; pll->ndiv > cp_table[pll->cp-6]; (pll->cp)++)
2988c2ecf20Sopenharmony_ci		;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return 0;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int clk_pll3200c32_get_rate(unsigned long input, struct stm_pll *pll,
3048c2ecf20Sopenharmony_ci			unsigned long *rate)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	if (!pll->idf)
3078c2ecf20Sopenharmony_ci		pll->idf = 1;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	*rate = ((2 * (input / 1000) * pll->ndiv) / pll->idf) * 1000;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return 0;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic unsigned long recalc_stm_pll3200c32(struct clk_hw *hw,
3158c2ecf20Sopenharmony_ci		unsigned long parent_rate)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
3188c2ecf20Sopenharmony_ci	unsigned long ndiv, idf;
3198c2ecf20Sopenharmony_ci	unsigned long rate = 0;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
3228c2ecf20Sopenharmony_ci		return 0;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	ndiv = CLKGEN_READ(pll, ndiv);
3258c2ecf20Sopenharmony_ci	idf = CLKGEN_READ(pll, idf);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (idf)
3288c2ecf20Sopenharmony_ci		/* Note: input is divided to avoid overflow */
3298c2ecf20Sopenharmony_ci		rate = ((2 * (parent_rate/1000) * ndiv) / idf) * 1000;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	return rate;
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic long round_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate,
3378c2ecf20Sopenharmony_ci		unsigned long *prate)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct stm_pll params;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (!clk_pll3200c32_get_params(*prate, rate, &params))
3428c2ecf20Sopenharmony_ci		clk_pll3200c32_get_rate(*prate, &params, &rate);
3438c2ecf20Sopenharmony_ci	else {
3448c2ecf20Sopenharmony_ci		pr_debug("%s: %s rate %ld Invalid\n", __func__,
3458c2ecf20Sopenharmony_ci			 __clk_get_name(hw->clk), rate);
3468c2ecf20Sopenharmony_ci		return 0;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",
3508c2ecf20Sopenharmony_ci		 __func__, __clk_get_name(hw->clk),
3518c2ecf20Sopenharmony_ci		 rate, (unsigned int)params.ndiv,
3528c2ecf20Sopenharmony_ci		 (unsigned int)params.idf);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return rate;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate,
3588c2ecf20Sopenharmony_ci				unsigned long parent_rate)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
3618c2ecf20Sopenharmony_ci	struct stm_pll params;
3628c2ecf20Sopenharmony_ci	long hwrate = 0;
3638c2ecf20Sopenharmony_ci	unsigned long flags = 0;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (!rate || !parent_rate)
3668c2ecf20Sopenharmony_ci		return -EINVAL;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	if (!clk_pll3200c32_get_params(parent_rate, rate, &params))
3698c2ecf20Sopenharmony_ci		clk_pll3200c32_get_rate(parent_rate, &params, &hwrate);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",
3728c2ecf20Sopenharmony_ci		 __func__, __clk_get_name(hw->clk),
3738c2ecf20Sopenharmony_ci		 hwrate, (unsigned int)params.ndiv,
3748c2ecf20Sopenharmony_ci		 (unsigned int)params.idf);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (!hwrate)
3778c2ecf20Sopenharmony_ci		return -EINVAL;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	pll->ndiv = params.ndiv;
3808c2ecf20Sopenharmony_ci	pll->idf = params.idf;
3818c2ecf20Sopenharmony_ci	pll->cp = params.cp;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	__clkgen_pll_disable(hw);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (pll->lock)
3868c2ecf20Sopenharmony_ci		spin_lock_irqsave(pll->lock, flags);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
3898c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, idf, pll->idf);
3908c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, cp, pll->cp);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (pll->lock)
3938c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pll->lock, flags);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	__clkgen_pll_enable(hw);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	return 0;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/* PLL output structure
4018c2ecf20Sopenharmony_ci * FVCO >> /2 >> FVCOBY2 (no output)
4028c2ecf20Sopenharmony_ci *                 |> Divider (ODF) >> PHI
4038c2ecf20Sopenharmony_ci *
4048c2ecf20Sopenharmony_ci * FVCOby2 output = (input * 2 * NDIV) / IDF (assuming FRAC_CONTROL==L)
4058c2ecf20Sopenharmony_ci *
4068c2ecf20Sopenharmony_ci * Rules:
4078c2ecf20Sopenharmony_ci *   4Mhz <= INFF input <= 350Mhz
4088c2ecf20Sopenharmony_ci *   4Mhz <= INFIN (INFF / IDF) <= 50Mhz
4098c2ecf20Sopenharmony_ci *   19.05Mhz <= FVCOby2 output (PHI w ODF=1) <= 3000Mhz
4108c2ecf20Sopenharmony_ci *   1 <= i (register/dec value for IDF) <= 7
4118c2ecf20Sopenharmony_ci *   8 <= n (register/dec value for NDIV) <= 246
4128c2ecf20Sopenharmony_ci */
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic int clk_pll4600c28_get_params(unsigned long input, unsigned long output,
4158c2ecf20Sopenharmony_ci			  struct stm_pll *pll)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	unsigned long i, infin, n;
4198c2ecf20Sopenharmony_ci	unsigned long deviation = ~0;
4208c2ecf20Sopenharmony_ci	unsigned long new_freq, new_deviation;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	/* Output clock range: 19Mhz to 3000Mhz */
4238c2ecf20Sopenharmony_ci	if (output < 19000000 || output > 3000000000u)
4248c2ecf20Sopenharmony_ci		return -EINVAL;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* For better jitter, IDF should be smallest and NDIV must be maximum */
4278c2ecf20Sopenharmony_ci	for (i = 1; i <= 7 && deviation; i++) {
4288c2ecf20Sopenharmony_ci		/* INFIN checks */
4298c2ecf20Sopenharmony_ci		infin = input / i;
4308c2ecf20Sopenharmony_ci		if (infin < 4000000 || infin > 50000000)
4318c2ecf20Sopenharmony_ci			continue;	/* Invalid case */
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		n = output / (infin * 2);
4348c2ecf20Sopenharmony_ci		if (n < 8 || n > 246)
4358c2ecf20Sopenharmony_ci			continue;	/* Invalid case */
4368c2ecf20Sopenharmony_ci		if (n < 246)
4378c2ecf20Sopenharmony_ci			n++;	/* To work around 'y' when n=x.y */
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci		for (; n >= 8 && deviation; n--) {
4408c2ecf20Sopenharmony_ci			new_freq = infin * 2 * n;
4418c2ecf20Sopenharmony_ci			if (new_freq < output)
4428c2ecf20Sopenharmony_ci				break;	/* Optimization: shorting loop */
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci			new_deviation = new_freq - output;
4458c2ecf20Sopenharmony_ci			if (!new_deviation || new_deviation < deviation) {
4468c2ecf20Sopenharmony_ci				pll->idf  = i;
4478c2ecf20Sopenharmony_ci				pll->ndiv = n;
4488c2ecf20Sopenharmony_ci				deviation = new_deviation;
4498c2ecf20Sopenharmony_ci			}
4508c2ecf20Sopenharmony_ci		}
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (deviation == ~0) /* No solution found */
4548c2ecf20Sopenharmony_ci		return -EINVAL;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	return 0;
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic int clk_pll4600c28_get_rate(unsigned long input, struct stm_pll *pll,
4608c2ecf20Sopenharmony_ci			unsigned long *rate)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	if (!pll->idf)
4638c2ecf20Sopenharmony_ci		pll->idf = 1;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	*rate = (input / pll->idf) * 2 * pll->ndiv;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return 0;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic unsigned long recalc_stm_pll4600c28(struct clk_hw *hw,
4718c2ecf20Sopenharmony_ci				    unsigned long parent_rate)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
4748c2ecf20Sopenharmony_ci	struct stm_pll params;
4758c2ecf20Sopenharmony_ci	unsigned long rate;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw))
4788c2ecf20Sopenharmony_ci		return 0;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	params.ndiv = CLKGEN_READ(pll, ndiv);
4818c2ecf20Sopenharmony_ci	params.idf = CLKGEN_READ(pll, idf);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	clk_pll4600c28_get_rate(parent_rate, &params, &rate);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return rate;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic long round_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate,
4918c2ecf20Sopenharmony_ci				      unsigned long *prate)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	struct stm_pll params;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (!clk_pll4600c28_get_params(*prate, rate, &params)) {
4968c2ecf20Sopenharmony_ci		clk_pll4600c28_get_rate(*prate, &params, &rate);
4978c2ecf20Sopenharmony_ci	} else {
4988c2ecf20Sopenharmony_ci		pr_debug("%s: %s rate %ld Invalid\n", __func__,
4998c2ecf20Sopenharmony_ci			 __clk_get_name(hw->clk), rate);
5008c2ecf20Sopenharmony_ci		return 0;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",
5048c2ecf20Sopenharmony_ci		 __func__, __clk_get_name(hw->clk),
5058c2ecf20Sopenharmony_ci		 rate, (unsigned int)params.ndiv,
5068c2ecf20Sopenharmony_ci		 (unsigned int)params.idf);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	return rate;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic int set_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate,
5128c2ecf20Sopenharmony_ci				   unsigned long parent_rate)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	struct clkgen_pll *pll = to_clkgen_pll(hw);
5158c2ecf20Sopenharmony_ci	struct stm_pll params;
5168c2ecf20Sopenharmony_ci	long hwrate;
5178c2ecf20Sopenharmony_ci	unsigned long flags = 0;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (!rate || !parent_rate)
5208c2ecf20Sopenharmony_ci		return -EINVAL;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (!clk_pll4600c28_get_params(parent_rate, rate, &params)) {
5238c2ecf20Sopenharmony_ci		clk_pll4600c28_get_rate(parent_rate, &params, &hwrate);
5248c2ecf20Sopenharmony_ci	} else {
5258c2ecf20Sopenharmony_ci		pr_debug("%s: %s rate %ld Invalid\n", __func__,
5268c2ecf20Sopenharmony_ci			 __clk_get_name(hw->clk), rate);
5278c2ecf20Sopenharmony_ci		return -EINVAL;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",
5318c2ecf20Sopenharmony_ci		 __func__, __clk_get_name(hw->clk),
5328c2ecf20Sopenharmony_ci		 hwrate, (unsigned int)params.ndiv,
5338c2ecf20Sopenharmony_ci		 (unsigned int)params.idf);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (!hwrate)
5368c2ecf20Sopenharmony_ci		return -EINVAL;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	pll->ndiv = params.ndiv;
5398c2ecf20Sopenharmony_ci	pll->idf = params.idf;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	__clkgen_pll_disable(hw);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (pll->lock)
5448c2ecf20Sopenharmony_ci		spin_lock_irqsave(pll->lock, flags);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
5478c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, idf, pll->idf);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (pll->lock)
5508c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pll->lock, flags);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	__clkgen_pll_enable(hw);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return 0;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic const struct clk_ops stm_pll3200c32_ops = {
5588c2ecf20Sopenharmony_ci	.enable		= clkgen_pll_enable,
5598c2ecf20Sopenharmony_ci	.disable	= clkgen_pll_disable,
5608c2ecf20Sopenharmony_ci	.is_enabled	= clkgen_pll_is_enabled,
5618c2ecf20Sopenharmony_ci	.recalc_rate	= recalc_stm_pll3200c32,
5628c2ecf20Sopenharmony_ci};
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic const struct clk_ops stm_pll3200c32_a9_ops = {
5658c2ecf20Sopenharmony_ci	.enable		= clkgen_pll_enable,
5668c2ecf20Sopenharmony_ci	.disable	= clkgen_pll_disable,
5678c2ecf20Sopenharmony_ci	.is_enabled	= clkgen_pll_is_enabled,
5688c2ecf20Sopenharmony_ci	.recalc_rate	= recalc_stm_pll3200c32,
5698c2ecf20Sopenharmony_ci	.round_rate	= round_rate_stm_pll3200c32,
5708c2ecf20Sopenharmony_ci	.set_rate	= set_rate_stm_pll3200c32,
5718c2ecf20Sopenharmony_ci};
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic const struct clk_ops stm_pll4600c28_ops = {
5748c2ecf20Sopenharmony_ci	.enable		= clkgen_pll_enable,
5758c2ecf20Sopenharmony_ci	.disable	= clkgen_pll_disable,
5768c2ecf20Sopenharmony_ci	.is_enabled	= clkgen_pll_is_enabled,
5778c2ecf20Sopenharmony_ci	.recalc_rate	= recalc_stm_pll4600c28,
5788c2ecf20Sopenharmony_ci	.round_rate	= round_rate_stm_pll4600c28,
5798c2ecf20Sopenharmony_ci	.set_rate	= set_rate_stm_pll4600c28,
5808c2ecf20Sopenharmony_ci};
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic struct clk * __init clkgen_pll_register(const char *parent_name,
5838c2ecf20Sopenharmony_ci				struct clkgen_pll_data	*pll_data,
5848c2ecf20Sopenharmony_ci				void __iomem *reg, unsigned long pll_flags,
5858c2ecf20Sopenharmony_ci				const char *clk_name, spinlock_t *lock)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct clkgen_pll *pll;
5888c2ecf20Sopenharmony_ci	struct clk *clk;
5898c2ecf20Sopenharmony_ci	struct clk_init_data init;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
5928c2ecf20Sopenharmony_ci	if (!pll)
5938c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	init.name = clk_name;
5968c2ecf20Sopenharmony_ci	init.ops = pll_data->ops;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	init.flags = pll_flags | CLK_GET_RATE_NOCACHE;
5998c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
6008c2ecf20Sopenharmony_ci	init.num_parents  = 1;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	pll->data = pll_data;
6038c2ecf20Sopenharmony_ci	pll->regs_base = reg;
6048c2ecf20Sopenharmony_ci	pll->hw.init = &init;
6058c2ecf20Sopenharmony_ci	pll->lock = lock;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	clk = clk_register(NULL, &pll->hw);
6088c2ecf20Sopenharmony_ci	if (IS_ERR(clk)) {
6098c2ecf20Sopenharmony_ci		kfree(pll);
6108c2ecf20Sopenharmony_ci		return clk;
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	pr_debug("%s: parent %s rate %lu\n",
6148c2ecf20Sopenharmony_ci			__clk_get_name(clk),
6158c2ecf20Sopenharmony_ci			__clk_get_name(clk_get_parent(clk)),
6168c2ecf20Sopenharmony_ci			clk_get_rate(clk));
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	return clk;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic void __iomem * __init clkgen_get_register_base(
6228c2ecf20Sopenharmony_ci				struct device_node *np)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	struct device_node *pnode;
6258c2ecf20Sopenharmony_ci	void __iomem *reg = NULL;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	pnode = of_get_parent(np);
6288c2ecf20Sopenharmony_ci	if (!pnode)
6298c2ecf20Sopenharmony_ci		return NULL;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	reg = of_iomap(pnode, 0);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	of_node_put(pnode);
6348c2ecf20Sopenharmony_ci	return reg;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic struct clk * __init clkgen_odf_register(const char *parent_name,
6388c2ecf20Sopenharmony_ci					       void __iomem *reg,
6398c2ecf20Sopenharmony_ci					       struct clkgen_pll_data *pll_data,
6408c2ecf20Sopenharmony_ci					       unsigned long pll_flags, int odf,
6418c2ecf20Sopenharmony_ci					       spinlock_t *odf_lock,
6428c2ecf20Sopenharmony_ci					       const char *odf_name)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct clk *clk;
6458c2ecf20Sopenharmony_ci	unsigned long flags;
6468c2ecf20Sopenharmony_ci	struct clk_gate *gate;
6478c2ecf20Sopenharmony_ci	struct clk_divider *div;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	flags = pll_flags | CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
6528c2ecf20Sopenharmony_ci	if (!gate)
6538c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	gate->flags = CLK_GATE_SET_TO_DISABLE;
6568c2ecf20Sopenharmony_ci	gate->reg = reg + pll_data->odf_gate[odf].offset;
6578c2ecf20Sopenharmony_ci	gate->bit_idx = pll_data->odf_gate[odf].shift;
6588c2ecf20Sopenharmony_ci	gate->lock = odf_lock;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	div = kzalloc(sizeof(*div), GFP_KERNEL);
6618c2ecf20Sopenharmony_ci	if (!div) {
6628c2ecf20Sopenharmony_ci		kfree(gate);
6638c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
6678c2ecf20Sopenharmony_ci	div->reg = reg + pll_data->odf[odf].offset;
6688c2ecf20Sopenharmony_ci	div->shift = pll_data->odf[odf].shift;
6698c2ecf20Sopenharmony_ci	div->width = fls(pll_data->odf[odf].mask);
6708c2ecf20Sopenharmony_ci	div->lock = odf_lock;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	clk = clk_register_composite(NULL, odf_name, &parent_name, 1,
6738c2ecf20Sopenharmony_ci				     NULL, NULL,
6748c2ecf20Sopenharmony_ci				     &div->hw, &clk_divider_ops,
6758c2ecf20Sopenharmony_ci				     &gate->hw, &clk_gate_ops,
6768c2ecf20Sopenharmony_ci				     flags);
6778c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
6788c2ecf20Sopenharmony_ci		return clk;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	pr_debug("%s: parent %s rate %lu\n",
6818c2ecf20Sopenharmony_ci			__clk_get_name(clk),
6828c2ecf20Sopenharmony_ci			__clk_get_name(clk_get_parent(clk)),
6838c2ecf20Sopenharmony_ci			clk_get_rate(clk));
6848c2ecf20Sopenharmony_ci	return clk;
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cistatic void __init clkgen_c32_pll_setup(struct device_node *np,
6898c2ecf20Sopenharmony_ci		struct clkgen_pll_data *data)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	struct clk *clk;
6928c2ecf20Sopenharmony_ci	const char *parent_name, *pll_name;
6938c2ecf20Sopenharmony_ci	void __iomem *pll_base;
6948c2ecf20Sopenharmony_ci	int num_odfs, odf;
6958c2ecf20Sopenharmony_ci	struct clk_onecell_data *clk_data;
6968c2ecf20Sopenharmony_ci	unsigned long pll_flags = 0;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	parent_name = of_clk_get_parent_name(np, 0);
7008c2ecf20Sopenharmony_ci	if (!parent_name)
7018c2ecf20Sopenharmony_ci		return;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	pll_base = clkgen_get_register_base(np);
7048c2ecf20Sopenharmony_ci	if (!pll_base)
7058c2ecf20Sopenharmony_ci		return;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	of_clk_detect_critical(np, 0, &pll_flags);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	clk = clkgen_pll_register(parent_name, data, pll_base, pll_flags,
7108c2ecf20Sopenharmony_ci				  np->name, data->lock);
7118c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
7128c2ecf20Sopenharmony_ci		return;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	pll_name = __clk_get_name(clk);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	num_odfs = data->num_odfs;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
7198c2ecf20Sopenharmony_ci	if (!clk_data)
7208c2ecf20Sopenharmony_ci		return;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	clk_data->clk_num = num_odfs;
7238c2ecf20Sopenharmony_ci	clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
7248c2ecf20Sopenharmony_ci				 GFP_KERNEL);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	if (!clk_data->clks)
7278c2ecf20Sopenharmony_ci		goto err;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	for (odf = 0; odf < num_odfs; odf++) {
7308c2ecf20Sopenharmony_ci		struct clk *clk;
7318c2ecf20Sopenharmony_ci		const char *clk_name;
7328c2ecf20Sopenharmony_ci		unsigned long odf_flags = 0;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci		if (of_property_read_string_index(np, "clock-output-names",
7358c2ecf20Sopenharmony_ci						  odf, &clk_name))
7368c2ecf20Sopenharmony_ci			return;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		of_clk_detect_critical(np, odf, &odf_flags);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci		clk = clkgen_odf_register(pll_name, pll_base, data, odf_flags,
7418c2ecf20Sopenharmony_ci				odf, &clkgena_c32_odf_lock, clk_name);
7428c2ecf20Sopenharmony_ci		if (IS_ERR(clk))
7438c2ecf20Sopenharmony_ci			goto err;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		clk_data->clks[odf] = clk;
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
7498c2ecf20Sopenharmony_ci	return;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cierr:
7528c2ecf20Sopenharmony_ci	kfree(pll_name);
7538c2ecf20Sopenharmony_ci	kfree(clk_data->clks);
7548c2ecf20Sopenharmony_ci	kfree(clk_data);
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_cistatic void __init clkgen_c32_pll0_setup(struct device_node *np)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	clkgen_c32_pll_setup(np,
7598c2ecf20Sopenharmony_ci			(struct clkgen_pll_data *) &st_pll3200c32_cx_0);
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ciCLK_OF_DECLARE(c32_pll0, "st,clkgen-pll0", clkgen_c32_pll0_setup);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic void __init clkgen_c32_pll1_setup(struct device_node *np)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	clkgen_c32_pll_setup(np,
7668c2ecf20Sopenharmony_ci			(struct clkgen_pll_data *) &st_pll3200c32_cx_1);
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ciCLK_OF_DECLARE(c32_pll1, "st,clkgen-pll1", clkgen_c32_pll1_setup);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic void __init clkgen_c32_plla9_setup(struct device_node *np)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	clkgen_c32_pll_setup(np,
7738c2ecf20Sopenharmony_ci			(struct clkgen_pll_data *) &st_pll3200c32_407_a9);
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ciCLK_OF_DECLARE(c32_plla9, "st,stih407-clkgen-plla9", clkgen_c32_plla9_setup);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic void __init clkgen_c28_plla9_setup(struct device_node *np)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	clkgen_c32_pll_setup(np,
7808c2ecf20Sopenharmony_ci			(struct clkgen_pll_data *) &st_pll4600c28_418_a9);
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ciCLK_OF_DECLARE(c28_plla9, "st,stih418-clkgen-plla9", clkgen_c28_plla9_setup);
783