18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2014 STMicroelectronics R&D Ltd
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
178c2ecf20Sopenharmony_ci#include "clkgen.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Maximum input clock to the PLL before we divide it down by 2
218c2ecf20Sopenharmony_ci * although in reality in actual systems this has never been seen to
228c2ecf20Sopenharmony_ci * be used.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci#define QUADFS_NDIV_THRESHOLD 30000000
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define PLL_BW_GOODREF   (0L)
278c2ecf20Sopenharmony_ci#define PLL_BW_VBADREF   (1L)
288c2ecf20Sopenharmony_ci#define PLL_BW_BADREF    (2L)
298c2ecf20Sopenharmony_ci#define PLL_BW_VGOODREF  (3L)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define QUADFS_MAX_CHAN 4
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct stm_fs {
348c2ecf20Sopenharmony_ci	unsigned long ndiv;
358c2ecf20Sopenharmony_ci	unsigned long mdiv;
368c2ecf20Sopenharmony_ci	unsigned long pe;
378c2ecf20Sopenharmony_ci	unsigned long sdiv;
388c2ecf20Sopenharmony_ci	unsigned long nsdiv;
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistruct clkgen_quadfs_data {
428c2ecf20Sopenharmony_ci	bool reset_present;
438c2ecf20Sopenharmony_ci	bool bwfilter_present;
448c2ecf20Sopenharmony_ci	bool lockstatus_present;
458c2ecf20Sopenharmony_ci	bool powerup_polarity;
468c2ecf20Sopenharmony_ci	bool standby_polarity;
478c2ecf20Sopenharmony_ci	bool nsdiv_present;
488c2ecf20Sopenharmony_ci	bool nrst_present;
498c2ecf20Sopenharmony_ci	struct clkgen_field ndiv;
508c2ecf20Sopenharmony_ci	struct clkgen_field ref_bw;
518c2ecf20Sopenharmony_ci	struct clkgen_field nreset;
528c2ecf20Sopenharmony_ci	struct clkgen_field npda;
538c2ecf20Sopenharmony_ci	struct clkgen_field lock_status;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	struct clkgen_field nrst[QUADFS_MAX_CHAN];
568c2ecf20Sopenharmony_ci	struct clkgen_field nsb[QUADFS_MAX_CHAN];
578c2ecf20Sopenharmony_ci	struct clkgen_field en[QUADFS_MAX_CHAN];
588c2ecf20Sopenharmony_ci	struct clkgen_field mdiv[QUADFS_MAX_CHAN];
598c2ecf20Sopenharmony_ci	struct clkgen_field pe[QUADFS_MAX_CHAN];
608c2ecf20Sopenharmony_ci	struct clkgen_field sdiv[QUADFS_MAX_CHAN];
618c2ecf20Sopenharmony_ci	struct clkgen_field nsdiv[QUADFS_MAX_CHAN];
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	const struct clk_ops *pll_ops;
648c2ecf20Sopenharmony_ci	int  (*get_params)(unsigned long, unsigned long, struct stm_fs *);
658c2ecf20Sopenharmony_ci	int  (*get_rate)(unsigned long , const struct stm_fs *,
668c2ecf20Sopenharmony_ci			unsigned long *);
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic const struct clk_ops st_quadfs_pll_c32_ops;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int clk_fs660c32_dig_get_params(unsigned long input,
728c2ecf20Sopenharmony_ci		unsigned long output, struct stm_fs *fs);
738c2ecf20Sopenharmony_cistatic int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *,
748c2ecf20Sopenharmony_ci		unsigned long *);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic const struct clkgen_quadfs_data st_fs660c32_C = {
778c2ecf20Sopenharmony_ci	.nrst_present = true,
788c2ecf20Sopenharmony_ci	.nrst	= { CLKGEN_FIELD(0x2f0, 0x1, 0),
798c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2f0, 0x1, 1),
808c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2f0, 0x1, 2),
818c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2f0, 0x1, 3) },
828c2ecf20Sopenharmony_ci	.npda	= CLKGEN_FIELD(0x2f0, 0x1, 12),
838c2ecf20Sopenharmony_ci	.nsb	= { CLKGEN_FIELD(0x2f0, 0x1, 8),
848c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2f0, 0x1, 9),
858c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2f0, 0x1, 10),
868c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2f0, 0x1, 11) },
878c2ecf20Sopenharmony_ci	.nsdiv_present = true,
888c2ecf20Sopenharmony_ci	.nsdiv	= { CLKGEN_FIELD(0x304, 0x1, 24),
898c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x308, 0x1, 24),
908c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x30c, 0x1, 24),
918c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x310, 0x1, 24) },
928c2ecf20Sopenharmony_ci	.mdiv	= { CLKGEN_FIELD(0x304, 0x1f, 15),
938c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x308, 0x1f, 15),
948c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x30c, 0x1f, 15),
958c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x310, 0x1f, 15) },
968c2ecf20Sopenharmony_ci	.en	= { CLKGEN_FIELD(0x2fc, 0x1, 0),
978c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2fc, 0x1, 1),
988c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2fc, 0x1, 2),
998c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2fc, 0x1, 3) },
1008c2ecf20Sopenharmony_ci	.ndiv	= CLKGEN_FIELD(0x2f4, 0x7, 16),
1018c2ecf20Sopenharmony_ci	.pe	= { CLKGEN_FIELD(0x304, 0x7fff, 0),
1028c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x308, 0x7fff, 0),
1038c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x30c, 0x7fff, 0),
1048c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x310, 0x7fff, 0) },
1058c2ecf20Sopenharmony_ci	.sdiv	= { CLKGEN_FIELD(0x304, 0xf, 20),
1068c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x308, 0xf, 20),
1078c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x30c, 0xf, 20),
1088c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x310, 0xf, 20) },
1098c2ecf20Sopenharmony_ci	.lockstatus_present = true,
1108c2ecf20Sopenharmony_ci	.lock_status = CLKGEN_FIELD(0x2f0, 0x1, 24),
1118c2ecf20Sopenharmony_ci	.powerup_polarity = 1,
1128c2ecf20Sopenharmony_ci	.standby_polarity = 1,
1138c2ecf20Sopenharmony_ci	.pll_ops	= &st_quadfs_pll_c32_ops,
1148c2ecf20Sopenharmony_ci	.get_params	= clk_fs660c32_dig_get_params,
1158c2ecf20Sopenharmony_ci	.get_rate	= clk_fs660c32_dig_get_rate,
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic const struct clkgen_quadfs_data st_fs660c32_D = {
1198c2ecf20Sopenharmony_ci	.nrst_present = true,
1208c2ecf20Sopenharmony_ci	.nrst	= { CLKGEN_FIELD(0x2a0, 0x1, 0),
1218c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2a0, 0x1, 1),
1228c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2a0, 0x1, 2),
1238c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2a0, 0x1, 3) },
1248c2ecf20Sopenharmony_ci	.ndiv	= CLKGEN_FIELD(0x2a4, 0x7, 16),
1258c2ecf20Sopenharmony_ci	.pe	= { CLKGEN_FIELD(0x2b4, 0x7fff, 0),
1268c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2b8, 0x7fff, 0),
1278c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2bc, 0x7fff, 0),
1288c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2c0, 0x7fff, 0) },
1298c2ecf20Sopenharmony_ci	.sdiv	= { CLKGEN_FIELD(0x2b4, 0xf, 20),
1308c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2b8, 0xf, 20),
1318c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2bc, 0xf, 20),
1328c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2c0, 0xf, 20) },
1338c2ecf20Sopenharmony_ci	.npda	= CLKGEN_FIELD(0x2a0, 0x1, 12),
1348c2ecf20Sopenharmony_ci	.nsb	= { CLKGEN_FIELD(0x2a0, 0x1, 8),
1358c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2a0, 0x1, 9),
1368c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2a0, 0x1, 10),
1378c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2a0, 0x1, 11) },
1388c2ecf20Sopenharmony_ci	.nsdiv_present = true,
1398c2ecf20Sopenharmony_ci	.nsdiv	= { CLKGEN_FIELD(0x2b4, 0x1, 24),
1408c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2b8, 0x1, 24),
1418c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2bc, 0x1, 24),
1428c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2c0, 0x1, 24) },
1438c2ecf20Sopenharmony_ci	.mdiv	= { CLKGEN_FIELD(0x2b4, 0x1f, 15),
1448c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2b8, 0x1f, 15),
1458c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2bc, 0x1f, 15),
1468c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2c0, 0x1f, 15) },
1478c2ecf20Sopenharmony_ci	.en	= { CLKGEN_FIELD(0x2ac, 0x1, 0),
1488c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2ac, 0x1, 1),
1498c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2ac, 0x1, 2),
1508c2ecf20Sopenharmony_ci		    CLKGEN_FIELD(0x2ac, 0x1, 3) },
1518c2ecf20Sopenharmony_ci	.lockstatus_present = true,
1528c2ecf20Sopenharmony_ci	.lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24),
1538c2ecf20Sopenharmony_ci	.powerup_polarity = 1,
1548c2ecf20Sopenharmony_ci	.standby_polarity = 1,
1558c2ecf20Sopenharmony_ci	.pll_ops	= &st_quadfs_pll_c32_ops,
1568c2ecf20Sopenharmony_ci	.get_params	= clk_fs660c32_dig_get_params,
1578c2ecf20Sopenharmony_ci	.get_rate	= clk_fs660c32_dig_get_rate,};
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/**
1608c2ecf20Sopenharmony_ci * DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor
1618c2ecf20Sopenharmony_ci *
1628c2ecf20Sopenharmony_ci * Traits of this clock:
1638c2ecf20Sopenharmony_ci * prepare - clk_(un)prepare only ensures parent is (un)prepared
1648c2ecf20Sopenharmony_ci * enable - clk_enable and clk_disable are functional & control the Fsyn
1658c2ecf20Sopenharmony_ci * rate - inherits rate from parent. set_rate/round_rate/recalc_rate
1668c2ecf20Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
1678c2ecf20Sopenharmony_ci */
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/**
1708c2ecf20Sopenharmony_ci * struct st_clk_quadfs_pll - A pll which outputs a fixed multiplier of
1718c2ecf20Sopenharmony_ci *                                  its parent clock, found inside a type of
1728c2ecf20Sopenharmony_ci *                                  ST quad channel frequency synthesizer block
1738c2ecf20Sopenharmony_ci *
1748c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces.
1758c2ecf20Sopenharmony_ci * @ndiv: regmap field for the ndiv control.
1768c2ecf20Sopenharmony_ci * @regs_base: base address of the configuration registers.
1778c2ecf20Sopenharmony_ci * @lock: spinlock.
1788c2ecf20Sopenharmony_ci *
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_cistruct st_clk_quadfs_pll {
1818c2ecf20Sopenharmony_ci	struct clk_hw	hw;
1828c2ecf20Sopenharmony_ci	void __iomem	*regs_base;
1838c2ecf20Sopenharmony_ci	spinlock_t	*lock;
1848c2ecf20Sopenharmony_ci	struct clkgen_quadfs_data *data;
1858c2ecf20Sopenharmony_ci	u32 ndiv;
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci#define to_quadfs_pll(_hw) container_of(_hw, struct st_clk_quadfs_pll, hw)
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int quadfs_pll_enable(struct clk_hw *hw)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
1938c2ecf20Sopenharmony_ci	unsigned long flags = 0, timeout = jiffies + msecs_to_jiffies(10);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (pll->lock)
1968c2ecf20Sopenharmony_ci		spin_lock_irqsave(pll->lock, flags);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/*
1998c2ecf20Sopenharmony_ci	 * Bring block out of reset if we have reset control.
2008c2ecf20Sopenharmony_ci	 */
2018c2ecf20Sopenharmony_ci	if (pll->data->reset_present)
2028c2ecf20Sopenharmony_ci		CLKGEN_WRITE(pll, nreset, 1);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/*
2058c2ecf20Sopenharmony_ci	 * Use a fixed input clock noise bandwidth filter for the moment
2068c2ecf20Sopenharmony_ci	 */
2078c2ecf20Sopenharmony_ci	if (pll->data->bwfilter_present)
2088c2ecf20Sopenharmony_ci		CLKGEN_WRITE(pll, ref_bw, PLL_BW_GOODREF);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/*
2148c2ecf20Sopenharmony_ci	 * Power up the PLL
2158c2ecf20Sopenharmony_ci	 */
2168c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, npda, !pll->data->powerup_polarity);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (pll->lock)
2198c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pll->lock, flags);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (pll->data->lockstatus_present)
2228c2ecf20Sopenharmony_ci		while (!CLKGEN_READ(pll, lock_status)) {
2238c2ecf20Sopenharmony_ci			if (time_after(jiffies, timeout))
2248c2ecf20Sopenharmony_ci				return -ETIMEDOUT;
2258c2ecf20Sopenharmony_ci			cpu_relax();
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic void quadfs_pll_disable(struct clk_hw *hw)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
2348c2ecf20Sopenharmony_ci	unsigned long flags = 0;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (pll->lock)
2378c2ecf20Sopenharmony_ci		spin_lock_irqsave(pll->lock, flags);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/*
2408c2ecf20Sopenharmony_ci	 * Powerdown the PLL and then put block into soft reset if we have
2418c2ecf20Sopenharmony_ci	 * reset control.
2428c2ecf20Sopenharmony_ci	 */
2438c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, npda, pll->data->powerup_polarity);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	if (pll->data->reset_present)
2468c2ecf20Sopenharmony_ci		CLKGEN_WRITE(pll, nreset, 0);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (pll->lock)
2498c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pll->lock, flags);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int quadfs_pll_is_enabled(struct clk_hw *hw)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
2558c2ecf20Sopenharmony_ci	u32 npda = CLKGEN_READ(pll, npda);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return pll->data->powerup_polarity ? !npda : !!npda;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs,
2618c2ecf20Sopenharmony_ci			   unsigned long *rate)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	unsigned long nd = fs->ndiv + 16; /* ndiv value */
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	*rate = input * nd;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return 0;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw,
2718c2ecf20Sopenharmony_ci					unsigned long parent_rate)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
2748c2ecf20Sopenharmony_ci	unsigned long rate = 0;
2758c2ecf20Sopenharmony_ci	struct stm_fs params;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	params.ndiv = CLKGEN_READ(pll, ndiv);
2788c2ecf20Sopenharmony_ci	if (clk_fs660c32_vco_get_rate(parent_rate, &params, &rate))
2798c2ecf20Sopenharmony_ci		pr_err("%s:%s error calculating rate\n",
2808c2ecf20Sopenharmony_ci		       clk_hw_get_name(hw), __func__);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	pll->ndiv = params.ndiv;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return rate;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int clk_fs660c32_vco_get_params(unsigned long input,
2888c2ecf20Sopenharmony_ci				unsigned long output, struct stm_fs *fs)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci/* Formula
2918c2ecf20Sopenharmony_ci   VCO frequency = (fin x ndiv) / pdiv
2928c2ecf20Sopenharmony_ci   ndiv = VCOfreq * pdiv / fin
2938c2ecf20Sopenharmony_ci   */
2948c2ecf20Sopenharmony_ci	unsigned long pdiv = 1, n;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Output clock range: 384Mhz to 660Mhz */
2978c2ecf20Sopenharmony_ci	if (output < 384000000 || output > 660000000)
2988c2ecf20Sopenharmony_ci		return -EINVAL;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (input > 40000000)
3018c2ecf20Sopenharmony_ci		/* This means that PDIV would be 2 instead of 1.
3028c2ecf20Sopenharmony_ci		   Not supported today. */
3038c2ecf20Sopenharmony_ci		return -EINVAL;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	input /= 1000;
3068c2ecf20Sopenharmony_ci	output /= 1000;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	n = output * pdiv / input;
3098c2ecf20Sopenharmony_ci	if (n < 16)
3108c2ecf20Sopenharmony_ci		n = 16;
3118c2ecf20Sopenharmony_ci	fs->ndiv = n - 16; /* Converting formula value to reg value */
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return 0;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw,
3178c2ecf20Sopenharmony_ci					   unsigned long rate,
3188c2ecf20Sopenharmony_ci					   unsigned long *prate)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct stm_fs params;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (clk_fs660c32_vco_get_params(*prate, rate, &params))
3238c2ecf20Sopenharmony_ci		return rate;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	clk_fs660c32_vco_get_rate(*prate, &params, &rate);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	pr_debug("%s: %s new rate %ld [ndiv=%u]\n",
3288c2ecf20Sopenharmony_ci		 __func__, clk_hw_get_name(hw),
3298c2ecf20Sopenharmony_ci		 rate, (unsigned int)params.ndiv);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return rate;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate,
3358c2ecf20Sopenharmony_ci				unsigned long parent_rate)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
3388c2ecf20Sopenharmony_ci	struct stm_fs params;
3398c2ecf20Sopenharmony_ci	long hwrate = 0;
3408c2ecf20Sopenharmony_ci	unsigned long flags = 0;
3418c2ecf20Sopenharmony_ci	int ret;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!rate || !parent_rate)
3448c2ecf20Sopenharmony_ci		return -EINVAL;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	ret = clk_fs660c32_vco_get_params(parent_rate, rate, &params);
3478c2ecf20Sopenharmony_ci	if (ret)
3488c2ecf20Sopenharmony_ci		return ret;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	clk_fs660c32_vco_get_rate(parent_rate, &params, &hwrate);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n",
3538c2ecf20Sopenharmony_ci		 __func__, clk_hw_get_name(hw),
3548c2ecf20Sopenharmony_ci		 hwrate, (unsigned int)params.ndiv);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (!hwrate)
3578c2ecf20Sopenharmony_ci		return -EINVAL;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	pll->ndiv = params.ndiv;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (pll->lock)
3628c2ecf20Sopenharmony_ci		spin_lock_irqsave(pll->lock, flags);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (pll->lock)
3678c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pll->lock, flags);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return 0;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic const struct clk_ops st_quadfs_pll_c32_ops = {
3738c2ecf20Sopenharmony_ci	.enable		= quadfs_pll_enable,
3748c2ecf20Sopenharmony_ci	.disable	= quadfs_pll_disable,
3758c2ecf20Sopenharmony_ci	.is_enabled	= quadfs_pll_is_enabled,
3768c2ecf20Sopenharmony_ci	.recalc_rate	= quadfs_pll_fs660c32_recalc_rate,
3778c2ecf20Sopenharmony_ci	.round_rate	= quadfs_pll_fs660c32_round_rate,
3788c2ecf20Sopenharmony_ci	.set_rate	= quadfs_pll_fs660c32_set_rate,
3798c2ecf20Sopenharmony_ci};
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic struct clk * __init st_clk_register_quadfs_pll(
3828c2ecf20Sopenharmony_ci		const char *name, const char *parent_name,
3838c2ecf20Sopenharmony_ci		struct clkgen_quadfs_data *quadfs, void __iomem *reg,
3848c2ecf20Sopenharmony_ci		spinlock_t *lock)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct st_clk_quadfs_pll *pll;
3878c2ecf20Sopenharmony_ci	struct clk *clk;
3888c2ecf20Sopenharmony_ci	struct clk_init_data init;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/*
3918c2ecf20Sopenharmony_ci	 * Sanity check required pointers.
3928c2ecf20Sopenharmony_ci	 */
3938c2ecf20Sopenharmony_ci	if (WARN_ON(!name || !parent_name))
3948c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
3978c2ecf20Sopenharmony_ci	if (!pll)
3988c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	init.name = name;
4018c2ecf20Sopenharmony_ci	init.ops = quadfs->pll_ops;
4028c2ecf20Sopenharmony_ci	init.flags = CLK_GET_RATE_NOCACHE;
4038c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
4048c2ecf20Sopenharmony_ci	init.num_parents = 1;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	pll->data = quadfs;
4078c2ecf20Sopenharmony_ci	pll->regs_base = reg;
4088c2ecf20Sopenharmony_ci	pll->lock = lock;
4098c2ecf20Sopenharmony_ci	pll->hw.init = &init;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	clk = clk_register(NULL, &pll->hw);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
4148c2ecf20Sopenharmony_ci		kfree(pll);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	return clk;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/**
4208c2ecf20Sopenharmony_ci * DOC: A digital frequency synthesizer
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci * Traits of this clock:
4238c2ecf20Sopenharmony_ci * prepare - clk_(un)prepare only ensures parent is (un)prepared
4248c2ecf20Sopenharmony_ci * enable - clk_enable and clk_disable are functional
4258c2ecf20Sopenharmony_ci * rate - set rate is functional
4268c2ecf20Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
4278c2ecf20Sopenharmony_ci */
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci/**
4308c2ecf20Sopenharmony_ci * struct st_clk_quadfs_fsynth - One clock output from a four channel digital
4318c2ecf20Sopenharmony_ci *                                  frequency synthesizer (fsynth) block.
4328c2ecf20Sopenharmony_ci *
4338c2ecf20Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces
4348c2ecf20Sopenharmony_ci *
4358c2ecf20Sopenharmony_ci * @nsb: regmap field in the output control register for the digital
4368c2ecf20Sopenharmony_ci *       standby of this fsynth channel. This control is active low so
4378c2ecf20Sopenharmony_ci *       the channel is in standby when the control bit is cleared.
4388c2ecf20Sopenharmony_ci *
4398c2ecf20Sopenharmony_ci * @nsdiv: regmap field in the output control register for
4408c2ecf20Sopenharmony_ci *          for the optional divide by 3 of this fsynth channel. This control
4418c2ecf20Sopenharmony_ci *          is active low so the divide by 3 is active when the control bit is
4428c2ecf20Sopenharmony_ci *          cleared and the divide is bypassed when the bit is set.
4438c2ecf20Sopenharmony_ci */
4448c2ecf20Sopenharmony_cistruct st_clk_quadfs_fsynth {
4458c2ecf20Sopenharmony_ci	struct clk_hw	hw;
4468c2ecf20Sopenharmony_ci	void __iomem	*regs_base;
4478c2ecf20Sopenharmony_ci	spinlock_t	*lock;
4488c2ecf20Sopenharmony_ci	struct clkgen_quadfs_data *data;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	u32 chan;
4518c2ecf20Sopenharmony_ci	/*
4528c2ecf20Sopenharmony_ci	 * Cached hardware values from set_rate so we can program the
4538c2ecf20Sopenharmony_ci	 * hardware in enable. There are two reasons for this:
4548c2ecf20Sopenharmony_ci	 *
4558c2ecf20Sopenharmony_ci	 *  1. The registers may not be writable until the parent has been
4568c2ecf20Sopenharmony_ci	 *     enabled.
4578c2ecf20Sopenharmony_ci	 *
4588c2ecf20Sopenharmony_ci	 *  2. It restores the clock rate when a driver does an enable
4598c2ecf20Sopenharmony_ci	 *     on PM restore, after a suspend to RAM has lost the hardware
4608c2ecf20Sopenharmony_ci	 *     setup.
4618c2ecf20Sopenharmony_ci	 */
4628c2ecf20Sopenharmony_ci	u32 md;
4638c2ecf20Sopenharmony_ci	u32 pe;
4648c2ecf20Sopenharmony_ci	u32 sdiv;
4658c2ecf20Sopenharmony_ci	u32 nsdiv;
4668c2ecf20Sopenharmony_ci};
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci#define to_quadfs_fsynth(_hw) \
4698c2ecf20Sopenharmony_ci	container_of(_hw, struct st_clk_quadfs_fsynth, hw)
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic void quadfs_fsynth_program_enable(struct st_clk_quadfs_fsynth *fs)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	/*
4748c2ecf20Sopenharmony_ci	 * Pulse the program enable register lsb to make the hardware take
4758c2ecf20Sopenharmony_ci	 * notice of the new md/pe values with a glitchless transition.
4768c2ecf20Sopenharmony_ci	 */
4778c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, en[fs->chan], 1);
4788c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, en[fs->chan], 0);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic void quadfs_fsynth_program_rate(struct st_clk_quadfs_fsynth *fs)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	unsigned long flags = 0;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	/*
4868c2ecf20Sopenharmony_ci	 * Ensure the md/pe parameters are ignored while we are
4878c2ecf20Sopenharmony_ci	 * reprogramming them so we can get a glitchless change
4888c2ecf20Sopenharmony_ci	 * when fine tuning the speed of a running clock.
4898c2ecf20Sopenharmony_ci	 */
4908c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, en[fs->chan], 0);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, mdiv[fs->chan], fs->md);
4938c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, pe[fs->chan], fs->pe);
4948c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, sdiv[fs->chan], fs->sdiv);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (fs->lock)
4978c2ecf20Sopenharmony_ci		spin_lock_irqsave(fs->lock, flags);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (fs->data->nsdiv_present)
5008c2ecf20Sopenharmony_ci		CLKGEN_WRITE(fs, nsdiv[fs->chan], fs->nsdiv);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (fs->lock)
5038c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(fs->lock, flags);
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic int quadfs_fsynth_enable(struct clk_hw *hw)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
5098c2ecf20Sopenharmony_ci	unsigned long flags = 0;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw));
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	quadfs_fsynth_program_rate(fs);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (fs->lock)
5168c2ecf20Sopenharmony_ci		spin_lock_irqsave(fs->lock, flags);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (fs->data->nrst_present)
5218c2ecf20Sopenharmony_ci		CLKGEN_WRITE(fs, nrst[fs->chan], 0);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (fs->lock)
5248c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(fs->lock, flags);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	quadfs_fsynth_program_enable(fs);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	return 0;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic void quadfs_fsynth_disable(struct clk_hw *hw)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
5348c2ecf20Sopenharmony_ci	unsigned long flags = 0;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw));
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (fs->lock)
5398c2ecf20Sopenharmony_ci		spin_lock_irqsave(fs->lock, flags);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	CLKGEN_WRITE(fs, nsb[fs->chan], fs->data->standby_polarity);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (fs->lock)
5448c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(fs->lock, flags);
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_cistatic int quadfs_fsynth_is_enabled(struct clk_hw *hw)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
5508c2ecf20Sopenharmony_ci	u32 nsb = CLKGEN_READ(fs, nsb[fs->chan]);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	pr_debug("%s: %s enable bit = 0x%x\n",
5538c2ecf20Sopenharmony_ci		 __func__, clk_hw_get_name(hw), nsb);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	return fs->data->standby_polarity ? !nsb : !!nsb;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci#define P20		(uint64_t)(1 << 20)
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int clk_fs660c32_dig_get_rate(unsigned long input,
5618c2ecf20Sopenharmony_ci				const struct stm_fs *fs, unsigned long *rate)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	unsigned long s = (1 << fs->sdiv);
5648c2ecf20Sopenharmony_ci	unsigned long ns;
5658c2ecf20Sopenharmony_ci	uint64_t res;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	/*
5688c2ecf20Sopenharmony_ci	 * 'nsdiv' is a register value ('BIN') which is translated
5698c2ecf20Sopenharmony_ci	 * to a decimal value according to following rules.
5708c2ecf20Sopenharmony_ci	 *
5718c2ecf20Sopenharmony_ci	 *     nsdiv      ns.dec
5728c2ecf20Sopenharmony_ci	 *       0        3
5738c2ecf20Sopenharmony_ci	 *       1        1
5748c2ecf20Sopenharmony_ci	 */
5758c2ecf20Sopenharmony_ci	ns = (fs->nsdiv == 1) ? 1 : 3;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	res = (P20 * (32 + fs->mdiv) + 32 * fs->pe) * s * ns;
5788c2ecf20Sopenharmony_ci	*rate = (unsigned long)div64_u64(input * P20 * 32, res);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	return 0;
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int clk_fs660c32_get_pe(int m, int si, unsigned long *deviation,
5858c2ecf20Sopenharmony_ci		signed long input, unsigned long output, uint64_t *p,
5868c2ecf20Sopenharmony_ci		struct stm_fs *fs)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	unsigned long new_freq, new_deviation;
5898c2ecf20Sopenharmony_ci	struct stm_fs fs_tmp;
5908c2ecf20Sopenharmony_ci	uint64_t val;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	val = (uint64_t)output << si;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	*p = (uint64_t)input * P20 - (32LL  + (uint64_t)m) * val * (P20 / 32LL);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	*p = div64_u64(*p, val);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	if (*p > 32767LL)
5998c2ecf20Sopenharmony_ci		return 1;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	fs_tmp.mdiv = (unsigned long) m;
6028c2ecf20Sopenharmony_ci	fs_tmp.pe = (unsigned long)*p;
6038c2ecf20Sopenharmony_ci	fs_tmp.sdiv = si;
6048c2ecf20Sopenharmony_ci	fs_tmp.nsdiv = 1;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	new_deviation = abs(output - new_freq);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	if (new_deviation < *deviation) {
6118c2ecf20Sopenharmony_ci		fs->mdiv = m;
6128c2ecf20Sopenharmony_ci		fs->pe = (unsigned long)*p;
6138c2ecf20Sopenharmony_ci		fs->sdiv = si;
6148c2ecf20Sopenharmony_ci		fs->nsdiv = 1;
6158c2ecf20Sopenharmony_ci		*deviation = new_deviation;
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci	return 0;
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic int clk_fs660c32_dig_get_params(unsigned long input,
6218c2ecf20Sopenharmony_ci		unsigned long output, struct stm_fs *fs)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	int si;	/* sdiv_reg (8 downto 0) */
6248c2ecf20Sopenharmony_ci	int m; /* md value */
6258c2ecf20Sopenharmony_ci	unsigned long new_freq, new_deviation;
6268c2ecf20Sopenharmony_ci	/* initial condition to say: "infinite deviation" */
6278c2ecf20Sopenharmony_ci	unsigned long deviation = ~0;
6288c2ecf20Sopenharmony_ci	uint64_t p, p1, p2;	/* pe value */
6298c2ecf20Sopenharmony_ci	int r1, r2;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	struct stm_fs fs_tmp;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	for (si = 0; (si <= 8) && deviation; si++) {
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		/* Boundary test to avoid useless iteration */
6368c2ecf20Sopenharmony_ci		r1 = clk_fs660c32_get_pe(0, si, &deviation,
6378c2ecf20Sopenharmony_ci				input, output, &p1, fs);
6388c2ecf20Sopenharmony_ci		r2 = clk_fs660c32_get_pe(31, si, &deviation,
6398c2ecf20Sopenharmony_ci				input, output, &p2, fs);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		/* No solution */
6428c2ecf20Sopenharmony_ci		if (r1 && r2 && (p1 > p2))
6438c2ecf20Sopenharmony_ci			continue;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		/* Try to find best deviation */
6468c2ecf20Sopenharmony_ci		for (m = 1; (m < 31) && deviation; m++)
6478c2ecf20Sopenharmony_ci			clk_fs660c32_get_pe(m, si, &deviation,
6488c2ecf20Sopenharmony_ci					input, output, &p, fs);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if (deviation == ~0) /* No solution found */
6538c2ecf20Sopenharmony_ci		return -1;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	/* pe fine tuning if deviation not 0: +/- 2 around computed pe value */
6568c2ecf20Sopenharmony_ci	if (deviation) {
6578c2ecf20Sopenharmony_ci		fs_tmp.mdiv = fs->mdiv;
6588c2ecf20Sopenharmony_ci		fs_tmp.sdiv = fs->sdiv;
6598c2ecf20Sopenharmony_ci		fs_tmp.nsdiv = fs->nsdiv;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci		if (fs->pe > 2)
6628c2ecf20Sopenharmony_ci			p2 = fs->pe - 2;
6638c2ecf20Sopenharmony_ci		else
6648c2ecf20Sopenharmony_ci			p2 = 0;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		for (; p2 < 32768ll && (p2 <= (fs->pe + 2)); p2++) {
6678c2ecf20Sopenharmony_ci			fs_tmp.pe = (unsigned long)p2;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci			clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci			new_deviation = abs(output - new_freq);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci			/* Check if this is a better solution */
6748c2ecf20Sopenharmony_ci			if (new_deviation < deviation) {
6758c2ecf20Sopenharmony_ci				fs->pe = (unsigned long)p2;
6768c2ecf20Sopenharmony_ci				deviation = new_deviation;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci			}
6798c2ecf20Sopenharmony_ci		}
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci	return 0;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth *fs,
6858c2ecf20Sopenharmony_ci		struct stm_fs *params)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	/*
6888c2ecf20Sopenharmony_ci	 * Get the initial hardware values for recalc_rate
6898c2ecf20Sopenharmony_ci	 */
6908c2ecf20Sopenharmony_ci	params->mdiv	= CLKGEN_READ(fs, mdiv[fs->chan]);
6918c2ecf20Sopenharmony_ci	params->pe	= CLKGEN_READ(fs, pe[fs->chan]);
6928c2ecf20Sopenharmony_ci	params->sdiv	= CLKGEN_READ(fs, sdiv[fs->chan]);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	if (fs->data->nsdiv_present)
6958c2ecf20Sopenharmony_ci		params->nsdiv = CLKGEN_READ(fs, nsdiv[fs->chan]);
6968c2ecf20Sopenharmony_ci	else
6978c2ecf20Sopenharmony_ci		params->nsdiv = 1;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	/*
7008c2ecf20Sopenharmony_ci	 * If All are NULL then assume no clock rate is programmed.
7018c2ecf20Sopenharmony_ci	 */
7028c2ecf20Sopenharmony_ci	if (!params->mdiv && !params->pe && !params->sdiv)
7038c2ecf20Sopenharmony_ci		return 1;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	fs->md = params->mdiv;
7068c2ecf20Sopenharmony_ci	fs->pe = params->pe;
7078c2ecf20Sopenharmony_ci	fs->sdiv = params->sdiv;
7088c2ecf20Sopenharmony_ci	fs->nsdiv = params->nsdiv;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	return 0;
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic long quadfs_find_best_rate(struct clk_hw *hw, unsigned long drate,
7148c2ecf20Sopenharmony_ci				unsigned long prate, struct stm_fs *params)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
7178c2ecf20Sopenharmony_ci	int (*clk_fs_get_rate)(unsigned long ,
7188c2ecf20Sopenharmony_ci				const struct stm_fs *, unsigned long *);
7198c2ecf20Sopenharmony_ci	int (*clk_fs_get_params)(unsigned long, unsigned long, struct stm_fs *);
7208c2ecf20Sopenharmony_ci	unsigned long rate = 0;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	clk_fs_get_rate = fs->data->get_rate;
7238c2ecf20Sopenharmony_ci	clk_fs_get_params = fs->data->get_params;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (!clk_fs_get_params(prate, drate, params))
7268c2ecf20Sopenharmony_ci		clk_fs_get_rate(prate, params, &rate);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	return rate;
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic unsigned long quadfs_recalc_rate(struct clk_hw *hw,
7328c2ecf20Sopenharmony_ci		unsigned long parent_rate)
7338c2ecf20Sopenharmony_ci{
7348c2ecf20Sopenharmony_ci	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
7358c2ecf20Sopenharmony_ci	unsigned long rate = 0;
7368c2ecf20Sopenharmony_ci	struct stm_fs params;
7378c2ecf20Sopenharmony_ci	int (*clk_fs_get_rate)(unsigned long ,
7388c2ecf20Sopenharmony_ci				const struct stm_fs *, unsigned long *);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	clk_fs_get_rate = fs->data->get_rate;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (quadfs_fsynt_get_hw_value_for_recalc(fs, &params))
7438c2ecf20Sopenharmony_ci		return 0;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (clk_fs_get_rate(parent_rate, &params, &rate)) {
7468c2ecf20Sopenharmony_ci		pr_err("%s:%s error calculating rate\n",
7478c2ecf20Sopenharmony_ci		       clk_hw_get_name(hw), __func__);
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	return rate;
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic long quadfs_round_rate(struct clk_hw *hw, unsigned long rate,
7568c2ecf20Sopenharmony_ci				     unsigned long *prate)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct stm_fs params;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	rate = quadfs_find_best_rate(hw, rate, *prate, &params);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
7638c2ecf20Sopenharmony_ci		 __func__, clk_hw_get_name(hw),
7648c2ecf20Sopenharmony_ci		 rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv,
7658c2ecf20Sopenharmony_ci			 (unsigned int)params.pe, (unsigned int)params.nsdiv);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	return rate;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistatic void quadfs_program_and_enable(struct st_clk_quadfs_fsynth *fs,
7728c2ecf20Sopenharmony_ci		struct stm_fs *params)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	fs->md = params->mdiv;
7758c2ecf20Sopenharmony_ci	fs->pe = params->pe;
7768c2ecf20Sopenharmony_ci	fs->sdiv = params->sdiv;
7778c2ecf20Sopenharmony_ci	fs->nsdiv = params->nsdiv;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/*
7808c2ecf20Sopenharmony_ci	 * In some integrations you can only change the fsynth programming when
7818c2ecf20Sopenharmony_ci	 * the parent entity containing it is enabled.
7828c2ecf20Sopenharmony_ci	 */
7838c2ecf20Sopenharmony_ci	quadfs_fsynth_program_rate(fs);
7848c2ecf20Sopenharmony_ci	quadfs_fsynth_program_enable(fs);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic int quadfs_set_rate(struct clk_hw *hw, unsigned long rate,
7888c2ecf20Sopenharmony_ci				  unsigned long parent_rate)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
7918c2ecf20Sopenharmony_ci	struct stm_fs params;
7928c2ecf20Sopenharmony_ci	long hwrate;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (!rate || !parent_rate)
7958c2ecf20Sopenharmony_ci		return -EINVAL;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(struct stm_fs));
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	hwrate = quadfs_find_best_rate(hw, rate, parent_rate, &params);
8008c2ecf20Sopenharmony_ci	if (!hwrate)
8018c2ecf20Sopenharmony_ci		return -EINVAL;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	quadfs_program_and_enable(fs, &params);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	return 0;
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cistatic const struct clk_ops st_quadfs_ops = {
8118c2ecf20Sopenharmony_ci	.enable		= quadfs_fsynth_enable,
8128c2ecf20Sopenharmony_ci	.disable	= quadfs_fsynth_disable,
8138c2ecf20Sopenharmony_ci	.is_enabled	= quadfs_fsynth_is_enabled,
8148c2ecf20Sopenharmony_ci	.round_rate	= quadfs_round_rate,
8158c2ecf20Sopenharmony_ci	.set_rate	= quadfs_set_rate,
8168c2ecf20Sopenharmony_ci	.recalc_rate	= quadfs_recalc_rate,
8178c2ecf20Sopenharmony_ci};
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic struct clk * __init st_clk_register_quadfs_fsynth(
8208c2ecf20Sopenharmony_ci		const char *name, const char *parent_name,
8218c2ecf20Sopenharmony_ci		struct clkgen_quadfs_data *quadfs, void __iomem *reg, u32 chan,
8228c2ecf20Sopenharmony_ci		unsigned long flags, spinlock_t *lock)
8238c2ecf20Sopenharmony_ci{
8248c2ecf20Sopenharmony_ci	struct st_clk_quadfs_fsynth *fs;
8258c2ecf20Sopenharmony_ci	struct clk *clk;
8268c2ecf20Sopenharmony_ci	struct clk_init_data init;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	/*
8298c2ecf20Sopenharmony_ci	 * Sanity check required pointers, note that nsdiv3 is optional.
8308c2ecf20Sopenharmony_ci	 */
8318c2ecf20Sopenharmony_ci	if (WARN_ON(!name || !parent_name))
8328c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	fs = kzalloc(sizeof(*fs), GFP_KERNEL);
8358c2ecf20Sopenharmony_ci	if (!fs)
8368c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	init.name = name;
8398c2ecf20Sopenharmony_ci	init.ops = &st_quadfs_ops;
8408c2ecf20Sopenharmony_ci	init.flags = flags | CLK_GET_RATE_NOCACHE;
8418c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
8428c2ecf20Sopenharmony_ci	init.num_parents = 1;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	fs->data = quadfs;
8458c2ecf20Sopenharmony_ci	fs->regs_base = reg;
8468c2ecf20Sopenharmony_ci	fs->chan = chan;
8478c2ecf20Sopenharmony_ci	fs->lock = lock;
8488c2ecf20Sopenharmony_ci	fs->hw.init = &init;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	clk = clk_register(NULL, &fs->hw);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
8538c2ecf20Sopenharmony_ci		kfree(fs);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return clk;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic void __init st_of_create_quadfs_fsynths(
8598c2ecf20Sopenharmony_ci		struct device_node *np, const char *pll_name,
8608c2ecf20Sopenharmony_ci		struct clkgen_quadfs_data *quadfs, void __iomem *reg,
8618c2ecf20Sopenharmony_ci		spinlock_t *lock)
8628c2ecf20Sopenharmony_ci{
8638c2ecf20Sopenharmony_ci	struct clk_onecell_data *clk_data;
8648c2ecf20Sopenharmony_ci	int fschan;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
8678c2ecf20Sopenharmony_ci	if (!clk_data)
8688c2ecf20Sopenharmony_ci		return;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	clk_data->clk_num = QUADFS_MAX_CHAN;
8718c2ecf20Sopenharmony_ci	clk_data->clks = kcalloc(QUADFS_MAX_CHAN, sizeof(struct clk *),
8728c2ecf20Sopenharmony_ci				 GFP_KERNEL);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	if (!clk_data->clks) {
8758c2ecf20Sopenharmony_ci		kfree(clk_data);
8768c2ecf20Sopenharmony_ci		return;
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	for (fschan = 0; fschan < QUADFS_MAX_CHAN; fschan++) {
8808c2ecf20Sopenharmony_ci		struct clk *clk;
8818c2ecf20Sopenharmony_ci		const char *clk_name;
8828c2ecf20Sopenharmony_ci		unsigned long flags = 0;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		if (of_property_read_string_index(np, "clock-output-names",
8858c2ecf20Sopenharmony_ci						  fschan, &clk_name)) {
8868c2ecf20Sopenharmony_ci			break;
8878c2ecf20Sopenharmony_ci		}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		/*
8908c2ecf20Sopenharmony_ci		 * If we read an empty clock name then the channel is unused
8918c2ecf20Sopenharmony_ci		 */
8928c2ecf20Sopenharmony_ci		if (*clk_name == '\0')
8938c2ecf20Sopenharmony_ci			continue;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci		of_clk_detect_critical(np, fschan, &flags);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci		clk = st_clk_register_quadfs_fsynth(clk_name, pll_name,
8988c2ecf20Sopenharmony_ci						    quadfs, reg, fschan,
8998c2ecf20Sopenharmony_ci						    flags, lock);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		/*
9028c2ecf20Sopenharmony_ci		 * If there was an error registering this clock output, clean
9038c2ecf20Sopenharmony_ci		 * up and move on to the next one.
9048c2ecf20Sopenharmony_ci		 */
9058c2ecf20Sopenharmony_ci		if (!IS_ERR(clk)) {
9068c2ecf20Sopenharmony_ci			clk_data->clks[fschan] = clk;
9078c2ecf20Sopenharmony_ci			pr_debug("%s: parent %s rate %u\n",
9088c2ecf20Sopenharmony_ci				__clk_get_name(clk),
9098c2ecf20Sopenharmony_ci				__clk_get_name(clk_get_parent(clk)),
9108c2ecf20Sopenharmony_ci				(unsigned int)clk_get_rate(clk));
9118c2ecf20Sopenharmony_ci		}
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic void __init st_of_quadfs_setup(struct device_node *np,
9188c2ecf20Sopenharmony_ci		struct clkgen_quadfs_data *data)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	struct clk *clk;
9218c2ecf20Sopenharmony_ci	const char *pll_name, *clk_parent_name;
9228c2ecf20Sopenharmony_ci	void __iomem *reg;
9238c2ecf20Sopenharmony_ci	spinlock_t *lock;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	reg = of_iomap(np, 0);
9268c2ecf20Sopenharmony_ci	if (!reg)
9278c2ecf20Sopenharmony_ci		return;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	clk_parent_name = of_clk_get_parent_name(np, 0);
9308c2ecf20Sopenharmony_ci	if (!clk_parent_name)
9318c2ecf20Sopenharmony_ci		return;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	pll_name = kasprintf(GFP_KERNEL, "%pOFn.pll", np);
9348c2ecf20Sopenharmony_ci	if (!pll_name)
9358c2ecf20Sopenharmony_ci		return;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	lock = kzalloc(sizeof(*lock), GFP_KERNEL);
9388c2ecf20Sopenharmony_ci	if (!lock)
9398c2ecf20Sopenharmony_ci		goto err_exit;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	spin_lock_init(lock);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, data,
9448c2ecf20Sopenharmony_ci			reg, lock);
9458c2ecf20Sopenharmony_ci	if (IS_ERR(clk)) {
9468c2ecf20Sopenharmony_ci		kfree(lock);
9478c2ecf20Sopenharmony_ci		goto err_exit;
9488c2ecf20Sopenharmony_ci	} else
9498c2ecf20Sopenharmony_ci		pr_debug("%s: parent %s rate %u\n",
9508c2ecf20Sopenharmony_ci			__clk_get_name(clk),
9518c2ecf20Sopenharmony_ci			__clk_get_name(clk_get_parent(clk)),
9528c2ecf20Sopenharmony_ci			(unsigned int)clk_get_rate(clk));
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	st_of_create_quadfs_fsynths(np, pll_name, data, reg, lock);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_cierr_exit:
9578c2ecf20Sopenharmony_ci	kfree(pll_name); /* No longer need local copy of the PLL name */
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic void __init st_of_quadfs660C_setup(struct device_node *np)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_C);
9638c2ecf20Sopenharmony_ci}
9648c2ecf20Sopenharmony_ciCLK_OF_DECLARE(quadfs660C, "st,quadfs-pll", st_of_quadfs660C_setup);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic void __init st_of_quadfs660D_setup(struct device_node *np)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_D);
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ciCLK_OF_DECLARE(quadfs660D, "st,quadfs", st_of_quadfs660D_setup);
971