162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * MTMIPS SoCs Clock Driver
462306a36Sopenharmony_ci * Author: Sergio Paracuellos <sergio.paracuellos@gmail.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/bitops.h>
862306a36Sopenharmony_ci#include <linux/clk-provider.h>
962306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <linux/regmap.h>
1262306a36Sopenharmony_ci#include <linux/reset-controller.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Configuration registers */
1662306a36Sopenharmony_ci#define SYSC_REG_SYSTEM_CONFIG		0x10
1762306a36Sopenharmony_ci#define SYSC_REG_CLKCFG0		0x2c
1862306a36Sopenharmony_ci#define SYSC_REG_RESET_CTRL		0x34
1962306a36Sopenharmony_ci#define SYSC_REG_CPU_SYS_CLKCFG		0x3c
2062306a36Sopenharmony_ci#define SYSC_REG_CPLL_CONFIG0		0x54
2162306a36Sopenharmony_ci#define SYSC_REG_CPLL_CONFIG1		0x58
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* RT2880 SoC */
2462306a36Sopenharmony_ci#define RT2880_CONFIG_CPUCLK_SHIFT	20
2562306a36Sopenharmony_ci#define RT2880_CONFIG_CPUCLK_MASK	0x3
2662306a36Sopenharmony_ci#define RT2880_CONFIG_CPUCLK_250	0x0
2762306a36Sopenharmony_ci#define RT2880_CONFIG_CPUCLK_266	0x1
2862306a36Sopenharmony_ci#define RT2880_CONFIG_CPUCLK_280	0x2
2962306a36Sopenharmony_ci#define RT2880_CONFIG_CPUCLK_300	0x3
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* RT305X SoC */
3262306a36Sopenharmony_ci#define RT305X_SYSCFG_CPUCLK_SHIFT	18
3362306a36Sopenharmony_ci#define RT305X_SYSCFG_CPUCLK_MASK	0x1
3462306a36Sopenharmony_ci#define RT305X_SYSCFG_CPUCLK_LOW	0x0
3562306a36Sopenharmony_ci#define RT305X_SYSCFG_CPUCLK_HIGH	0x1
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* RT3352 SoC */
3862306a36Sopenharmony_ci#define RT3352_SYSCFG0_CPUCLK_SHIFT	8
3962306a36Sopenharmony_ci#define RT3352_SYSCFG0_CPUCLK_MASK	0x1
4062306a36Sopenharmony_ci#define RT3352_SYSCFG0_CPUCLK_LOW	0x0
4162306a36Sopenharmony_ci#define RT3352_SYSCFG0_CPUCLK_HIGH	0x1
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* RT3383 SoC */
4462306a36Sopenharmony_ci#define RT3883_SYSCFG0_DRAM_TYPE_DDR2	BIT(17)
4562306a36Sopenharmony_ci#define RT3883_SYSCFG0_CPUCLK_SHIFT	8
4662306a36Sopenharmony_ci#define RT3883_SYSCFG0_CPUCLK_MASK	0x3
4762306a36Sopenharmony_ci#define RT3883_SYSCFG0_CPUCLK_250	0x0
4862306a36Sopenharmony_ci#define RT3883_SYSCFG0_CPUCLK_384	0x1
4962306a36Sopenharmony_ci#define RT3883_SYSCFG0_CPUCLK_480	0x2
5062306a36Sopenharmony_ci#define RT3883_SYSCFG0_CPUCLK_500	0x3
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* RT5350 SoC */
5362306a36Sopenharmony_ci#define RT5350_CLKCFG0_XTAL_SEL		BIT(20)
5462306a36Sopenharmony_ci#define RT5350_SYSCFG0_CPUCLK_SHIFT	8
5562306a36Sopenharmony_ci#define RT5350_SYSCFG0_CPUCLK_MASK	0x3
5662306a36Sopenharmony_ci#define RT5350_SYSCFG0_CPUCLK_360	0x0
5762306a36Sopenharmony_ci#define RT5350_SYSCFG0_CPUCLK_320	0x2
5862306a36Sopenharmony_ci#define RT5350_SYSCFG0_CPUCLK_300	0x3
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* MT7620 and MT76x8 SoCs */
6162306a36Sopenharmony_ci#define MT7620_XTAL_FREQ_SEL		BIT(6)
6262306a36Sopenharmony_ci#define CPLL_CFG0_SW_CFG		BIT(31)
6362306a36Sopenharmony_ci#define CPLL_CFG0_PLL_MULT_RATIO_SHIFT	16
6462306a36Sopenharmony_ci#define CPLL_CFG0_PLL_MULT_RATIO_MASK   0x7
6562306a36Sopenharmony_ci#define CPLL_CFG0_LC_CURFCK		BIT(15)
6662306a36Sopenharmony_ci#define CPLL_CFG0_BYPASS_REF_CLK	BIT(14)
6762306a36Sopenharmony_ci#define CPLL_CFG0_PLL_DIV_RATIO_SHIFT	10
6862306a36Sopenharmony_ci#define CPLL_CFG0_PLL_DIV_RATIO_MASK	0x3
6962306a36Sopenharmony_ci#define CPLL_CFG1_CPU_AUX1		BIT(25)
7062306a36Sopenharmony_ci#define CPLL_CFG1_CPU_AUX0		BIT(24)
7162306a36Sopenharmony_ci#define CLKCFG0_PERI_CLK_SEL		BIT(4)
7262306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_SHIFT	16
7362306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_MASK	0xf
7462306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_1	0	/* 1:1   (Reserved) */
7562306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_1_5	1	/* 1:1.5 (Reserved) */
7662306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_2	2	/* 1:2   */
7762306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_2_5	3       /* 1:2.5 (Reserved) */
7862306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_3	4	/* 1:3   */
7962306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_3_5	5	/* 1:3.5 (Reserved) */
8062306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_4	6	/* 1:4   */
8162306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_5	7	/* 1:5   */
8262306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_OCP_RATIO_10	8	/* 1:10  */
8362306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_CPU_FDIV_SHIFT	8
8462306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_CPU_FDIV_MASK	0x1f
8562306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_CPU_FFRAC_SHIFT	0
8662306a36Sopenharmony_ci#define CPU_SYS_CLKCFG_CPU_FFRAC_MASK	0x1f
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* clock scaling */
8962306a36Sopenharmony_ci#define CLKCFG_FDIV_MASK		0x1f00
9062306a36Sopenharmony_ci#define CLKCFG_FDIV_USB_VAL		0x0300
9162306a36Sopenharmony_ci#define CLKCFG_FFRAC_MASK		0x001f
9262306a36Sopenharmony_ci#define CLKCFG_FFRAC_USB_VAL		0x0003
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct mtmips_clk;
9562306a36Sopenharmony_cistruct mtmips_clk_fixed;
9662306a36Sopenharmony_cistruct mtmips_clk_factor;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistruct mtmips_clk_data {
9962306a36Sopenharmony_ci	struct mtmips_clk *clk_base;
10062306a36Sopenharmony_ci	size_t num_clk_base;
10162306a36Sopenharmony_ci	struct mtmips_clk_fixed *clk_fixed;
10262306a36Sopenharmony_ci	size_t num_clk_fixed;
10362306a36Sopenharmony_ci	struct mtmips_clk_factor *clk_factor;
10462306a36Sopenharmony_ci	size_t num_clk_factor;
10562306a36Sopenharmony_ci	struct mtmips_clk *clk_periph;
10662306a36Sopenharmony_ci	size_t num_clk_periph;
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistruct mtmips_clk_priv {
11062306a36Sopenharmony_ci	struct regmap *sysc;
11162306a36Sopenharmony_ci	const struct mtmips_clk_data *data;
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistruct mtmips_clk {
11562306a36Sopenharmony_ci	struct clk_hw hw;
11662306a36Sopenharmony_ci	struct mtmips_clk_priv *priv;
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistruct mtmips_clk_fixed {
12062306a36Sopenharmony_ci	const char *name;
12162306a36Sopenharmony_ci	const char *parent;
12262306a36Sopenharmony_ci	unsigned long rate;
12362306a36Sopenharmony_ci	struct clk_hw *hw;
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistruct mtmips_clk_factor {
12762306a36Sopenharmony_ci	const char *name;
12862306a36Sopenharmony_ci	const char *parent;
12962306a36Sopenharmony_ci	int mult;
13062306a36Sopenharmony_ci	int div;
13162306a36Sopenharmony_ci	unsigned long flags;
13262306a36Sopenharmony_ci	struct clk_hw *hw;
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic unsigned long mtmips_pherip_clk_rate(struct clk_hw *hw,
13662306a36Sopenharmony_ci					    unsigned long parent_rate)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	return parent_rate;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic const struct clk_ops mtmips_periph_clk_ops = {
14262306a36Sopenharmony_ci	.recalc_rate = mtmips_pherip_clk_rate,
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define CLK_PERIPH(_name, _parent) {				\
14662306a36Sopenharmony_ci	.init = &(const struct clk_init_data) {			\
14762306a36Sopenharmony_ci		.name = _name,					\
14862306a36Sopenharmony_ci		.ops = &mtmips_periph_clk_ops,			\
14962306a36Sopenharmony_ci		.parent_data = &(const struct clk_parent_data) {\
15062306a36Sopenharmony_ci			.name = _parent,			\
15162306a36Sopenharmony_ci			.fw_name = _parent			\
15262306a36Sopenharmony_ci		},						\
15362306a36Sopenharmony_ci		.num_parents = 1,				\
15462306a36Sopenharmony_ci		/*						\
15562306a36Sopenharmony_ci		 * There are drivers for these SoCs that are	\
15662306a36Sopenharmony_ci		 * older than clock driver and are not prepared \
15762306a36Sopenharmony_ci		 * for the clock. We don't want the kernel to   \
15862306a36Sopenharmony_ci		 * disable anything so we add CLK_IS_CRITICAL	\
15962306a36Sopenharmony_ci		 * flag here.					\
16062306a36Sopenharmony_ci		 */						\
16162306a36Sopenharmony_ci		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL	\
16262306a36Sopenharmony_ci	},							\
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic struct mtmips_clk rt2880_pherip_clks[] = {
16662306a36Sopenharmony_ci	{ CLK_PERIPH("300100.timer", "bus") },
16762306a36Sopenharmony_ci	{ CLK_PERIPH("300120.watchdog", "bus") },
16862306a36Sopenharmony_ci	{ CLK_PERIPH("300500.uart", "bus") },
16962306a36Sopenharmony_ci	{ CLK_PERIPH("300900.i2c", "bus") },
17062306a36Sopenharmony_ci	{ CLK_PERIPH("300c00.uartlite", "bus") },
17162306a36Sopenharmony_ci	{ CLK_PERIPH("400000.ethernet", "bus") },
17262306a36Sopenharmony_ci	{ CLK_PERIPH("480000.wmac", "xtal") }
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic struct mtmips_clk rt305x_pherip_clks[] = {
17662306a36Sopenharmony_ci	{ CLK_PERIPH("10000100.timer", "bus") },
17762306a36Sopenharmony_ci	{ CLK_PERIPH("10000120.watchdog", "bus") },
17862306a36Sopenharmony_ci	{ CLK_PERIPH("10000500.uart", "bus") },
17962306a36Sopenharmony_ci	{ CLK_PERIPH("10000900.i2c", "bus") },
18062306a36Sopenharmony_ci	{ CLK_PERIPH("10000a00.i2s", "bus") },
18162306a36Sopenharmony_ci	{ CLK_PERIPH("10000b00.spi", "bus") },
18262306a36Sopenharmony_ci	{ CLK_PERIPH("10000b40.spi", "bus") },
18362306a36Sopenharmony_ci	{ CLK_PERIPH("10000c00.uartlite", "bus") },
18462306a36Sopenharmony_ci	{ CLK_PERIPH("10100000.ethernet", "bus") },
18562306a36Sopenharmony_ci	{ CLK_PERIPH("10180000.wmac", "xtal") }
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic struct mtmips_clk rt5350_pherip_clks[] = {
18962306a36Sopenharmony_ci	{ CLK_PERIPH("10000100.timer", "bus") },
19062306a36Sopenharmony_ci	{ CLK_PERIPH("10000120.watchdog", "bus") },
19162306a36Sopenharmony_ci	{ CLK_PERIPH("10000500.uart", "periph") },
19262306a36Sopenharmony_ci	{ CLK_PERIPH("10000900.i2c", "periph") },
19362306a36Sopenharmony_ci	{ CLK_PERIPH("10000a00.i2s", "periph") },
19462306a36Sopenharmony_ci	{ CLK_PERIPH("10000b00.spi", "bus") },
19562306a36Sopenharmony_ci	{ CLK_PERIPH("10000b40.spi", "bus") },
19662306a36Sopenharmony_ci	{ CLK_PERIPH("10000c00.uartlite", "periph") },
19762306a36Sopenharmony_ci	{ CLK_PERIPH("10100000.ethernet", "bus") },
19862306a36Sopenharmony_ci	{ CLK_PERIPH("10180000.wmac", "xtal") }
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic struct mtmips_clk mt7620_pherip_clks[] = {
20262306a36Sopenharmony_ci	{ CLK_PERIPH("10000100.timer", "periph") },
20362306a36Sopenharmony_ci	{ CLK_PERIPH("10000120.watchdog", "periph") },
20462306a36Sopenharmony_ci	{ CLK_PERIPH("10000500.uart", "periph") },
20562306a36Sopenharmony_ci	{ CLK_PERIPH("10000900.i2c", "periph") },
20662306a36Sopenharmony_ci	{ CLK_PERIPH("10000a00.i2s", "periph") },
20762306a36Sopenharmony_ci	{ CLK_PERIPH("10000b00.spi", "bus") },
20862306a36Sopenharmony_ci	{ CLK_PERIPH("10000b40.spi", "bus") },
20962306a36Sopenharmony_ci	{ CLK_PERIPH("10000c00.uartlite", "periph") },
21062306a36Sopenharmony_ci	{ CLK_PERIPH("10180000.wmac", "xtal") }
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic struct mtmips_clk mt76x8_pherip_clks[] = {
21462306a36Sopenharmony_ci	{ CLK_PERIPH("10000100.timer", "periph") },
21562306a36Sopenharmony_ci	{ CLK_PERIPH("10000120.watchdog", "periph") },
21662306a36Sopenharmony_ci	{ CLK_PERIPH("10000900.i2c", "periph") },
21762306a36Sopenharmony_ci	{ CLK_PERIPH("10000a00.i2s", "pcmi2s") },
21862306a36Sopenharmony_ci	{ CLK_PERIPH("10000b00.spi", "bus") },
21962306a36Sopenharmony_ci	{ CLK_PERIPH("10000b40.spi", "bus") },
22062306a36Sopenharmony_ci	{ CLK_PERIPH("10000c00.uart0", "periph") },
22162306a36Sopenharmony_ci	{ CLK_PERIPH("10000d00.uart1", "periph") },
22262306a36Sopenharmony_ci	{ CLK_PERIPH("10000e00.uart2", "periph") },
22362306a36Sopenharmony_ci	{ CLK_PERIPH("10300000.wmac", "xtal") }
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic int mtmips_register_pherip_clocks(struct device_node *np,
22762306a36Sopenharmony_ci					 struct clk_hw_onecell_data *clk_data,
22862306a36Sopenharmony_ci					 struct mtmips_clk_priv *priv)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct clk_hw **hws = clk_data->hws;
23162306a36Sopenharmony_ci	struct mtmips_clk *sclk;
23262306a36Sopenharmony_ci	size_t idx_start = priv->data->num_clk_base + priv->data->num_clk_fixed +
23362306a36Sopenharmony_ci			   priv->data->num_clk_factor;
23462306a36Sopenharmony_ci	int ret, i;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_periph; i++) {
23762306a36Sopenharmony_ci		int idx = idx_start + i;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		sclk = &priv->data->clk_periph[i];
24062306a36Sopenharmony_ci		ret = of_clk_hw_register(np, &sclk->hw);
24162306a36Sopenharmony_ci		if (ret) {
24262306a36Sopenharmony_ci			pr_err("Couldn't register peripheral clock %d\n", idx);
24362306a36Sopenharmony_ci			goto err_clk_unreg;
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		hws[idx] = &sclk->hw;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cierr_clk_unreg:
25262306a36Sopenharmony_ci	while (--i >= 0) {
25362306a36Sopenharmony_ci		sclk = &priv->data->clk_periph[i];
25462306a36Sopenharmony_ci		clk_hw_unregister(&sclk->hw);
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	return ret;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci#define CLK_FIXED(_name, _parent, _rate) \
26062306a36Sopenharmony_ci	{				 \
26162306a36Sopenharmony_ci		.name = _name,		 \
26262306a36Sopenharmony_ci		.parent = _parent,	 \
26362306a36Sopenharmony_ci		.rate = _rate		 \
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic struct mtmips_clk_fixed rt305x_fixed_clocks[] = {
26762306a36Sopenharmony_ci	CLK_FIXED("xtal", NULL, 40000000)
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic struct mtmips_clk_fixed rt3352_fixed_clocks[] = {
27162306a36Sopenharmony_ci	CLK_FIXED("periph", "xtal", 40000000)
27262306a36Sopenharmony_ci};
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic struct mtmips_clk_fixed mt76x8_fixed_clocks[] = {
27562306a36Sopenharmony_ci	CLK_FIXED("pcmi2s", "xtal", 480000000),
27662306a36Sopenharmony_ci	CLK_FIXED("periph", "xtal", 40000000)
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int mtmips_register_fixed_clocks(struct clk_hw_onecell_data *clk_data,
28062306a36Sopenharmony_ci					struct mtmips_clk_priv *priv)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct clk_hw **hws = clk_data->hws;
28362306a36Sopenharmony_ci	struct mtmips_clk_fixed *sclk;
28462306a36Sopenharmony_ci	size_t idx_start = priv->data->num_clk_base;
28562306a36Sopenharmony_ci	int ret, i;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_fixed; i++) {
28862306a36Sopenharmony_ci		int idx = idx_start + i;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		sclk = &priv->data->clk_fixed[i];
29162306a36Sopenharmony_ci		sclk->hw = clk_hw_register_fixed_rate(NULL, sclk->name,
29262306a36Sopenharmony_ci						      sclk->parent, 0,
29362306a36Sopenharmony_ci						      sclk->rate);
29462306a36Sopenharmony_ci		if (IS_ERR(sclk->hw)) {
29562306a36Sopenharmony_ci			ret = PTR_ERR(sclk->hw);
29662306a36Sopenharmony_ci			pr_err("Couldn't register fixed clock %d\n", idx);
29762306a36Sopenharmony_ci			goto err_clk_unreg;
29862306a36Sopenharmony_ci		}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		hws[idx] = sclk->hw;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	return 0;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cierr_clk_unreg:
30662306a36Sopenharmony_ci	while (--i >= 0) {
30762306a36Sopenharmony_ci		sclk = &priv->data->clk_fixed[i];
30862306a36Sopenharmony_ci		clk_hw_unregister_fixed_rate(sclk->hw);
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci	return ret;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci#define CLK_FACTOR(_name, _parent, _mult, _div)		\
31462306a36Sopenharmony_ci	{						\
31562306a36Sopenharmony_ci		.name = _name,				\
31662306a36Sopenharmony_ci		.parent = _parent,			\
31762306a36Sopenharmony_ci		.mult = _mult,				\
31862306a36Sopenharmony_ci		.div = _div,				\
31962306a36Sopenharmony_ci		.flags = CLK_SET_RATE_PARENT		\
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic struct mtmips_clk_factor rt2880_factor_clocks[] = {
32362306a36Sopenharmony_ci	CLK_FACTOR("bus", "cpu", 1, 2)
32462306a36Sopenharmony_ci};
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic struct mtmips_clk_factor rt305x_factor_clocks[] = {
32762306a36Sopenharmony_ci	CLK_FACTOR("bus", "cpu", 1, 3)
32862306a36Sopenharmony_ci};
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic int mtmips_register_factor_clocks(struct clk_hw_onecell_data *clk_data,
33162306a36Sopenharmony_ci					 struct mtmips_clk_priv *priv)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct clk_hw **hws = clk_data->hws;
33462306a36Sopenharmony_ci	struct mtmips_clk_factor *sclk;
33562306a36Sopenharmony_ci	size_t idx_start = priv->data->num_clk_base + priv->data->num_clk_fixed;
33662306a36Sopenharmony_ci	int ret, i;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_factor; i++) {
33962306a36Sopenharmony_ci		int idx = idx_start + i;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		sclk = &priv->data->clk_factor[i];
34262306a36Sopenharmony_ci		sclk->hw = clk_hw_register_fixed_factor(NULL, sclk->name,
34362306a36Sopenharmony_ci						  sclk->parent, sclk->flags,
34462306a36Sopenharmony_ci						  sclk->mult, sclk->div);
34562306a36Sopenharmony_ci		if (IS_ERR(sclk->hw)) {
34662306a36Sopenharmony_ci			ret = PTR_ERR(sclk->hw);
34762306a36Sopenharmony_ci			pr_err("Couldn't register factor clock %d\n", idx);
34862306a36Sopenharmony_ci			goto err_clk_unreg;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		hws[idx] = sclk->hw;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return 0;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cierr_clk_unreg:
35762306a36Sopenharmony_ci	while (--i >= 0) {
35862306a36Sopenharmony_ci		sclk = &priv->data->clk_factor[i];
35962306a36Sopenharmony_ci		clk_hw_unregister_fixed_factor(sclk->hw);
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci	return ret;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic inline struct mtmips_clk *to_mtmips_clk(struct clk_hw *hw)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	return container_of(hw, struct mtmips_clk, hw);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic unsigned long rt5350_xtal_recalc_rate(struct clk_hw *hw,
37062306a36Sopenharmony_ci					     unsigned long parent_rate)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
37362306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
37462306a36Sopenharmony_ci	u32 val;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &val);
37762306a36Sopenharmony_ci	if (!(val & RT5350_CLKCFG0_XTAL_SEL))
37862306a36Sopenharmony_ci		return 20000000;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return 40000000;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic unsigned long rt5350_cpu_recalc_rate(struct clk_hw *hw,
38462306a36Sopenharmony_ci					    unsigned long xtal_clk)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
38762306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
38862306a36Sopenharmony_ci	u32 t;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
39162306a36Sopenharmony_ci	t = (t >> RT5350_SYSCFG0_CPUCLK_SHIFT) & RT5350_SYSCFG0_CPUCLK_MASK;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	switch (t) {
39462306a36Sopenharmony_ci	case RT5350_SYSCFG0_CPUCLK_360:
39562306a36Sopenharmony_ci		return 360000000;
39662306a36Sopenharmony_ci	case RT5350_SYSCFG0_CPUCLK_320:
39762306a36Sopenharmony_ci		return 320000000;
39862306a36Sopenharmony_ci	case RT5350_SYSCFG0_CPUCLK_300:
39962306a36Sopenharmony_ci		return 300000000;
40062306a36Sopenharmony_ci	default:
40162306a36Sopenharmony_ci		BUG();
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic unsigned long rt5350_bus_recalc_rate(struct clk_hw *hw,
40662306a36Sopenharmony_ci					    unsigned long parent_rate)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	if (parent_rate == 320000000)
40962306a36Sopenharmony_ci		return parent_rate / 4;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return parent_rate / 3;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic unsigned long rt3352_cpu_recalc_rate(struct clk_hw *hw,
41562306a36Sopenharmony_ci					    unsigned long xtal_clk)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
41862306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
41962306a36Sopenharmony_ci	u32 t;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
42262306a36Sopenharmony_ci	t = (t >> RT3352_SYSCFG0_CPUCLK_SHIFT) & RT3352_SYSCFG0_CPUCLK_MASK;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	switch (t) {
42562306a36Sopenharmony_ci	case RT3352_SYSCFG0_CPUCLK_LOW:
42662306a36Sopenharmony_ci		return 384000000;
42762306a36Sopenharmony_ci	case RT3352_SYSCFG0_CPUCLK_HIGH:
42862306a36Sopenharmony_ci		return 400000000;
42962306a36Sopenharmony_ci	default:
43062306a36Sopenharmony_ci		BUG();
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic unsigned long rt305x_cpu_recalc_rate(struct clk_hw *hw,
43562306a36Sopenharmony_ci					    unsigned long xtal_clk)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
43862306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
43962306a36Sopenharmony_ci	u32 t;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
44262306a36Sopenharmony_ci	t = (t >> RT305X_SYSCFG_CPUCLK_SHIFT) & RT305X_SYSCFG_CPUCLK_MASK;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	switch (t) {
44562306a36Sopenharmony_ci	case RT305X_SYSCFG_CPUCLK_LOW:
44662306a36Sopenharmony_ci		return 320000000;
44762306a36Sopenharmony_ci	case RT305X_SYSCFG_CPUCLK_HIGH:
44862306a36Sopenharmony_ci		return 384000000;
44962306a36Sopenharmony_ci	default:
45062306a36Sopenharmony_ci		BUG();
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic unsigned long rt3883_cpu_recalc_rate(struct clk_hw *hw,
45562306a36Sopenharmony_ci					    unsigned long xtal_clk)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
45862306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
45962306a36Sopenharmony_ci	u32 t;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
46262306a36Sopenharmony_ci	t = (t >> RT3883_SYSCFG0_CPUCLK_SHIFT) & RT3883_SYSCFG0_CPUCLK_MASK;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	switch (t) {
46562306a36Sopenharmony_ci	case RT3883_SYSCFG0_CPUCLK_250:
46662306a36Sopenharmony_ci		return 250000000;
46762306a36Sopenharmony_ci	case RT3883_SYSCFG0_CPUCLK_384:
46862306a36Sopenharmony_ci		return 384000000;
46962306a36Sopenharmony_ci	case RT3883_SYSCFG0_CPUCLK_480:
47062306a36Sopenharmony_ci		return 480000000;
47162306a36Sopenharmony_ci	case RT3883_SYSCFG0_CPUCLK_500:
47262306a36Sopenharmony_ci		return 500000000;
47362306a36Sopenharmony_ci	default:
47462306a36Sopenharmony_ci		BUG();
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic unsigned long rt3883_bus_recalc_rate(struct clk_hw *hw,
47962306a36Sopenharmony_ci					    unsigned long parent_rate)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
48262306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
48362306a36Sopenharmony_ci	u32 ddr2;
48462306a36Sopenharmony_ci	u32 t;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
48762306a36Sopenharmony_ci	ddr2 = t & RT3883_SYSCFG0_DRAM_TYPE_DDR2;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	switch (parent_rate) {
49062306a36Sopenharmony_ci	case 250000000:
49162306a36Sopenharmony_ci		return (ddr2) ? 125000000 : 83000000;
49262306a36Sopenharmony_ci	case 384000000:
49362306a36Sopenharmony_ci		return (ddr2) ? 128000000 : 96000000;
49462306a36Sopenharmony_ci	case 480000000:
49562306a36Sopenharmony_ci		return (ddr2) ? 160000000 : 120000000;
49662306a36Sopenharmony_ci	case 500000000:
49762306a36Sopenharmony_ci		return (ddr2) ? 166000000 : 125000000;
49862306a36Sopenharmony_ci	default:
49962306a36Sopenharmony_ci		WARN_ON_ONCE(parent_rate == 0);
50062306a36Sopenharmony_ci		return parent_rate / 4;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic unsigned long rt2880_cpu_recalc_rate(struct clk_hw *hw,
50562306a36Sopenharmony_ci					    unsigned long xtal_clk)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
50862306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
50962306a36Sopenharmony_ci	u32 t;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
51262306a36Sopenharmony_ci	t = (t >> RT2880_CONFIG_CPUCLK_SHIFT) & RT2880_CONFIG_CPUCLK_MASK;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	switch (t) {
51562306a36Sopenharmony_ci	case RT2880_CONFIG_CPUCLK_250:
51662306a36Sopenharmony_ci		return 250000000;
51762306a36Sopenharmony_ci	case RT2880_CONFIG_CPUCLK_266:
51862306a36Sopenharmony_ci		return 266000000;
51962306a36Sopenharmony_ci	case RT2880_CONFIG_CPUCLK_280:
52062306a36Sopenharmony_ci		return 280000000;
52162306a36Sopenharmony_ci	case RT2880_CONFIG_CPUCLK_300:
52262306a36Sopenharmony_ci		return 300000000;
52362306a36Sopenharmony_ci	default:
52462306a36Sopenharmony_ci		BUG();
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic u32 mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	u64 t;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	t = ref_rate;
53362306a36Sopenharmony_ci	t *= mul;
53462306a36Sopenharmony_ci	t = div_u64(t, div);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	return t;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic unsigned long mt7620_pll_recalc_rate(struct clk_hw *hw,
54062306a36Sopenharmony_ci					    unsigned long parent_rate)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	static const u32 clk_divider[] = { 2, 3, 4, 8 };
54362306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
54462306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
54562306a36Sopenharmony_ci	unsigned long cpu_pll;
54662306a36Sopenharmony_ci	u32 t;
54762306a36Sopenharmony_ci	u32 mul;
54862306a36Sopenharmony_ci	u32 div;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_CPLL_CONFIG0, &t);
55162306a36Sopenharmony_ci	if (t & CPLL_CFG0_BYPASS_REF_CLK) {
55262306a36Sopenharmony_ci		cpu_pll = parent_rate;
55362306a36Sopenharmony_ci	} else if ((t & CPLL_CFG0_SW_CFG) == 0) {
55462306a36Sopenharmony_ci		cpu_pll = 600000000;
55562306a36Sopenharmony_ci	} else {
55662306a36Sopenharmony_ci		mul = (t >> CPLL_CFG0_PLL_MULT_RATIO_SHIFT) &
55762306a36Sopenharmony_ci			CPLL_CFG0_PLL_MULT_RATIO_MASK;
55862306a36Sopenharmony_ci		mul += 24;
55962306a36Sopenharmony_ci		if (t & CPLL_CFG0_LC_CURFCK)
56062306a36Sopenharmony_ci			mul *= 2;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		div = (t >> CPLL_CFG0_PLL_DIV_RATIO_SHIFT) &
56362306a36Sopenharmony_ci			CPLL_CFG0_PLL_DIV_RATIO_MASK;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		WARN_ON_ONCE(div >= ARRAY_SIZE(clk_divider));
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		cpu_pll = mt7620_calc_rate(parent_rate, mul, clk_divider[div]);
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_CPLL_CONFIG1, &t);
57162306a36Sopenharmony_ci	if (t & CPLL_CFG1_CPU_AUX1)
57262306a36Sopenharmony_ci		return parent_rate;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (t & CPLL_CFG1_CPU_AUX0)
57562306a36Sopenharmony_ci		return 480000000;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	return cpu_pll;
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic unsigned long mt7620_cpu_recalc_rate(struct clk_hw *hw,
58162306a36Sopenharmony_ci					    unsigned long parent_rate)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
58462306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
58562306a36Sopenharmony_ci	u32 t;
58662306a36Sopenharmony_ci	u32 mul;
58762306a36Sopenharmony_ci	u32 div;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
59062306a36Sopenharmony_ci	mul = t & CPU_SYS_CLKCFG_CPU_FFRAC_MASK;
59162306a36Sopenharmony_ci	div = (t >> CPU_SYS_CLKCFG_CPU_FDIV_SHIFT) &
59262306a36Sopenharmony_ci		CPU_SYS_CLKCFG_CPU_FDIV_MASK;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return mt7620_calc_rate(parent_rate, mul, div);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic unsigned long mt7620_bus_recalc_rate(struct clk_hw *hw,
59862306a36Sopenharmony_ci					    unsigned long parent_rate)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	static const u32 ocp_dividers[16] = {
60162306a36Sopenharmony_ci		[CPU_SYS_CLKCFG_OCP_RATIO_2] = 2,
60262306a36Sopenharmony_ci		[CPU_SYS_CLKCFG_OCP_RATIO_3] = 3,
60362306a36Sopenharmony_ci		[CPU_SYS_CLKCFG_OCP_RATIO_4] = 4,
60462306a36Sopenharmony_ci		[CPU_SYS_CLKCFG_OCP_RATIO_5] = 5,
60562306a36Sopenharmony_ci		[CPU_SYS_CLKCFG_OCP_RATIO_10] = 10,
60662306a36Sopenharmony_ci	};
60762306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
60862306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
60962306a36Sopenharmony_ci	u32 t;
61062306a36Sopenharmony_ci	u32 ocp_ratio;
61162306a36Sopenharmony_ci	u32 div;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
61462306a36Sopenharmony_ci	ocp_ratio = (t >> CPU_SYS_CLKCFG_OCP_RATIO_SHIFT) &
61562306a36Sopenharmony_ci		CPU_SYS_CLKCFG_OCP_RATIO_MASK;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (WARN_ON_ONCE(ocp_ratio >= ARRAY_SIZE(ocp_dividers)))
61862306a36Sopenharmony_ci		return parent_rate;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	div = ocp_dividers[ocp_ratio];
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (WARN(!div, "invalid divider for OCP ratio %u", ocp_ratio))
62362306a36Sopenharmony_ci		return parent_rate;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	return parent_rate / div;
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic unsigned long mt7620_periph_recalc_rate(struct clk_hw *hw,
62962306a36Sopenharmony_ci					       unsigned long parent_rate)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
63262306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
63362306a36Sopenharmony_ci	u32 t;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_CLKCFG0, &t);
63662306a36Sopenharmony_ci	if (t & CLKCFG0_PERI_CLK_SEL)
63762306a36Sopenharmony_ci		return parent_rate;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return 40000000;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic unsigned long mt76x8_xtal_recalc_rate(struct clk_hw *hw,
64362306a36Sopenharmony_ci					     unsigned long parent_rate)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	struct mtmips_clk *clk = to_mtmips_clk(hw);
64662306a36Sopenharmony_ci	struct regmap *sysc = clk->priv->sysc;
64762306a36Sopenharmony_ci	u32 t;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
65062306a36Sopenharmony_ci	if (t & MT7620_XTAL_FREQ_SEL)
65162306a36Sopenharmony_ci		return 40000000;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	return 20000000;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic unsigned long mt76x8_cpu_recalc_rate(struct clk_hw *hw,
65762306a36Sopenharmony_ci					    unsigned long xtal_clk)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	if (xtal_clk == 40000000)
66062306a36Sopenharmony_ci		return 580000000;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	return 575000000;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci#define CLK_BASE(_name, _parent, _recalc) {				\
66662306a36Sopenharmony_ci	.init = &(const struct clk_init_data) {				\
66762306a36Sopenharmony_ci		.name = _name,						\
66862306a36Sopenharmony_ci		.ops = &(const struct clk_ops) {			\
66962306a36Sopenharmony_ci			.recalc_rate = _recalc,				\
67062306a36Sopenharmony_ci		},							\
67162306a36Sopenharmony_ci		.parent_data = &(const struct clk_parent_data) {	\
67262306a36Sopenharmony_ci			.name = _parent,				\
67362306a36Sopenharmony_ci			.fw_name = _parent				\
67462306a36Sopenharmony_ci		},							\
67562306a36Sopenharmony_ci		.num_parents = _parent ? 1 : 0				\
67662306a36Sopenharmony_ci	},								\
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistatic struct mtmips_clk rt2880_clks_base[] = {
68062306a36Sopenharmony_ci	{ CLK_BASE("cpu", "xtal", rt2880_cpu_recalc_rate) }
68162306a36Sopenharmony_ci};
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic struct mtmips_clk rt305x_clks_base[] = {
68462306a36Sopenharmony_ci	{ CLK_BASE("cpu", "xtal", rt305x_cpu_recalc_rate) }
68562306a36Sopenharmony_ci};
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic struct mtmips_clk rt3352_clks_base[] = {
68862306a36Sopenharmony_ci	{ CLK_BASE("xtal", NULL, rt5350_xtal_recalc_rate) },
68962306a36Sopenharmony_ci	{ CLK_BASE("cpu", "xtal", rt3352_cpu_recalc_rate) }
69062306a36Sopenharmony_ci};
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic struct mtmips_clk rt3883_clks_base[] = {
69362306a36Sopenharmony_ci	{ CLK_BASE("cpu", "xtal", rt3883_cpu_recalc_rate) },
69462306a36Sopenharmony_ci	{ CLK_BASE("bus", "cpu", rt3883_bus_recalc_rate) }
69562306a36Sopenharmony_ci};
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_cistatic struct mtmips_clk rt5350_clks_base[] = {
69862306a36Sopenharmony_ci	{ CLK_BASE("xtal", NULL, rt5350_xtal_recalc_rate) },
69962306a36Sopenharmony_ci	{ CLK_BASE("cpu", "xtal", rt5350_cpu_recalc_rate) },
70062306a36Sopenharmony_ci	{ CLK_BASE("bus", "cpu", rt5350_bus_recalc_rate) }
70162306a36Sopenharmony_ci};
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic struct mtmips_clk mt7620_clks_base[] = {
70462306a36Sopenharmony_ci	{ CLK_BASE("xtal", NULL, mt76x8_xtal_recalc_rate) },
70562306a36Sopenharmony_ci	{ CLK_BASE("pll", "xtal", mt7620_pll_recalc_rate) },
70662306a36Sopenharmony_ci	{ CLK_BASE("cpu", "pll", mt7620_cpu_recalc_rate) },
70762306a36Sopenharmony_ci	{ CLK_BASE("periph", "xtal", mt7620_periph_recalc_rate) },
70862306a36Sopenharmony_ci	{ CLK_BASE("bus", "cpu", mt7620_bus_recalc_rate) }
70962306a36Sopenharmony_ci};
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic struct mtmips_clk mt76x8_clks_base[] = {
71262306a36Sopenharmony_ci	{ CLK_BASE("xtal", NULL, mt76x8_xtal_recalc_rate) },
71362306a36Sopenharmony_ci	{ CLK_BASE("cpu", "xtal", mt76x8_cpu_recalc_rate) }
71462306a36Sopenharmony_ci};
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int mtmips_register_clocks(struct device_node *np,
71762306a36Sopenharmony_ci				  struct clk_hw_onecell_data *clk_data,
71862306a36Sopenharmony_ci				  struct mtmips_clk_priv *priv)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct clk_hw **hws = clk_data->hws;
72162306a36Sopenharmony_ci	struct mtmips_clk *sclk;
72262306a36Sopenharmony_ci	int ret, i;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_base; i++) {
72562306a36Sopenharmony_ci		sclk = &priv->data->clk_base[i];
72662306a36Sopenharmony_ci		sclk->priv = priv;
72762306a36Sopenharmony_ci		ret = of_clk_hw_register(np, &sclk->hw);
72862306a36Sopenharmony_ci		if (ret) {
72962306a36Sopenharmony_ci			pr_err("Couldn't register top clock %i\n", i);
73062306a36Sopenharmony_ci			goto err_clk_unreg;
73162306a36Sopenharmony_ci		}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		hws[i] = &sclk->hw;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	return 0;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cierr_clk_unreg:
73962306a36Sopenharmony_ci	while (--i >= 0) {
74062306a36Sopenharmony_ci		sclk = &priv->data->clk_base[i];
74162306a36Sopenharmony_ci		clk_hw_unregister(&sclk->hw);
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci	return ret;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic const struct mtmips_clk_data rt2880_clk_data = {
74762306a36Sopenharmony_ci	.clk_base = rt2880_clks_base,
74862306a36Sopenharmony_ci	.num_clk_base = ARRAY_SIZE(rt2880_clks_base),
74962306a36Sopenharmony_ci	.clk_fixed = rt305x_fixed_clocks,
75062306a36Sopenharmony_ci	.num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks),
75162306a36Sopenharmony_ci	.clk_factor = rt2880_factor_clocks,
75262306a36Sopenharmony_ci	.num_clk_factor = ARRAY_SIZE(rt2880_factor_clocks),
75362306a36Sopenharmony_ci	.clk_periph = rt2880_pherip_clks,
75462306a36Sopenharmony_ci	.num_clk_periph = ARRAY_SIZE(rt2880_pherip_clks),
75562306a36Sopenharmony_ci};
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic const struct mtmips_clk_data rt305x_clk_data = {
75862306a36Sopenharmony_ci	.clk_base = rt305x_clks_base,
75962306a36Sopenharmony_ci	.num_clk_base = ARRAY_SIZE(rt305x_clks_base),
76062306a36Sopenharmony_ci	.clk_fixed = rt305x_fixed_clocks,
76162306a36Sopenharmony_ci	.num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks),
76262306a36Sopenharmony_ci	.clk_factor = rt305x_factor_clocks,
76362306a36Sopenharmony_ci	.num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks),
76462306a36Sopenharmony_ci	.clk_periph = rt305x_pherip_clks,
76562306a36Sopenharmony_ci	.num_clk_periph = ARRAY_SIZE(rt305x_pherip_clks),
76662306a36Sopenharmony_ci};
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic const struct mtmips_clk_data rt3352_clk_data = {
76962306a36Sopenharmony_ci	.clk_base = rt3352_clks_base,
77062306a36Sopenharmony_ci	.num_clk_base = ARRAY_SIZE(rt3352_clks_base),
77162306a36Sopenharmony_ci	.clk_fixed = rt3352_fixed_clocks,
77262306a36Sopenharmony_ci	.num_clk_fixed = ARRAY_SIZE(rt3352_fixed_clocks),
77362306a36Sopenharmony_ci	.clk_factor = rt305x_factor_clocks,
77462306a36Sopenharmony_ci	.num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks),
77562306a36Sopenharmony_ci	.clk_periph = rt5350_pherip_clks,
77662306a36Sopenharmony_ci	.num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks),
77762306a36Sopenharmony_ci};
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic const struct mtmips_clk_data rt3883_clk_data = {
78062306a36Sopenharmony_ci	.clk_base = rt3883_clks_base,
78162306a36Sopenharmony_ci	.num_clk_base = ARRAY_SIZE(rt3883_clks_base),
78262306a36Sopenharmony_ci	.clk_fixed = rt305x_fixed_clocks,
78362306a36Sopenharmony_ci	.num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks),
78462306a36Sopenharmony_ci	.clk_factor = NULL,
78562306a36Sopenharmony_ci	.num_clk_factor = 0,
78662306a36Sopenharmony_ci	.clk_periph = rt5350_pherip_clks,
78762306a36Sopenharmony_ci	.num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks),
78862306a36Sopenharmony_ci};
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic const struct mtmips_clk_data rt5350_clk_data = {
79162306a36Sopenharmony_ci	.clk_base = rt5350_clks_base,
79262306a36Sopenharmony_ci	.num_clk_base = ARRAY_SIZE(rt5350_clks_base),
79362306a36Sopenharmony_ci	.clk_fixed = rt3352_fixed_clocks,
79462306a36Sopenharmony_ci	.num_clk_fixed = ARRAY_SIZE(rt3352_fixed_clocks),
79562306a36Sopenharmony_ci	.clk_factor = NULL,
79662306a36Sopenharmony_ci	.num_clk_factor = 0,
79762306a36Sopenharmony_ci	.clk_periph = rt5350_pherip_clks,
79862306a36Sopenharmony_ci	.num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks),
79962306a36Sopenharmony_ci};
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic const struct mtmips_clk_data mt7620_clk_data = {
80262306a36Sopenharmony_ci	.clk_base = mt7620_clks_base,
80362306a36Sopenharmony_ci	.num_clk_base = ARRAY_SIZE(mt7620_clks_base),
80462306a36Sopenharmony_ci	.clk_fixed = NULL,
80562306a36Sopenharmony_ci	.num_clk_fixed = 0,
80662306a36Sopenharmony_ci	.clk_factor = NULL,
80762306a36Sopenharmony_ci	.num_clk_factor = 0,
80862306a36Sopenharmony_ci	.clk_periph = mt7620_pherip_clks,
80962306a36Sopenharmony_ci	.num_clk_periph = ARRAY_SIZE(mt7620_pherip_clks),
81062306a36Sopenharmony_ci};
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic const struct mtmips_clk_data mt76x8_clk_data = {
81362306a36Sopenharmony_ci	.clk_base = mt76x8_clks_base,
81462306a36Sopenharmony_ci	.num_clk_base = ARRAY_SIZE(mt76x8_clks_base),
81562306a36Sopenharmony_ci	.clk_fixed = mt76x8_fixed_clocks,
81662306a36Sopenharmony_ci	.num_clk_fixed = ARRAY_SIZE(mt76x8_fixed_clocks),
81762306a36Sopenharmony_ci	.clk_factor = rt305x_factor_clocks,
81862306a36Sopenharmony_ci	.num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks),
81962306a36Sopenharmony_ci	.clk_periph = mt76x8_pherip_clks,
82062306a36Sopenharmony_ci	.num_clk_periph = ARRAY_SIZE(mt76x8_pherip_clks),
82162306a36Sopenharmony_ci};
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic const struct of_device_id mtmips_of_match[] = {
82462306a36Sopenharmony_ci	{
82562306a36Sopenharmony_ci		.compatible = "ralink,rt2880-reset",
82662306a36Sopenharmony_ci		.data = NULL,
82762306a36Sopenharmony_ci	},
82862306a36Sopenharmony_ci	{
82962306a36Sopenharmony_ci		.compatible = "ralink,rt2880-sysc",
83062306a36Sopenharmony_ci		.data = &rt2880_clk_data,
83162306a36Sopenharmony_ci	},
83262306a36Sopenharmony_ci	{
83362306a36Sopenharmony_ci		.compatible = "ralink,rt3050-sysc",
83462306a36Sopenharmony_ci		.data = &rt305x_clk_data,
83562306a36Sopenharmony_ci	},
83662306a36Sopenharmony_ci	{
83762306a36Sopenharmony_ci		.compatible = "ralink,rt3052-sysc",
83862306a36Sopenharmony_ci		.data = &rt305x_clk_data,
83962306a36Sopenharmony_ci	},
84062306a36Sopenharmony_ci	{
84162306a36Sopenharmony_ci		.compatible = "ralink,rt3352-sysc",
84262306a36Sopenharmony_ci		.data = &rt3352_clk_data,
84362306a36Sopenharmony_ci	},
84462306a36Sopenharmony_ci	{
84562306a36Sopenharmony_ci		.compatible = "ralink,rt3883-sysc",
84662306a36Sopenharmony_ci		.data = &rt3883_clk_data,
84762306a36Sopenharmony_ci	},
84862306a36Sopenharmony_ci	{
84962306a36Sopenharmony_ci		.compatible = "ralink,rt5350-sysc",
85062306a36Sopenharmony_ci		.data = &rt5350_clk_data,
85162306a36Sopenharmony_ci	},
85262306a36Sopenharmony_ci	{
85362306a36Sopenharmony_ci		.compatible = "ralink,mt7620-sysc",
85462306a36Sopenharmony_ci		.data = &mt7620_clk_data,
85562306a36Sopenharmony_ci	},
85662306a36Sopenharmony_ci	{
85762306a36Sopenharmony_ci		.compatible = "ralink,mt7628-sysc",
85862306a36Sopenharmony_ci		.data = &mt76x8_clk_data,
85962306a36Sopenharmony_ci	},
86062306a36Sopenharmony_ci	{
86162306a36Sopenharmony_ci		.compatible = "ralink,mt7688-sysc",
86262306a36Sopenharmony_ci		.data = &mt76x8_clk_data,
86362306a36Sopenharmony_ci	},
86462306a36Sopenharmony_ci	{}
86562306a36Sopenharmony_ci};
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic void __init mtmips_clk_regs_init(struct device_node *node,
86862306a36Sopenharmony_ci					struct mtmips_clk_priv *priv)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	u32 t;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	if (!of_device_is_compatible(node, "ralink,mt7620-sysc"))
87362306a36Sopenharmony_ci		return;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	/*
87662306a36Sopenharmony_ci	 * When the CPU goes into sleep mode, the BUS
87762306a36Sopenharmony_ci	 * clock will be too low for USB to function properly.
87862306a36Sopenharmony_ci	 * Adjust the busses fractional divider to fix this
87962306a36Sopenharmony_ci	 */
88062306a36Sopenharmony_ci	regmap_read(priv->sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
88162306a36Sopenharmony_ci	t &= ~(CLKCFG_FDIV_MASK | CLKCFG_FFRAC_MASK);
88262306a36Sopenharmony_ci	t |= CLKCFG_FDIV_USB_VAL | CLKCFG_FFRAC_USB_VAL;
88362306a36Sopenharmony_ci	regmap_write(priv->sysc, SYSC_REG_CPU_SYS_CLKCFG, t);
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic void __init mtmips_clk_init(struct device_node *node)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	const struct of_device_id *match;
88962306a36Sopenharmony_ci	const struct mtmips_clk_data *data;
89062306a36Sopenharmony_ci	struct mtmips_clk_priv *priv;
89162306a36Sopenharmony_ci	struct clk_hw_onecell_data *clk_data;
89262306a36Sopenharmony_ci	int ret, i, count;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
89562306a36Sopenharmony_ci	if (!priv)
89662306a36Sopenharmony_ci		return;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	priv->sysc = syscon_node_to_regmap(node);
89962306a36Sopenharmony_ci	if (IS_ERR(priv->sysc)) {
90062306a36Sopenharmony_ci		pr_err("Could not get sysc syscon regmap\n");
90162306a36Sopenharmony_ci		goto free_clk_priv;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	mtmips_clk_regs_init(node, priv);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	match = of_match_node(mtmips_of_match, node);
90762306a36Sopenharmony_ci	if (WARN_ON(!match))
90862306a36Sopenharmony_ci		return;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	data = match->data;
91162306a36Sopenharmony_ci	priv->data = data;
91262306a36Sopenharmony_ci	count = priv->data->num_clk_base + priv->data->num_clk_fixed +
91362306a36Sopenharmony_ci		priv->data->num_clk_factor + priv->data->num_clk_periph;
91462306a36Sopenharmony_ci	clk_data = kzalloc(struct_size(clk_data, hws, count), GFP_KERNEL);
91562306a36Sopenharmony_ci	if (!clk_data)
91662306a36Sopenharmony_ci		goto free_clk_priv;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	ret = mtmips_register_clocks(node, clk_data, priv);
91962306a36Sopenharmony_ci	if (ret) {
92062306a36Sopenharmony_ci		pr_err("Couldn't register top clocks\n");
92162306a36Sopenharmony_ci		goto free_clk_data;
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	ret = mtmips_register_fixed_clocks(clk_data, priv);
92562306a36Sopenharmony_ci	if (ret) {
92662306a36Sopenharmony_ci		pr_err("Couldn't register fixed clocks\n");
92762306a36Sopenharmony_ci		goto unreg_clk_top;
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	ret = mtmips_register_factor_clocks(clk_data, priv);
93162306a36Sopenharmony_ci	if (ret) {
93262306a36Sopenharmony_ci		pr_err("Couldn't register factor clocks\n");
93362306a36Sopenharmony_ci		goto unreg_clk_fixed;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	ret = mtmips_register_pherip_clocks(node, clk_data, priv);
93762306a36Sopenharmony_ci	if (ret) {
93862306a36Sopenharmony_ci		pr_err("Couldn't register peripheral clocks\n");
93962306a36Sopenharmony_ci		goto unreg_clk_factor;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	clk_data->num = count;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
94562306a36Sopenharmony_ci	if (ret) {
94662306a36Sopenharmony_ci		pr_err("Couldn't add clk hw provider\n");
94762306a36Sopenharmony_ci		goto unreg_clk_periph;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ciunreg_clk_periph:
95362306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_periph; i++) {
95462306a36Sopenharmony_ci		struct mtmips_clk *sclk = &priv->data->clk_periph[i];
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		clk_hw_unregister(&sclk->hw);
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ciunreg_clk_factor:
96062306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_factor; i++) {
96162306a36Sopenharmony_ci		struct mtmips_clk_factor *sclk = &priv->data->clk_factor[i];
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		clk_hw_unregister_fixed_factor(sclk->hw);
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ciunreg_clk_fixed:
96762306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_fixed; i++) {
96862306a36Sopenharmony_ci		struct mtmips_clk_fixed *sclk = &priv->data->clk_fixed[i];
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci		clk_hw_unregister_fixed_rate(sclk->hw);
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ciunreg_clk_top:
97462306a36Sopenharmony_ci	for (i = 0; i < priv->data->num_clk_base; i++) {
97562306a36Sopenharmony_ci		struct mtmips_clk *sclk = &priv->data->clk_base[i];
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		clk_hw_unregister(&sclk->hw);
97862306a36Sopenharmony_ci	}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cifree_clk_data:
98162306a36Sopenharmony_ci	kfree(clk_data);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cifree_clk_priv:
98462306a36Sopenharmony_ci	kfree(priv);
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(rt2880_clk, "ralink,rt2880-sysc", mtmips_clk_init);
98762306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(rt3050_clk, "ralink,rt3050-sysc", mtmips_clk_init);
98862306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(rt3052_clk, "ralink,rt3052-sysc", mtmips_clk_init);
98962306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(rt3352_clk, "ralink,rt3352-sysc", mtmips_clk_init);
99062306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(rt3883_clk, "ralink,rt3883-sysc", mtmips_clk_init);
99162306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(rt5350_clk, "ralink,rt5350-sysc", mtmips_clk_init);
99262306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(mt7620_clk, "ralink,mt7620-sysc", mtmips_clk_init);
99362306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(mt7628_clk, "ralink,mt7628-sysc", mtmips_clk_init);
99462306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(mt7688_clk, "ralink,mt7688-sysc", mtmips_clk_init);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cistruct mtmips_rst {
99762306a36Sopenharmony_ci	struct reset_controller_dev rcdev;
99862306a36Sopenharmony_ci	struct regmap *sysc;
99962306a36Sopenharmony_ci};
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic struct mtmips_rst *to_mtmips_rst(struct reset_controller_dev *dev)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	return container_of(dev, struct mtmips_rst, rcdev);
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic int mtmips_assert_device(struct reset_controller_dev *rcdev,
100762306a36Sopenharmony_ci				unsigned long id)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	struct mtmips_rst *data = to_mtmips_rst(rcdev);
101062306a36Sopenharmony_ci	struct regmap *sysc = data->sysc;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	return regmap_update_bits(sysc, SYSC_REG_RESET_CTRL, BIT(id), BIT(id));
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic int mtmips_deassert_device(struct reset_controller_dev *rcdev,
101662306a36Sopenharmony_ci				  unsigned long id)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	struct mtmips_rst *data = to_mtmips_rst(rcdev);
101962306a36Sopenharmony_ci	struct regmap *sysc = data->sysc;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return regmap_update_bits(sysc, SYSC_REG_RESET_CTRL, BIT(id), 0);
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int mtmips_reset_device(struct reset_controller_dev *rcdev,
102562306a36Sopenharmony_ci			       unsigned long id)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	int ret;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	ret = mtmips_assert_device(rcdev, id);
103062306a36Sopenharmony_ci	if (ret < 0)
103162306a36Sopenharmony_ci		return ret;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	return mtmips_deassert_device(rcdev, id);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic int mtmips_rst_xlate(struct reset_controller_dev *rcdev,
103762306a36Sopenharmony_ci			    const struct of_phandle_args *reset_spec)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	unsigned long id = reset_spec->args[0];
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	if (id == 0 || id >= rcdev->nr_resets)
104262306a36Sopenharmony_ci		return -EINVAL;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	return id;
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_cistatic const struct reset_control_ops reset_ops = {
104862306a36Sopenharmony_ci	.reset = mtmips_reset_device,
104962306a36Sopenharmony_ci	.assert = mtmips_assert_device,
105062306a36Sopenharmony_ci	.deassert = mtmips_deassert_device
105162306a36Sopenharmony_ci};
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic int mtmips_reset_init(struct device *dev, struct regmap *sysc)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	struct mtmips_rst *rst_data;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL);
105862306a36Sopenharmony_ci	if (!rst_data)
105962306a36Sopenharmony_ci		return -ENOMEM;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	rst_data->sysc = sysc;
106262306a36Sopenharmony_ci	rst_data->rcdev.ops = &reset_ops;
106362306a36Sopenharmony_ci	rst_data->rcdev.owner = THIS_MODULE;
106462306a36Sopenharmony_ci	rst_data->rcdev.nr_resets = 32;
106562306a36Sopenharmony_ci	rst_data->rcdev.of_reset_n_cells = 1;
106662306a36Sopenharmony_ci	rst_data->rcdev.of_xlate = mtmips_rst_xlate;
106762306a36Sopenharmony_ci	rst_data->rcdev.of_node = dev_of_node(dev);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	return devm_reset_controller_register(dev, &rst_data->rcdev);
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic int mtmips_clk_probe(struct platform_device *pdev)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
107562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
107662306a36Sopenharmony_ci	struct mtmips_clk_priv *priv;
107762306a36Sopenharmony_ci	int ret;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
108062306a36Sopenharmony_ci	if (!priv)
108162306a36Sopenharmony_ci		return -ENOMEM;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	priv->sysc = syscon_node_to_regmap(np);
108462306a36Sopenharmony_ci	if (IS_ERR(priv->sysc))
108562306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(priv->sysc),
108662306a36Sopenharmony_ci				     "Could not get sysc syscon regmap\n");
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	ret = mtmips_reset_init(dev, priv->sysc);
108962306a36Sopenharmony_ci	if (ret)
109062306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "Could not init reset controller\n");
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	return 0;
109362306a36Sopenharmony_ci}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_cistatic struct platform_driver mtmips_clk_driver = {
109662306a36Sopenharmony_ci	.probe = mtmips_clk_probe,
109762306a36Sopenharmony_ci	.driver = {
109862306a36Sopenharmony_ci		.name = "mtmips-clk",
109962306a36Sopenharmony_ci		.of_match_table = mtmips_of_match,
110062306a36Sopenharmony_ci	},
110162306a36Sopenharmony_ci};
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic int __init mtmips_clk_reset_init(void)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	return platform_driver_register(&mtmips_clk_driver);
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ciarch_initcall(mtmips_clk_reset_init);
1108