18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2016 Atmel Corporation,
48c2ecf20Sopenharmony_ci *		       Songjun Wu <songjun.wu@atmel.com>,
58c2ecf20Sopenharmony_ci *                     Nicolas Ferre <nicolas.ferre@atmel.com>
68c2ecf20Sopenharmony_ci *  Copyright (C) 2017 Free Electrons,
78c2ecf20Sopenharmony_ci *		       Quentin Schulz <quentin.schulz@free-electrons.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * The Sama5d2 SoC has two audio PLLs (PMC and PAD) that shares the same parent
108c2ecf20Sopenharmony_ci * (FRAC). FRAC can output between 620 and 700MHz and only multiply the rate of
118c2ecf20Sopenharmony_ci * its own parent. PMC and PAD can then divide the FRAC rate to best match the
128c2ecf20Sopenharmony_ci * asked rate.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Traits of FRAC clock:
158c2ecf20Sopenharmony_ci * enable - clk_enable writes nd, fracr parameters and enables PLL
168c2ecf20Sopenharmony_ci * rate - rate is adjustable.
178c2ecf20Sopenharmony_ci *        clk->rate = parent->rate * ((nd + 1) + (fracr / 2^22))
188c2ecf20Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Traits of PMC clock:
218c2ecf20Sopenharmony_ci * enable - clk_enable writes qdpmc, and enables PMC output
228c2ecf20Sopenharmony_ci * rate - rate is adjustable.
238c2ecf20Sopenharmony_ci *        clk->rate = parent->rate / (qdpmc + 1)
248c2ecf20Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Traits of PAD clock:
278c2ecf20Sopenharmony_ci * enable - clk_enable writes divisors and enables PAD output
288c2ecf20Sopenharmony_ci * rate - rate is adjustable.
298c2ecf20Sopenharmony_ci *        clk->rate = parent->rate / (qdaudio * div))
308c2ecf20Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/clk.h>
348c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
358c2ecf20Sopenharmony_ci#include <linux/clk/at91_pmc.h>
368c2ecf20Sopenharmony_ci#include <linux/of.h>
378c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
388c2ecf20Sopenharmony_ci#include <linux/regmap.h>
398c2ecf20Sopenharmony_ci#include <linux/slab.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "pmc.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define AUDIO_PLL_DIV_FRAC	BIT(22)
448c2ecf20Sopenharmony_ci#define AUDIO_PLL_ND_MAX	(AT91_PMC_AUDIO_PLL_ND_MASK >> \
458c2ecf20Sopenharmony_ci					AT91_PMC_AUDIO_PLL_ND_OFFSET)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define AUDIO_PLL_QDPAD(qd, div)	((AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV(qd) & \
488c2ecf20Sopenharmony_ci					  AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK) | \
498c2ecf20Sopenharmony_ci					 (AT91_PMC_AUDIO_PLL_QDPAD_DIV(div) & \
508c2ecf20Sopenharmony_ci					  AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK))
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define AUDIO_PLL_QDPMC_MAX		(AT91_PMC_AUDIO_PLL_QDPMC_MASK >> \
538c2ecf20Sopenharmony_ci						AT91_PMC_AUDIO_PLL_QDPMC_OFFSET)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define AUDIO_PLL_FOUT_MIN	620000000UL
568c2ecf20Sopenharmony_ci#define AUDIO_PLL_FOUT_MAX	700000000UL
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistruct clk_audio_frac {
598c2ecf20Sopenharmony_ci	struct clk_hw hw;
608c2ecf20Sopenharmony_ci	struct regmap *regmap;
618c2ecf20Sopenharmony_ci	u32 fracr;
628c2ecf20Sopenharmony_ci	u8 nd;
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistruct clk_audio_pad {
668c2ecf20Sopenharmony_ci	struct clk_hw hw;
678c2ecf20Sopenharmony_ci	struct regmap *regmap;
688c2ecf20Sopenharmony_ci	u8 qdaudio;
698c2ecf20Sopenharmony_ci	u8 div;
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistruct clk_audio_pmc {
738c2ecf20Sopenharmony_ci	struct clk_hw hw;
748c2ecf20Sopenharmony_ci	struct regmap *regmap;
758c2ecf20Sopenharmony_ci	u8 qdpmc;
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define to_clk_audio_frac(hw) container_of(hw, struct clk_audio_frac, hw)
798c2ecf20Sopenharmony_ci#define to_clk_audio_pad(hw) container_of(hw, struct clk_audio_pad, hw)
808c2ecf20Sopenharmony_ci#define to_clk_audio_pmc(hw) container_of(hw, struct clk_audio_pmc, hw)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int clk_audio_pll_frac_enable(struct clk_hw *hw)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct clk_audio_frac *frac = to_clk_audio_frac(hw);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
878c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_RESETN, 0);
888c2ecf20Sopenharmony_ci	regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
898c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_RESETN,
908c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_RESETN);
918c2ecf20Sopenharmony_ci	regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL1,
928c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_FRACR_MASK, frac->fracr);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/*
958c2ecf20Sopenharmony_ci	 * reset and enable have to be done in 2 separated writes
968c2ecf20Sopenharmony_ci	 * for AT91_PMC_AUDIO_PLL0
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
998c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PLLEN |
1008c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_ND_MASK,
1018c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PLLEN |
1028c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_ND(frac->nd));
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int clk_audio_pll_pad_enable(struct clk_hw *hw)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL1,
1128c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_QDPAD_MASK,
1138c2ecf20Sopenharmony_ci			   AUDIO_PLL_QDPAD(apad_ck->qdaudio, apad_ck->div));
1148c2ecf20Sopenharmony_ci	regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
1158c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PADEN, AT91_PMC_AUDIO_PLL_PADEN);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return 0;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int clk_audio_pll_pmc_enable(struct clk_hw *hw)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
1258c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PMCEN |
1268c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_QDPMC_MASK,
1278c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PMCEN |
1288c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_QDPMC(apmc_ck->qdpmc));
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic void clk_audio_pll_frac_disable(struct clk_hw *hw)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct clk_audio_frac *frac = to_clk_audio_frac(hw);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
1378c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PLLEN, 0);
1388c2ecf20Sopenharmony_ci	/* do it in 2 separated writes */
1398c2ecf20Sopenharmony_ci	regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
1408c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_RESETN, 0);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic void clk_audio_pll_pad_disable(struct clk_hw *hw)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
1488c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PADEN, 0);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic void clk_audio_pll_pmc_disable(struct clk_hw *hw)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
1568c2ecf20Sopenharmony_ci			   AT91_PMC_AUDIO_PLL_PMCEN, 0);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic unsigned long clk_audio_pll_fout(unsigned long parent_rate,
1608c2ecf20Sopenharmony_ci					unsigned long nd, unsigned long fracr)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	unsigned long long fr = (unsigned long long)parent_rate * fracr;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	fr = DIV_ROUND_CLOSEST_ULL(fr, AUDIO_PLL_DIV_FRAC);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return parent_rate * (nd + 1) + fr;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic unsigned long clk_audio_pll_frac_recalc_rate(struct clk_hw *hw,
1748c2ecf20Sopenharmony_ci						    unsigned long parent_rate)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct clk_audio_frac *frac = to_clk_audio_frac(hw);
1778c2ecf20Sopenharmony_ci	unsigned long fout;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	fout = clk_audio_pll_fout(parent_rate, frac->nd, frac->fracr);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	pr_debug("A PLL: %s, fout = %lu (nd = %u, fracr = %lu)\n", __func__,
1828c2ecf20Sopenharmony_ci		 fout, frac->nd, (unsigned long)frac->fracr);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return fout;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic unsigned long clk_audio_pll_pad_recalc_rate(struct clk_hw *hw,
1888c2ecf20Sopenharmony_ci						   unsigned long parent_rate)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
1918c2ecf20Sopenharmony_ci	unsigned long apad_rate = 0;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (apad_ck->qdaudio && apad_ck->div)
1948c2ecf20Sopenharmony_ci		apad_rate = parent_rate / (apad_ck->qdaudio * apad_ck->div);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	pr_debug("A PLL/PAD: %s, apad_rate = %lu (div = %u, qdaudio = %u)\n",
1978c2ecf20Sopenharmony_ci		 __func__, apad_rate, apad_ck->div, apad_ck->qdaudio);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return apad_rate;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic unsigned long clk_audio_pll_pmc_recalc_rate(struct clk_hw *hw,
2038c2ecf20Sopenharmony_ci						   unsigned long parent_rate)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
2068c2ecf20Sopenharmony_ci	unsigned long apmc_rate = 0;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	apmc_rate = parent_rate / (apmc_ck->qdpmc + 1);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	pr_debug("A PLL/PMC: %s, apmc_rate = %lu (qdpmc = %u)\n", __func__,
2118c2ecf20Sopenharmony_ci		 apmc_rate, apmc_ck->qdpmc);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return apmc_rate;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int clk_audio_pll_frac_compute_frac(unsigned long rate,
2178c2ecf20Sopenharmony_ci					   unsigned long parent_rate,
2188c2ecf20Sopenharmony_ci					   unsigned long *nd,
2198c2ecf20Sopenharmony_ci					   unsigned long *fracr)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	unsigned long long tmp, rem;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (!rate)
2248c2ecf20Sopenharmony_ci		return -EINVAL;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	tmp = rate;
2278c2ecf20Sopenharmony_ci	rem = do_div(tmp, parent_rate);
2288c2ecf20Sopenharmony_ci	if (!tmp || tmp >= AUDIO_PLL_ND_MAX)
2298c2ecf20Sopenharmony_ci		return -EINVAL;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	*nd = tmp - 1;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	tmp = rem * AUDIO_PLL_DIV_FRAC;
2348c2ecf20Sopenharmony_ci	tmp = DIV_ROUND_CLOSEST_ULL(tmp, parent_rate);
2358c2ecf20Sopenharmony_ci	if (tmp > AT91_PMC_AUDIO_PLL_FRACR_MASK)
2368c2ecf20Sopenharmony_ci		return -EINVAL;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* we can cast here as we verified the bounds just above */
2398c2ecf20Sopenharmony_ci	*fracr = (unsigned long)tmp;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return 0;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int clk_audio_pll_frac_determine_rate(struct clk_hw *hw,
2458c2ecf20Sopenharmony_ci					     struct clk_rate_request *req)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	unsigned long fracr, nd;
2488c2ecf20Sopenharmony_ci	int ret;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__,
2518c2ecf20Sopenharmony_ci		 req->rate, req->best_parent_rate);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	req->rate = clamp(req->rate, AUDIO_PLL_FOUT_MIN, AUDIO_PLL_FOUT_MAX);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	req->min_rate = max(req->min_rate, AUDIO_PLL_FOUT_MIN);
2568c2ecf20Sopenharmony_ci	req->max_rate = min(req->max_rate, AUDIO_PLL_FOUT_MAX);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	ret = clk_audio_pll_frac_compute_frac(req->rate, req->best_parent_rate,
2598c2ecf20Sopenharmony_ci					      &nd, &fracr);
2608c2ecf20Sopenharmony_ci	if (ret)
2618c2ecf20Sopenharmony_ci		return ret;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	req->rate = clk_audio_pll_fout(req->best_parent_rate, nd, fracr);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	req->best_parent_hw = clk_hw_get_parent(hw);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	pr_debug("A PLL: %s, best_rate = %lu (nd = %lu, fracr = %lu)\n",
2688c2ecf20Sopenharmony_ci		 __func__, req->rate, nd, fracr);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
2748c2ecf20Sopenharmony_ci					 unsigned long *parent_rate)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct clk_hw *pclk = clk_hw_get_parent(hw);
2778c2ecf20Sopenharmony_ci	long best_rate = -EINVAL;
2788c2ecf20Sopenharmony_ci	unsigned long best_parent_rate;
2798c2ecf20Sopenharmony_ci	unsigned long tmp_qd;
2808c2ecf20Sopenharmony_ci	u32 div;
2818c2ecf20Sopenharmony_ci	long tmp_rate;
2828c2ecf20Sopenharmony_ci	int tmp_diff;
2838c2ecf20Sopenharmony_ci	int best_diff = -1;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
2868c2ecf20Sopenharmony_ci		 rate, *parent_rate);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/*
2898c2ecf20Sopenharmony_ci	 * Rate divisor is actually made of two different divisors, multiplied
2908c2ecf20Sopenharmony_ci	 * between themselves before dividing the rate.
2918c2ecf20Sopenharmony_ci	 * tmp_qd goes from 1 to 31 and div is either 2 or 3.
2928c2ecf20Sopenharmony_ci	 * In order to avoid testing twice the rate divisor (e.g. divisor 12 can
2938c2ecf20Sopenharmony_ci	 * be found with (tmp_qd, div) = (2, 6) or (3, 4)), we remove any loop
2948c2ecf20Sopenharmony_ci	 * for a rate divisor when div is 2 and tmp_qd is a multiple of 3.
2958c2ecf20Sopenharmony_ci	 * We cannot inverse it (condition div is 3 and tmp_qd is even) or we
2968c2ecf20Sopenharmony_ci	 * would miss some rate divisor that aren't reachable with div being 2
2978c2ecf20Sopenharmony_ci	 * (e.g. rate divisor 90 is made with div = 3 and tmp_qd = 30, thus
2988c2ecf20Sopenharmony_ci	 * tmp_qd is even so we skip it because we think div 2 could make this
2998c2ecf20Sopenharmony_ci	 * rate divisor which isn't possible since tmp_qd has to be <= 31).
3008c2ecf20Sopenharmony_ci	 */
3018c2ecf20Sopenharmony_ci	for (tmp_qd = 1; tmp_qd < AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX; tmp_qd++)
3028c2ecf20Sopenharmony_ci		for (div = 2; div <= 3; div++) {
3038c2ecf20Sopenharmony_ci			if (div == 2 && tmp_qd % 3 == 0)
3048c2ecf20Sopenharmony_ci				continue;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci			best_parent_rate = clk_hw_round_rate(pclk,
3078c2ecf20Sopenharmony_ci							rate * tmp_qd * div);
3088c2ecf20Sopenharmony_ci			tmp_rate = best_parent_rate / (div * tmp_qd);
3098c2ecf20Sopenharmony_ci			tmp_diff = abs(rate - tmp_rate);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci			if (best_diff < 0 || best_diff > tmp_diff) {
3128c2ecf20Sopenharmony_ci				*parent_rate = best_parent_rate;
3138c2ecf20Sopenharmony_ci				best_rate = tmp_rate;
3148c2ecf20Sopenharmony_ci				best_diff = tmp_diff;
3158c2ecf20Sopenharmony_ci			}
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	pr_debug("A PLL/PAD: %s, best_rate = %ld, best_parent_rate = %lu\n",
3198c2ecf20Sopenharmony_ci		 __func__, best_rate, best_parent_rate);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return best_rate;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
3258c2ecf20Sopenharmony_ci					 unsigned long *parent_rate)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct clk_hw *pclk = clk_hw_get_parent(hw);
3288c2ecf20Sopenharmony_ci	long best_rate = -EINVAL;
3298c2ecf20Sopenharmony_ci	unsigned long best_parent_rate = 0;
3308c2ecf20Sopenharmony_ci	u32 tmp_qd = 0, div;
3318c2ecf20Sopenharmony_ci	long tmp_rate;
3328c2ecf20Sopenharmony_ci	int tmp_diff;
3338c2ecf20Sopenharmony_ci	int best_diff = -1;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
3368c2ecf20Sopenharmony_ci		 rate, *parent_rate);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (!rate)
3398c2ecf20Sopenharmony_ci		return 0;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	best_parent_rate = clk_round_rate(pclk->clk, 1);
3428c2ecf20Sopenharmony_ci	div = max(best_parent_rate / rate, 1UL);
3438c2ecf20Sopenharmony_ci	for (; div <= AUDIO_PLL_QDPMC_MAX; div++) {
3448c2ecf20Sopenharmony_ci		best_parent_rate = clk_round_rate(pclk->clk, rate * div);
3458c2ecf20Sopenharmony_ci		tmp_rate = best_parent_rate / div;
3468c2ecf20Sopenharmony_ci		tmp_diff = abs(rate - tmp_rate);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		if (best_diff < 0 || best_diff > tmp_diff) {
3498c2ecf20Sopenharmony_ci			*parent_rate = best_parent_rate;
3508c2ecf20Sopenharmony_ci			best_rate = tmp_rate;
3518c2ecf20Sopenharmony_ci			best_diff = tmp_diff;
3528c2ecf20Sopenharmony_ci			tmp_qd = div;
3538c2ecf20Sopenharmony_ci			if (!best_diff)
3548c2ecf20Sopenharmony_ci				break;	/* got exact match */
3558c2ecf20Sopenharmony_ci		}
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	pr_debug("A PLL/PMC: %s, best_rate = %ld, best_parent_rate = %lu (qd = %d)\n",
3598c2ecf20Sopenharmony_ci		 __func__, best_rate, *parent_rate, tmp_qd - 1);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return best_rate;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic int clk_audio_pll_frac_set_rate(struct clk_hw *hw, unsigned long rate,
3658c2ecf20Sopenharmony_ci				       unsigned long parent_rate)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct clk_audio_frac *frac = to_clk_audio_frac(hw);
3688c2ecf20Sopenharmony_ci	unsigned long fracr, nd;
3698c2ecf20Sopenharmony_ci	int ret;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__, rate,
3728c2ecf20Sopenharmony_ci		 parent_rate);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (rate < AUDIO_PLL_FOUT_MIN || rate > AUDIO_PLL_FOUT_MAX)
3758c2ecf20Sopenharmony_ci		return -EINVAL;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	ret = clk_audio_pll_frac_compute_frac(rate, parent_rate, &nd, &fracr);
3788c2ecf20Sopenharmony_ci	if (ret)
3798c2ecf20Sopenharmony_ci		return ret;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	frac->nd = nd;
3828c2ecf20Sopenharmony_ci	frac->fracr = fracr;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int clk_audio_pll_pad_set_rate(struct clk_hw *hw, unsigned long rate,
3888c2ecf20Sopenharmony_ci				      unsigned long parent_rate)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
3918c2ecf20Sopenharmony_ci	u8 tmp_div;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
3948c2ecf20Sopenharmony_ci		 rate, parent_rate);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (!rate)
3978c2ecf20Sopenharmony_ci		return -EINVAL;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	tmp_div = parent_rate / rate;
4008c2ecf20Sopenharmony_ci	if (tmp_div % 3 == 0) {
4018c2ecf20Sopenharmony_ci		apad_ck->qdaudio = tmp_div / 3;
4028c2ecf20Sopenharmony_ci		apad_ck->div = 3;
4038c2ecf20Sopenharmony_ci	} else {
4048c2ecf20Sopenharmony_ci		apad_ck->qdaudio = tmp_div / 2;
4058c2ecf20Sopenharmony_ci		apad_ck->div = 2;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic int clk_audio_pll_pmc_set_rate(struct clk_hw *hw, unsigned long rate,
4128c2ecf20Sopenharmony_ci				      unsigned long parent_rate)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (!rate)
4178c2ecf20Sopenharmony_ci		return -EINVAL;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
4208c2ecf20Sopenharmony_ci		 rate, parent_rate);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	apmc_ck->qdpmc = parent_rate / rate - 1;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	return 0;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic const struct clk_ops audio_pll_frac_ops = {
4288c2ecf20Sopenharmony_ci	.enable = clk_audio_pll_frac_enable,
4298c2ecf20Sopenharmony_ci	.disable = clk_audio_pll_frac_disable,
4308c2ecf20Sopenharmony_ci	.recalc_rate = clk_audio_pll_frac_recalc_rate,
4318c2ecf20Sopenharmony_ci	.determine_rate = clk_audio_pll_frac_determine_rate,
4328c2ecf20Sopenharmony_ci	.set_rate = clk_audio_pll_frac_set_rate,
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic const struct clk_ops audio_pll_pad_ops = {
4368c2ecf20Sopenharmony_ci	.enable = clk_audio_pll_pad_enable,
4378c2ecf20Sopenharmony_ci	.disable = clk_audio_pll_pad_disable,
4388c2ecf20Sopenharmony_ci	.recalc_rate = clk_audio_pll_pad_recalc_rate,
4398c2ecf20Sopenharmony_ci	.round_rate = clk_audio_pll_pad_round_rate,
4408c2ecf20Sopenharmony_ci	.set_rate = clk_audio_pll_pad_set_rate,
4418c2ecf20Sopenharmony_ci};
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic const struct clk_ops audio_pll_pmc_ops = {
4448c2ecf20Sopenharmony_ci	.enable = clk_audio_pll_pmc_enable,
4458c2ecf20Sopenharmony_ci	.disable = clk_audio_pll_pmc_disable,
4468c2ecf20Sopenharmony_ci	.recalc_rate = clk_audio_pll_pmc_recalc_rate,
4478c2ecf20Sopenharmony_ci	.round_rate = clk_audio_pll_pmc_round_rate,
4488c2ecf20Sopenharmony_ci	.set_rate = clk_audio_pll_pmc_set_rate,
4498c2ecf20Sopenharmony_ci};
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistruct clk_hw * __init
4528c2ecf20Sopenharmony_ciat91_clk_register_audio_pll_frac(struct regmap *regmap, const char *name,
4538c2ecf20Sopenharmony_ci				 const char *parent_name)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct clk_audio_frac *frac_ck;
4568c2ecf20Sopenharmony_ci	struct clk_init_data init = {};
4578c2ecf20Sopenharmony_ci	int ret;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	frac_ck = kzalloc(sizeof(*frac_ck), GFP_KERNEL);
4608c2ecf20Sopenharmony_ci	if (!frac_ck)
4618c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	init.name = name;
4648c2ecf20Sopenharmony_ci	init.ops = &audio_pll_frac_ops;
4658c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
4668c2ecf20Sopenharmony_ci	init.num_parents = 1;
4678c2ecf20Sopenharmony_ci	init.flags = CLK_SET_RATE_GATE;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	frac_ck->hw.init = &init;
4708c2ecf20Sopenharmony_ci	frac_ck->regmap = regmap;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &frac_ck->hw);
4738c2ecf20Sopenharmony_ci	if (ret) {
4748c2ecf20Sopenharmony_ci		kfree(frac_ck);
4758c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	return &frac_ck->hw;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistruct clk_hw * __init
4828c2ecf20Sopenharmony_ciat91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name,
4838c2ecf20Sopenharmony_ci				const char *parent_name)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct clk_audio_pad *apad_ck;
4868c2ecf20Sopenharmony_ci	struct clk_init_data init;
4878c2ecf20Sopenharmony_ci	int ret;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL);
4908c2ecf20Sopenharmony_ci	if (!apad_ck)
4918c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	init.name = name;
4948c2ecf20Sopenharmony_ci	init.ops = &audio_pll_pad_ops;
4958c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
4968c2ecf20Sopenharmony_ci	init.num_parents = 1;
4978c2ecf20Sopenharmony_ci	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
4988c2ecf20Sopenharmony_ci		CLK_SET_RATE_PARENT;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	apad_ck->hw.init = &init;
5018c2ecf20Sopenharmony_ci	apad_ck->regmap = regmap;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &apad_ck->hw);
5048c2ecf20Sopenharmony_ci	if (ret) {
5058c2ecf20Sopenharmony_ci		kfree(apad_ck);
5068c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	return &apad_ck->hw;
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistruct clk_hw * __init
5138c2ecf20Sopenharmony_ciat91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name,
5148c2ecf20Sopenharmony_ci				const char *parent_name)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct clk_audio_pmc *apmc_ck;
5178c2ecf20Sopenharmony_ci	struct clk_init_data init;
5188c2ecf20Sopenharmony_ci	int ret;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL);
5218c2ecf20Sopenharmony_ci	if (!apmc_ck)
5228c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	init.name = name;
5258c2ecf20Sopenharmony_ci	init.ops = &audio_pll_pmc_ops;
5268c2ecf20Sopenharmony_ci	init.parent_names = &parent_name;
5278c2ecf20Sopenharmony_ci	init.num_parents = 1;
5288c2ecf20Sopenharmony_ci	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
5298c2ecf20Sopenharmony_ci		CLK_SET_RATE_PARENT;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	apmc_ck->hw.init = &init;
5328c2ecf20Sopenharmony_ci	apmc_ck->regmap = regmap;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	ret = clk_hw_register(NULL, &apmc_ck->hw);
5358c2ecf20Sopenharmony_ci	if (ret) {
5368c2ecf20Sopenharmony_ci		kfree(apmc_ck);
5378c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	return &apmc_ck->hw;
5418c2ecf20Sopenharmony_ci}
542