162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2023 Nuvoton Technology Corp.
462306a36Sopenharmony_ci * Author: Chi-Fang Li <cfli0@nuvoton.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/bitfield.h>
862306a36Sopenharmony_ci#include <linux/clk-provider.h>
962306a36Sopenharmony_ci#include <linux/container_of.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/math64.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/units.h>
1662306a36Sopenharmony_ci#include <dt-bindings/clock/nuvoton,ma35d1-clk.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "clk-ma35d1.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* PLL frequency limits */
2162306a36Sopenharmony_ci#define PLL_FREF_MAX_FREQ	(200 * HZ_PER_MHZ)
2262306a36Sopenharmony_ci#define PLL_FREF_MIN_FREQ	(1 * HZ_PER_MHZ)
2362306a36Sopenharmony_ci#define PLL_FREF_M_MAX_FREQ	(40 * HZ_PER_MHZ)
2462306a36Sopenharmony_ci#define PLL_FREF_M_MIN_FREQ	(10 * HZ_PER_MHZ)
2562306a36Sopenharmony_ci#define PLL_FCLK_MAX_FREQ	(2400 * HZ_PER_MHZ)
2662306a36Sopenharmony_ci#define PLL_FCLK_MIN_FREQ	(600 * HZ_PER_MHZ)
2762306a36Sopenharmony_ci#define PLL_FCLKO_MAX_FREQ	(2400 * HZ_PER_MHZ)
2862306a36Sopenharmony_ci#define PLL_FCLKO_MIN_FREQ	(85700 * HZ_PER_KHZ)
2962306a36Sopenharmony_ci#define PLL_SS_RATE		0x77
3062306a36Sopenharmony_ci#define PLL_SLOPE		0x58CFA
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define REG_PLL_CTL0_OFFSET	0x0
3362306a36Sopenharmony_ci#define REG_PLL_CTL1_OFFSET	0x4
3462306a36Sopenharmony_ci#define REG_PLL_CTL2_OFFSET	0x8
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* bit fields for REG_CLK_PLL0CTL0, which is SMIC PLL design */
3762306a36Sopenharmony_ci#define SPLL0_CTL0_FBDIV	GENMASK(7, 0)
3862306a36Sopenharmony_ci#define SPLL0_CTL0_INDIV	GENMASK(11, 8)
3962306a36Sopenharmony_ci#define SPLL0_CTL0_OUTDIV	GENMASK(13, 12)
4062306a36Sopenharmony_ci#define SPLL0_CTL0_PD		BIT(16)
4162306a36Sopenharmony_ci#define SPLL0_CTL0_BP		BIT(17)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* bit fields for REG_CLK_PLLxCTL0 ~ REG_CLK_PLLxCTL2, where x = 2 ~ 5 */
4462306a36Sopenharmony_ci#define PLL_CTL0_FBDIV		GENMASK(10, 0)
4562306a36Sopenharmony_ci#define PLL_CTL0_INDIV		GENMASK(17, 12)
4662306a36Sopenharmony_ci#define PLL_CTL0_MODE		GENMASK(19, 18)
4762306a36Sopenharmony_ci#define PLL_CTL0_SSRATE		GENMASK(30, 20)
4862306a36Sopenharmony_ci#define PLL_CTL1_PD		BIT(0)
4962306a36Sopenharmony_ci#define PLL_CTL1_BP		BIT(1)
5062306a36Sopenharmony_ci#define PLL_CTL1_OUTDIV		GENMASK(6, 4)
5162306a36Sopenharmony_ci#define PLL_CTL1_FRAC		GENMASK(31, 24)
5262306a36Sopenharmony_ci#define PLL_CTL2_SLOPE		GENMASK(23, 0)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define INDIV_MIN		1
5562306a36Sopenharmony_ci#define INDIV_MAX		63
5662306a36Sopenharmony_ci#define FBDIV_MIN		16
5762306a36Sopenharmony_ci#define FBDIV_MAX		2047
5862306a36Sopenharmony_ci#define FBDIV_FRAC_MIN		1600
5962306a36Sopenharmony_ci#define FBDIV_FRAC_MAX		204700
6062306a36Sopenharmony_ci#define OUTDIV_MIN		1
6162306a36Sopenharmony_ci#define OUTDIV_MAX		7
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define PLL_MODE_INT            0
6462306a36Sopenharmony_ci#define PLL_MODE_FRAC           1
6562306a36Sopenharmony_ci#define PLL_MODE_SS             2
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct ma35d1_clk_pll {
6862306a36Sopenharmony_ci	struct clk_hw hw;
6962306a36Sopenharmony_ci	u32 id;
7062306a36Sopenharmony_ci	u8 mode;
7162306a36Sopenharmony_ci	void __iomem *ctl0_base;
7262306a36Sopenharmony_ci	void __iomem *ctl1_base;
7362306a36Sopenharmony_ci	void __iomem *ctl2_base;
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic inline struct ma35d1_clk_pll *to_ma35d1_clk_pll(struct clk_hw *_hw)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	return container_of(_hw, struct ma35d1_clk_pll, hw);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic unsigned long ma35d1_calc_smic_pll_freq(u32 pll0_ctl0,
8262306a36Sopenharmony_ci					       unsigned long parent_rate)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	u32 m, n, p, outdiv;
8562306a36Sopenharmony_ci	u64 pll_freq;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (pll0_ctl0 & SPLL0_CTL0_BP)
8862306a36Sopenharmony_ci		return parent_rate;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	n = FIELD_GET(SPLL0_CTL0_FBDIV, pll0_ctl0);
9162306a36Sopenharmony_ci	m = FIELD_GET(SPLL0_CTL0_INDIV, pll0_ctl0);
9262306a36Sopenharmony_ci	p = FIELD_GET(SPLL0_CTL0_OUTDIV, pll0_ctl0);
9362306a36Sopenharmony_ci	outdiv = 1 << p;
9462306a36Sopenharmony_ci	pll_freq = (u64)parent_rate * n;
9562306a36Sopenharmony_ci	div_u64(pll_freq, m * outdiv);
9662306a36Sopenharmony_ci	return pll_freq;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long parent_rate)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	unsigned long pll_freq, x;
10262306a36Sopenharmony_ci	u32 m, n, p;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (reg_ctl[1] & PLL_CTL1_BP)
10562306a36Sopenharmony_ci		return parent_rate;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	n = FIELD_GET(PLL_CTL0_FBDIV, reg_ctl[0]);
10862306a36Sopenharmony_ci	m = FIELD_GET(PLL_CTL0_INDIV, reg_ctl[0]);
10962306a36Sopenharmony_ci	p = FIELD_GET(PLL_CTL1_OUTDIV, reg_ctl[1]);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (mode == PLL_MODE_INT) {
11262306a36Sopenharmony_ci		pll_freq = (u64)parent_rate * n;
11362306a36Sopenharmony_ci		div_u64(pll_freq, m * p);
11462306a36Sopenharmony_ci	} else {
11562306a36Sopenharmony_ci		x = FIELD_GET(PLL_CTL1_FRAC, reg_ctl[1]);
11662306a36Sopenharmony_ci		/* 2 decimal places floating to integer (ex. 1.23 to 123) */
11762306a36Sopenharmony_ci		n = n * 100 + ((x * 100) / FIELD_MAX(PLL_CTL1_FRAC));
11862306a36Sopenharmony_ci		pll_freq = div_u64(parent_rate * n, 100 * m * p);
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci	return pll_freq;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int ma35d1_pll_find_closest(struct ma35d1_clk_pll *pll, unsigned long rate,
12462306a36Sopenharmony_ci				   unsigned long parent_rate, u32 *reg_ctl,
12562306a36Sopenharmony_ci				   unsigned long *freq)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	unsigned long min_diff = ULONG_MAX;
12862306a36Sopenharmony_ci	int fbdiv_min, fbdiv_max;
12962306a36Sopenharmony_ci	int p, m, n;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	*freq = 0;
13262306a36Sopenharmony_ci	if (rate < PLL_FCLKO_MIN_FREQ || rate > PLL_FCLKO_MAX_FREQ)
13362306a36Sopenharmony_ci		return -EINVAL;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (pll->mode == PLL_MODE_INT) {
13662306a36Sopenharmony_ci		fbdiv_min = FBDIV_MIN;
13762306a36Sopenharmony_ci		fbdiv_max = FBDIV_MAX;
13862306a36Sopenharmony_ci	} else {
13962306a36Sopenharmony_ci		fbdiv_min = FBDIV_FRAC_MIN;
14062306a36Sopenharmony_ci		fbdiv_max = FBDIV_FRAC_MAX;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	for (m = INDIV_MIN; m <= INDIV_MAX; m++) {
14462306a36Sopenharmony_ci		for (n = fbdiv_min; n <= fbdiv_max; n++) {
14562306a36Sopenharmony_ci			for (p = OUTDIV_MIN; p <= OUTDIV_MAX; p++) {
14662306a36Sopenharmony_ci				unsigned long tmp, fout, fclk, diff;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci				tmp = div_u64(parent_rate, m);
14962306a36Sopenharmony_ci				if (tmp < PLL_FREF_M_MIN_FREQ ||
15062306a36Sopenharmony_ci				    tmp > PLL_FREF_M_MAX_FREQ)
15162306a36Sopenharmony_ci					continue; /* constrain */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci				fclk = div_u64(parent_rate * n, m);
15462306a36Sopenharmony_ci				/* for 2 decimal places */
15562306a36Sopenharmony_ci				if (pll->mode != PLL_MODE_INT)
15662306a36Sopenharmony_ci					fclk = div_u64(fclk, 100);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci				if (fclk < PLL_FCLK_MIN_FREQ ||
15962306a36Sopenharmony_ci				    fclk > PLL_FCLK_MAX_FREQ)
16062306a36Sopenharmony_ci					continue; /* constrain */
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci				fout = div_u64(fclk, p);
16362306a36Sopenharmony_ci				if (fout < PLL_FCLKO_MIN_FREQ ||
16462306a36Sopenharmony_ci				    fout > PLL_FCLKO_MAX_FREQ)
16562306a36Sopenharmony_ci					continue; /* constrain */
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci				diff = abs(rate - fout);
16862306a36Sopenharmony_ci				if (diff < min_diff) {
16962306a36Sopenharmony_ci					reg_ctl[0] = FIELD_PREP(PLL_CTL0_INDIV, m) |
17062306a36Sopenharmony_ci						     FIELD_PREP(PLL_CTL0_FBDIV, n);
17162306a36Sopenharmony_ci					reg_ctl[1] = FIELD_PREP(PLL_CTL1_OUTDIV, p);
17262306a36Sopenharmony_ci					*freq = fout;
17362306a36Sopenharmony_ci					min_diff = diff;
17462306a36Sopenharmony_ci					if (min_diff == 0)
17562306a36Sopenharmony_ci						break;
17662306a36Sopenharmony_ci				}
17762306a36Sopenharmony_ci			}
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci	if (*freq == 0)
18162306a36Sopenharmony_ci		return -EINVAL; /* cannot find even one valid setting */
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic int ma35d1_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
18662306a36Sopenharmony_ci				   unsigned long parent_rate)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
18962306a36Sopenharmony_ci	u32 reg_ctl[3] = { 0 };
19062306a36Sopenharmony_ci	unsigned long pll_freq;
19162306a36Sopenharmony_ci	int ret;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (parent_rate < PLL_FREF_MIN_FREQ || parent_rate > PLL_FREF_MAX_FREQ)
19462306a36Sopenharmony_ci		return -EINVAL;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	ret = ma35d1_pll_find_closest(pll, rate, parent_rate, reg_ctl, &pll_freq);
19762306a36Sopenharmony_ci	if (ret != 0)
19862306a36Sopenharmony_ci		return ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	switch (pll->mode) {
20162306a36Sopenharmony_ci	case PLL_MODE_INT:
20262306a36Sopenharmony_ci		reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_INT);
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	case PLL_MODE_FRAC:
20562306a36Sopenharmony_ci		reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_FRAC);
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	case PLL_MODE_SS:
20862306a36Sopenharmony_ci		reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_SS) |
20962306a36Sopenharmony_ci			      FIELD_PREP(PLL_CTL0_SSRATE, PLL_SS_RATE);
21062306a36Sopenharmony_ci		reg_ctl[2] = FIELD_PREP(PLL_CTL2_SLOPE, PLL_SLOPE);
21162306a36Sopenharmony_ci		break;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci	reg_ctl[1] |= PLL_CTL1_PD;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	writel_relaxed(reg_ctl[0], pll->ctl0_base);
21662306a36Sopenharmony_ci	writel_relaxed(reg_ctl[1], pll->ctl1_base);
21762306a36Sopenharmony_ci	writel_relaxed(reg_ctl[2], pll->ctl2_base);
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic unsigned long ma35d1_clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
22462306a36Sopenharmony_ci	u32 reg_ctl[3];
22562306a36Sopenharmony_ci	unsigned long pll_freq;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (parent_rate < PLL_FREF_MIN_FREQ || parent_rate > PLL_FREF_MAX_FREQ)
22862306a36Sopenharmony_ci		return 0;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	switch (pll->id) {
23162306a36Sopenharmony_ci	case CAPLL:
23262306a36Sopenharmony_ci		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
23362306a36Sopenharmony_ci		pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], parent_rate);
23462306a36Sopenharmony_ci		return pll_freq;
23562306a36Sopenharmony_ci	case DDRPLL:
23662306a36Sopenharmony_ci	case APLL:
23762306a36Sopenharmony_ci	case EPLL:
23862306a36Sopenharmony_ci	case VPLL:
23962306a36Sopenharmony_ci		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
24062306a36Sopenharmony_ci		reg_ctl[1] = readl_relaxed(pll->ctl1_base);
24162306a36Sopenharmony_ci		pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, parent_rate);
24262306a36Sopenharmony_ci		return pll_freq;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic long ma35d1_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
24862306a36Sopenharmony_ci				      unsigned long *parent_rate)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
25162306a36Sopenharmony_ci	u32 reg_ctl[3] = { 0 };
25262306a36Sopenharmony_ci	unsigned long pll_freq;
25362306a36Sopenharmony_ci	long ret;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (*parent_rate < PLL_FREF_MIN_FREQ || *parent_rate > PLL_FREF_MAX_FREQ)
25662306a36Sopenharmony_ci		return -EINVAL;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	ret = ma35d1_pll_find_closest(pll, rate, *parent_rate, reg_ctl, &pll_freq);
25962306a36Sopenharmony_ci	if (ret < 0)
26062306a36Sopenharmony_ci		return ret;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	switch (pll->id) {
26362306a36Sopenharmony_ci	case CAPLL:
26462306a36Sopenharmony_ci		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
26562306a36Sopenharmony_ci		pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], *parent_rate);
26662306a36Sopenharmony_ci		return pll_freq;
26762306a36Sopenharmony_ci	case DDRPLL:
26862306a36Sopenharmony_ci	case APLL:
26962306a36Sopenharmony_ci	case EPLL:
27062306a36Sopenharmony_ci	case VPLL:
27162306a36Sopenharmony_ci		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
27262306a36Sopenharmony_ci		reg_ctl[1] = readl_relaxed(pll->ctl1_base);
27362306a36Sopenharmony_ci		pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, *parent_rate);
27462306a36Sopenharmony_ci		return pll_freq;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci	return 0;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int ma35d1_clk_pll_is_prepared(struct clk_hw *hw)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
28262306a36Sopenharmony_ci	u32 val = readl_relaxed(pll->ctl1_base);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return !(val & PLL_CTL1_PD);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic int ma35d1_clk_pll_prepare(struct clk_hw *hw)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
29062306a36Sopenharmony_ci	u32 val;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	val = readl_relaxed(pll->ctl1_base);
29362306a36Sopenharmony_ci	val &= ~PLL_CTL1_PD;
29462306a36Sopenharmony_ci	writel_relaxed(val, pll->ctl1_base);
29562306a36Sopenharmony_ci	return 0;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic void ma35d1_clk_pll_unprepare(struct clk_hw *hw)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
30162306a36Sopenharmony_ci	u32 val;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	val = readl_relaxed(pll->ctl1_base);
30462306a36Sopenharmony_ci	val |= PLL_CTL1_PD;
30562306a36Sopenharmony_ci	writel_relaxed(val, pll->ctl1_base);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic const struct clk_ops ma35d1_clk_pll_ops = {
30962306a36Sopenharmony_ci	.is_prepared = ma35d1_clk_pll_is_prepared,
31062306a36Sopenharmony_ci	.prepare = ma35d1_clk_pll_prepare,
31162306a36Sopenharmony_ci	.unprepare = ma35d1_clk_pll_unprepare,
31262306a36Sopenharmony_ci	.set_rate = ma35d1_clk_pll_set_rate,
31362306a36Sopenharmony_ci	.recalc_rate = ma35d1_clk_pll_recalc_rate,
31462306a36Sopenharmony_ci	.round_rate = ma35d1_clk_pll_round_rate,
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic const struct clk_ops ma35d1_clk_fixed_pll_ops = {
31862306a36Sopenharmony_ci	.recalc_rate = ma35d1_clk_pll_recalc_rate,
31962306a36Sopenharmony_ci	.round_rate = ma35d1_clk_pll_round_rate,
32062306a36Sopenharmony_ci};
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistruct clk_hw *ma35d1_reg_clk_pll(struct device *dev, u32 id, u8 u8mode, const char *name,
32362306a36Sopenharmony_ci				  struct clk_hw *parent_hw, void __iomem *base)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct clk_parent_data pdata = { .index = 0 };
32662306a36Sopenharmony_ci	struct clk_init_data init = {};
32762306a36Sopenharmony_ci	struct ma35d1_clk_pll *pll;
32862306a36Sopenharmony_ci	struct clk_hw *hw;
32962306a36Sopenharmony_ci	int ret;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
33262306a36Sopenharmony_ci	if (!pll)
33362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	pll->id = id;
33662306a36Sopenharmony_ci	pll->mode = u8mode;
33762306a36Sopenharmony_ci	pll->ctl0_base = base + REG_PLL_CTL0_OFFSET;
33862306a36Sopenharmony_ci	pll->ctl1_base = base + REG_PLL_CTL1_OFFSET;
33962306a36Sopenharmony_ci	pll->ctl2_base = base + REG_PLL_CTL2_OFFSET;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	init.name = name;
34262306a36Sopenharmony_ci	init.flags = 0;
34362306a36Sopenharmony_ci	pdata.hw = parent_hw;
34462306a36Sopenharmony_ci	init.parent_data = &pdata;
34562306a36Sopenharmony_ci	init.num_parents = 1;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (id == CAPLL || id == DDRPLL)
34862306a36Sopenharmony_ci		init.ops = &ma35d1_clk_fixed_pll_ops;
34962306a36Sopenharmony_ci	else
35062306a36Sopenharmony_ci		init.ops = &ma35d1_clk_pll_ops;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	pll->hw.init = &init;
35362306a36Sopenharmony_ci	hw = &pll->hw;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	ret = devm_clk_hw_register(dev, hw);
35662306a36Sopenharmony_ci	if (ret)
35762306a36Sopenharmony_ci		return ERR_PTR(ret);
35862306a36Sopenharmony_ci	return hw;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ma35d1_reg_clk_pll);
361