xref: /openbmc/linux/drivers/clk/ralink/clk-mtmips.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
16f3b1558SSergio Paracuellos // SPDX-License-Identifier: GPL-2.0
26f3b1558SSergio Paracuellos /*
36f3b1558SSergio Paracuellos  * MTMIPS SoCs Clock Driver
46f3b1558SSergio Paracuellos  * Author: Sergio Paracuellos <sergio.paracuellos@gmail.com>
56f3b1558SSergio Paracuellos  */
66f3b1558SSergio Paracuellos 
76f3b1558SSergio Paracuellos #include <linux/bitops.h>
86f3b1558SSergio Paracuellos #include <linux/clk-provider.h>
96f3b1558SSergio Paracuellos #include <linux/mfd/syscon.h>
106f3b1558SSergio Paracuellos #include <linux/platform_device.h>
116f3b1558SSergio Paracuellos #include <linux/regmap.h>
126f3b1558SSergio Paracuellos #include <linux/reset-controller.h>
136f3b1558SSergio Paracuellos #include <linux/slab.h>
146f3b1558SSergio Paracuellos 
156f3b1558SSergio Paracuellos /* Configuration registers */
166f3b1558SSergio Paracuellos #define SYSC_REG_SYSTEM_CONFIG		0x10
176f3b1558SSergio Paracuellos #define SYSC_REG_CLKCFG0		0x2c
186f3b1558SSergio Paracuellos #define SYSC_REG_RESET_CTRL		0x34
196f3b1558SSergio Paracuellos #define SYSC_REG_CPU_SYS_CLKCFG		0x3c
206f3b1558SSergio Paracuellos #define SYSC_REG_CPLL_CONFIG0		0x54
216f3b1558SSergio Paracuellos #define SYSC_REG_CPLL_CONFIG1		0x58
226f3b1558SSergio Paracuellos 
236f3b1558SSergio Paracuellos /* RT2880 SoC */
246f3b1558SSergio Paracuellos #define RT2880_CONFIG_CPUCLK_SHIFT	20
256f3b1558SSergio Paracuellos #define RT2880_CONFIG_CPUCLK_MASK	0x3
266f3b1558SSergio Paracuellos #define RT2880_CONFIG_CPUCLK_250	0x0
276f3b1558SSergio Paracuellos #define RT2880_CONFIG_CPUCLK_266	0x1
286f3b1558SSergio Paracuellos #define RT2880_CONFIG_CPUCLK_280	0x2
296f3b1558SSergio Paracuellos #define RT2880_CONFIG_CPUCLK_300	0x3
306f3b1558SSergio Paracuellos 
316f3b1558SSergio Paracuellos /* RT305X SoC */
326f3b1558SSergio Paracuellos #define RT305X_SYSCFG_CPUCLK_SHIFT	18
336f3b1558SSergio Paracuellos #define RT305X_SYSCFG_CPUCLK_MASK	0x1
346f3b1558SSergio Paracuellos #define RT305X_SYSCFG_CPUCLK_LOW	0x0
356f3b1558SSergio Paracuellos #define RT305X_SYSCFG_CPUCLK_HIGH	0x1
366f3b1558SSergio Paracuellos 
376f3b1558SSergio Paracuellos /* RT3352 SoC */
386f3b1558SSergio Paracuellos #define RT3352_SYSCFG0_CPUCLK_SHIFT	8
396f3b1558SSergio Paracuellos #define RT3352_SYSCFG0_CPUCLK_MASK	0x1
406f3b1558SSergio Paracuellos #define RT3352_SYSCFG0_CPUCLK_LOW	0x0
416f3b1558SSergio Paracuellos #define RT3352_SYSCFG0_CPUCLK_HIGH	0x1
426f3b1558SSergio Paracuellos 
436f3b1558SSergio Paracuellos /* RT3383 SoC */
446f3b1558SSergio Paracuellos #define RT3883_SYSCFG0_DRAM_TYPE_DDR2	BIT(17)
456f3b1558SSergio Paracuellos #define RT3883_SYSCFG0_CPUCLK_SHIFT	8
466f3b1558SSergio Paracuellos #define RT3883_SYSCFG0_CPUCLK_MASK	0x3
476f3b1558SSergio Paracuellos #define RT3883_SYSCFG0_CPUCLK_250	0x0
486f3b1558SSergio Paracuellos #define RT3883_SYSCFG0_CPUCLK_384	0x1
496f3b1558SSergio Paracuellos #define RT3883_SYSCFG0_CPUCLK_480	0x2
506f3b1558SSergio Paracuellos #define RT3883_SYSCFG0_CPUCLK_500	0x3
516f3b1558SSergio Paracuellos 
526f3b1558SSergio Paracuellos /* RT5350 SoC */
536f3b1558SSergio Paracuellos #define RT5350_CLKCFG0_XTAL_SEL		BIT(20)
546f3b1558SSergio Paracuellos #define RT5350_SYSCFG0_CPUCLK_SHIFT	8
556f3b1558SSergio Paracuellos #define RT5350_SYSCFG0_CPUCLK_MASK	0x3
566f3b1558SSergio Paracuellos #define RT5350_SYSCFG0_CPUCLK_360	0x0
576f3b1558SSergio Paracuellos #define RT5350_SYSCFG0_CPUCLK_320	0x2
586f3b1558SSergio Paracuellos #define RT5350_SYSCFG0_CPUCLK_300	0x3
596f3b1558SSergio Paracuellos 
606f3b1558SSergio Paracuellos /* MT7620 and MT76x8 SoCs */
616f3b1558SSergio Paracuellos #define MT7620_XTAL_FREQ_SEL		BIT(6)
626f3b1558SSergio Paracuellos #define CPLL_CFG0_SW_CFG		BIT(31)
636f3b1558SSergio Paracuellos #define CPLL_CFG0_PLL_MULT_RATIO_SHIFT	16
646f3b1558SSergio Paracuellos #define CPLL_CFG0_PLL_MULT_RATIO_MASK   0x7
656f3b1558SSergio Paracuellos #define CPLL_CFG0_LC_CURFCK		BIT(15)
666f3b1558SSergio Paracuellos #define CPLL_CFG0_BYPASS_REF_CLK	BIT(14)
676f3b1558SSergio Paracuellos #define CPLL_CFG0_PLL_DIV_RATIO_SHIFT	10
686f3b1558SSergio Paracuellos #define CPLL_CFG0_PLL_DIV_RATIO_MASK	0x3
696f3b1558SSergio Paracuellos #define CPLL_CFG1_CPU_AUX1		BIT(25)
706f3b1558SSergio Paracuellos #define CPLL_CFG1_CPU_AUX0		BIT(24)
716f3b1558SSergio Paracuellos #define CLKCFG0_PERI_CLK_SEL		BIT(4)
726f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_SHIFT	16
736f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_MASK	0xf
746f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_1	0	/* 1:1   (Reserved) */
756f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_1_5	1	/* 1:1.5 (Reserved) */
766f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_2	2	/* 1:2   */
776f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_2_5	3       /* 1:2.5 (Reserved) */
786f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_3	4	/* 1:3   */
796f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_3_5	5	/* 1:3.5 (Reserved) */
806f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_4	6	/* 1:4   */
816f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_5	7	/* 1:5   */
826f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_OCP_RATIO_10	8	/* 1:10  */
836f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_CPU_FDIV_SHIFT	8
846f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_CPU_FDIV_MASK	0x1f
856f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_CPU_FFRAC_SHIFT	0
866f3b1558SSergio Paracuellos #define CPU_SYS_CLKCFG_CPU_FFRAC_MASK	0x1f
876f3b1558SSergio Paracuellos 
886f3b1558SSergio Paracuellos /* clock scaling */
896f3b1558SSergio Paracuellos #define CLKCFG_FDIV_MASK		0x1f00
906f3b1558SSergio Paracuellos #define CLKCFG_FDIV_USB_VAL		0x0300
916f3b1558SSergio Paracuellos #define CLKCFG_FFRAC_MASK		0x001f
926f3b1558SSergio Paracuellos #define CLKCFG_FFRAC_USB_VAL		0x0003
936f3b1558SSergio Paracuellos 
946f3b1558SSergio Paracuellos struct mtmips_clk;
956f3b1558SSergio Paracuellos struct mtmips_clk_fixed;
966f3b1558SSergio Paracuellos struct mtmips_clk_factor;
976f3b1558SSergio Paracuellos 
986f3b1558SSergio Paracuellos struct mtmips_clk_data {
996f3b1558SSergio Paracuellos 	struct mtmips_clk *clk_base;
1006f3b1558SSergio Paracuellos 	size_t num_clk_base;
1016f3b1558SSergio Paracuellos 	struct mtmips_clk_fixed *clk_fixed;
1026f3b1558SSergio Paracuellos 	size_t num_clk_fixed;
1036f3b1558SSergio Paracuellos 	struct mtmips_clk_factor *clk_factor;
1046f3b1558SSergio Paracuellos 	size_t num_clk_factor;
1056f3b1558SSergio Paracuellos 	struct mtmips_clk *clk_periph;
1066f3b1558SSergio Paracuellos 	size_t num_clk_periph;
1076f3b1558SSergio Paracuellos };
1086f3b1558SSergio Paracuellos 
1096f3b1558SSergio Paracuellos struct mtmips_clk_priv {
1106f3b1558SSergio Paracuellos 	struct regmap *sysc;
1116f3b1558SSergio Paracuellos 	const struct mtmips_clk_data *data;
1126f3b1558SSergio Paracuellos };
1136f3b1558SSergio Paracuellos 
1146f3b1558SSergio Paracuellos struct mtmips_clk {
1156f3b1558SSergio Paracuellos 	struct clk_hw hw;
1166f3b1558SSergio Paracuellos 	struct mtmips_clk_priv *priv;
1176f3b1558SSergio Paracuellos };
1186f3b1558SSergio Paracuellos 
1196f3b1558SSergio Paracuellos struct mtmips_clk_fixed {
1206f3b1558SSergio Paracuellos 	const char *name;
1216f3b1558SSergio Paracuellos 	const char *parent;
1226f3b1558SSergio Paracuellos 	unsigned long rate;
1236f3b1558SSergio Paracuellos 	struct clk_hw *hw;
1246f3b1558SSergio Paracuellos };
1256f3b1558SSergio Paracuellos 
1266f3b1558SSergio Paracuellos struct mtmips_clk_factor {
1276f3b1558SSergio Paracuellos 	const char *name;
1286f3b1558SSergio Paracuellos 	const char *parent;
1296f3b1558SSergio Paracuellos 	int mult;
1306f3b1558SSergio Paracuellos 	int div;
1316f3b1558SSergio Paracuellos 	unsigned long flags;
1326f3b1558SSergio Paracuellos 	struct clk_hw *hw;
1336f3b1558SSergio Paracuellos };
1346f3b1558SSergio Paracuellos 
mtmips_pherip_clk_rate(struct clk_hw * hw,unsigned long parent_rate)1356f3b1558SSergio Paracuellos static unsigned long mtmips_pherip_clk_rate(struct clk_hw *hw,
1366f3b1558SSergio Paracuellos 					    unsigned long parent_rate)
1376f3b1558SSergio Paracuellos {
1386f3b1558SSergio Paracuellos 	return parent_rate;
1396f3b1558SSergio Paracuellos }
1406f3b1558SSergio Paracuellos 
1416f3b1558SSergio Paracuellos static const struct clk_ops mtmips_periph_clk_ops = {
1426f3b1558SSergio Paracuellos 	.recalc_rate = mtmips_pherip_clk_rate,
1436f3b1558SSergio Paracuellos };
1446f3b1558SSergio Paracuellos 
1456f3b1558SSergio Paracuellos #define CLK_PERIPH(_name, _parent) {				\
1466f3b1558SSergio Paracuellos 	.init = &(const struct clk_init_data) {			\
1476f3b1558SSergio Paracuellos 		.name = _name,					\
1486f3b1558SSergio Paracuellos 		.ops = &mtmips_periph_clk_ops,			\
1496f3b1558SSergio Paracuellos 		.parent_data = &(const struct clk_parent_data) {\
1506f3b1558SSergio Paracuellos 			.name = _parent,			\
1516f3b1558SSergio Paracuellos 			.fw_name = _parent			\
1526f3b1558SSergio Paracuellos 		},						\
1536f3b1558SSergio Paracuellos 		.num_parents = 1,				\
1546f3b1558SSergio Paracuellos 		/*						\
1556f3b1558SSergio Paracuellos 		 * There are drivers for these SoCs that are	\
1566f3b1558SSergio Paracuellos 		 * older than clock driver and are not prepared \
1576f3b1558SSergio Paracuellos 		 * for the clock. We don't want the kernel to   \
1586f3b1558SSergio Paracuellos 		 * disable anything so we add CLK_IS_CRITICAL	\
1596f3b1558SSergio Paracuellos 		 * flag here.					\
1606f3b1558SSergio Paracuellos 		 */						\
1616f3b1558SSergio Paracuellos 		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL	\
1626f3b1558SSergio Paracuellos 	},							\
1636f3b1558SSergio Paracuellos }
1646f3b1558SSergio Paracuellos 
1656f3b1558SSergio Paracuellos static struct mtmips_clk rt2880_pherip_clks[] = {
1666f3b1558SSergio Paracuellos 	{ CLK_PERIPH("300100.timer", "bus") },
1676f3b1558SSergio Paracuellos 	{ CLK_PERIPH("300120.watchdog", "bus") },
1686f3b1558SSergio Paracuellos 	{ CLK_PERIPH("300500.uart", "bus") },
1696f3b1558SSergio Paracuellos 	{ CLK_PERIPH("300900.i2c", "bus") },
1706f3b1558SSergio Paracuellos 	{ CLK_PERIPH("300c00.uartlite", "bus") },
1716f3b1558SSergio Paracuellos 	{ CLK_PERIPH("400000.ethernet", "bus") },
1726f3b1558SSergio Paracuellos 	{ CLK_PERIPH("480000.wmac", "xtal") }
1736f3b1558SSergio Paracuellos };
1746f3b1558SSergio Paracuellos 
1756f3b1558SSergio Paracuellos static struct mtmips_clk rt305x_pherip_clks[] = {
1766f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000100.timer", "bus") },
1776f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000120.watchdog", "bus") },
1786f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000500.uart", "bus") },
1796f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000900.i2c", "bus") },
1806f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000a00.i2s", "bus") },
1816f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b00.spi", "bus") },
1826f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b40.spi", "bus") },
1836f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000c00.uartlite", "bus") },
1846f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10100000.ethernet", "bus") },
1856f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10180000.wmac", "xtal") }
1866f3b1558SSergio Paracuellos };
1876f3b1558SSergio Paracuellos 
1886f3b1558SSergio Paracuellos static struct mtmips_clk rt5350_pherip_clks[] = {
1896f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000100.timer", "bus") },
1906f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000120.watchdog", "bus") },
1916f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000500.uart", "periph") },
1926f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000900.i2c", "periph") },
1936f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000a00.i2s", "periph") },
1946f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b00.spi", "bus") },
1956f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b40.spi", "bus") },
1966f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000c00.uartlite", "periph") },
1976f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10100000.ethernet", "bus") },
1986f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10180000.wmac", "xtal") }
1996f3b1558SSergio Paracuellos };
2006f3b1558SSergio Paracuellos 
2016f3b1558SSergio Paracuellos static struct mtmips_clk mt7620_pherip_clks[] = {
2026f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000100.timer", "periph") },
2036f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000120.watchdog", "periph") },
2046f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000500.uart", "periph") },
2056f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000900.i2c", "periph") },
2066f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000a00.i2s", "periph") },
2076f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b00.spi", "bus") },
2086f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b40.spi", "bus") },
2096f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000c00.uartlite", "periph") },
2106f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10180000.wmac", "xtal") }
2116f3b1558SSergio Paracuellos };
2126f3b1558SSergio Paracuellos 
2136f3b1558SSergio Paracuellos static struct mtmips_clk mt76x8_pherip_clks[] = {
2146f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000100.timer", "periph") },
2156f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000120.watchdog", "periph") },
2166f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000900.i2c", "periph") },
2176f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000a00.i2s", "pcmi2s") },
2186f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b00.spi", "bus") },
2196f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000b40.spi", "bus") },
2206f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000c00.uart0", "periph") },
2216f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000d00.uart1", "periph") },
2226f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10000e00.uart2", "periph") },
2236f3b1558SSergio Paracuellos 	{ CLK_PERIPH("10300000.wmac", "xtal") }
2246f3b1558SSergio Paracuellos };
2256f3b1558SSergio Paracuellos 
mtmips_register_pherip_clocks(struct device_node * np,struct clk_hw_onecell_data * clk_data,struct mtmips_clk_priv * priv)2266f3b1558SSergio Paracuellos static int mtmips_register_pherip_clocks(struct device_node *np,
2276f3b1558SSergio Paracuellos 					 struct clk_hw_onecell_data *clk_data,
2286f3b1558SSergio Paracuellos 					 struct mtmips_clk_priv *priv)
2296f3b1558SSergio Paracuellos {
2306f3b1558SSergio Paracuellos 	struct clk_hw **hws = clk_data->hws;
2316f3b1558SSergio Paracuellos 	struct mtmips_clk *sclk;
2326f3b1558SSergio Paracuellos 	size_t idx_start = priv->data->num_clk_base + priv->data->num_clk_fixed +
2336f3b1558SSergio Paracuellos 			   priv->data->num_clk_factor;
2346f3b1558SSergio Paracuellos 	int ret, i;
2356f3b1558SSergio Paracuellos 
2366f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_periph; i++) {
2376f3b1558SSergio Paracuellos 		int idx = idx_start + i;
2386f3b1558SSergio Paracuellos 
2396f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_periph[i];
2406f3b1558SSergio Paracuellos 		ret = of_clk_hw_register(np, &sclk->hw);
2416f3b1558SSergio Paracuellos 		if (ret) {
2426f3b1558SSergio Paracuellos 			pr_err("Couldn't register peripheral clock %d\n", idx);
2436f3b1558SSergio Paracuellos 			goto err_clk_unreg;
2446f3b1558SSergio Paracuellos 		}
2456f3b1558SSergio Paracuellos 
2466f3b1558SSergio Paracuellos 		hws[idx] = &sclk->hw;
2476f3b1558SSergio Paracuellos 	}
2486f3b1558SSergio Paracuellos 
2496f3b1558SSergio Paracuellos 	return 0;
2506f3b1558SSergio Paracuellos 
2516f3b1558SSergio Paracuellos err_clk_unreg:
2526f3b1558SSergio Paracuellos 	while (--i >= 0) {
2536f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_periph[i];
2546f3b1558SSergio Paracuellos 		clk_hw_unregister(&sclk->hw);
2556f3b1558SSergio Paracuellos 	}
2566f3b1558SSergio Paracuellos 	return ret;
2576f3b1558SSergio Paracuellos }
2586f3b1558SSergio Paracuellos 
2596f3b1558SSergio Paracuellos #define CLK_FIXED(_name, _parent, _rate) \
2606f3b1558SSergio Paracuellos 	{				 \
2616f3b1558SSergio Paracuellos 		.name = _name,		 \
2626f3b1558SSergio Paracuellos 		.parent = _parent,	 \
2636f3b1558SSergio Paracuellos 		.rate = _rate		 \
2646f3b1558SSergio Paracuellos 	}
2656f3b1558SSergio Paracuellos 
266f85a1d06SSergio Paracuellos static struct mtmips_clk_fixed rt3883_fixed_clocks[] = {
267f85a1d06SSergio Paracuellos 	CLK_FIXED("periph", "xtal", 40000000)
268f85a1d06SSergio Paracuellos };
269f85a1d06SSergio Paracuellos 
2706f3b1558SSergio Paracuellos static struct mtmips_clk_fixed rt3352_fixed_clocks[] = {
2716f3b1558SSergio Paracuellos 	CLK_FIXED("periph", "xtal", 40000000)
2726f3b1558SSergio Paracuellos };
2736f3b1558SSergio Paracuellos 
2746f3b1558SSergio Paracuellos static struct mtmips_clk_fixed mt76x8_fixed_clocks[] = {
2756f3b1558SSergio Paracuellos 	CLK_FIXED("pcmi2s", "xtal", 480000000),
2766f3b1558SSergio Paracuellos 	CLK_FIXED("periph", "xtal", 40000000)
2776f3b1558SSergio Paracuellos };
2786f3b1558SSergio Paracuellos 
mtmips_register_fixed_clocks(struct clk_hw_onecell_data * clk_data,struct mtmips_clk_priv * priv)2796f3b1558SSergio Paracuellos static int mtmips_register_fixed_clocks(struct clk_hw_onecell_data *clk_data,
2806f3b1558SSergio Paracuellos 					struct mtmips_clk_priv *priv)
2816f3b1558SSergio Paracuellos {
2826f3b1558SSergio Paracuellos 	struct clk_hw **hws = clk_data->hws;
2836f3b1558SSergio Paracuellos 	struct mtmips_clk_fixed *sclk;
2846f3b1558SSergio Paracuellos 	size_t idx_start = priv->data->num_clk_base;
2856f3b1558SSergio Paracuellos 	int ret, i;
2866f3b1558SSergio Paracuellos 
2876f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_fixed; i++) {
2886f3b1558SSergio Paracuellos 		int idx = idx_start + i;
2896f3b1558SSergio Paracuellos 
2906f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_fixed[i];
2916f3b1558SSergio Paracuellos 		sclk->hw = clk_hw_register_fixed_rate(NULL, sclk->name,
2926f3b1558SSergio Paracuellos 						      sclk->parent, 0,
2936f3b1558SSergio Paracuellos 						      sclk->rate);
2946f3b1558SSergio Paracuellos 		if (IS_ERR(sclk->hw)) {
2956e68dae9SNathan Chancellor 			ret = PTR_ERR(sclk->hw);
2966f3b1558SSergio Paracuellos 			pr_err("Couldn't register fixed clock %d\n", idx);
2976f3b1558SSergio Paracuellos 			goto err_clk_unreg;
2986f3b1558SSergio Paracuellos 		}
2996f3b1558SSergio Paracuellos 
3006f3b1558SSergio Paracuellos 		hws[idx] = sclk->hw;
3016f3b1558SSergio Paracuellos 	}
3026f3b1558SSergio Paracuellos 
3036f3b1558SSergio Paracuellos 	return 0;
3046f3b1558SSergio Paracuellos 
3056f3b1558SSergio Paracuellos err_clk_unreg:
3066f3b1558SSergio Paracuellos 	while (--i >= 0) {
3076f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_fixed[i];
3086f3b1558SSergio Paracuellos 		clk_hw_unregister_fixed_rate(sclk->hw);
3096f3b1558SSergio Paracuellos 	}
3106f3b1558SSergio Paracuellos 	return ret;
3116f3b1558SSergio Paracuellos }
3126f3b1558SSergio Paracuellos 
3136f3b1558SSergio Paracuellos #define CLK_FACTOR(_name, _parent, _mult, _div)		\
3146f3b1558SSergio Paracuellos 	{						\
3156f3b1558SSergio Paracuellos 		.name = _name,				\
3166f3b1558SSergio Paracuellos 		.parent = _parent,			\
3176f3b1558SSergio Paracuellos 		.mult = _mult,				\
3186f3b1558SSergio Paracuellos 		.div = _div,				\
3196f3b1558SSergio Paracuellos 		.flags = CLK_SET_RATE_PARENT		\
3206f3b1558SSergio Paracuellos 	}
3216f3b1558SSergio Paracuellos 
3226f3b1558SSergio Paracuellos static struct mtmips_clk_factor rt2880_factor_clocks[] = {
3236f3b1558SSergio Paracuellos 	CLK_FACTOR("bus", "cpu", 1, 2)
3246f3b1558SSergio Paracuellos };
3256f3b1558SSergio Paracuellos 
3266f3b1558SSergio Paracuellos static struct mtmips_clk_factor rt305x_factor_clocks[] = {
3276f3b1558SSergio Paracuellos 	CLK_FACTOR("bus", "cpu", 1, 3)
3286f3b1558SSergio Paracuellos };
3296f3b1558SSergio Paracuellos 
mtmips_register_factor_clocks(struct clk_hw_onecell_data * clk_data,struct mtmips_clk_priv * priv)3306f3b1558SSergio Paracuellos static int mtmips_register_factor_clocks(struct clk_hw_onecell_data *clk_data,
3316f3b1558SSergio Paracuellos 					 struct mtmips_clk_priv *priv)
3326f3b1558SSergio Paracuellos {
3336f3b1558SSergio Paracuellos 	struct clk_hw **hws = clk_data->hws;
3346f3b1558SSergio Paracuellos 	struct mtmips_clk_factor *sclk;
3356f3b1558SSergio Paracuellos 	size_t idx_start = priv->data->num_clk_base + priv->data->num_clk_fixed;
3366f3b1558SSergio Paracuellos 	int ret, i;
3376f3b1558SSergio Paracuellos 
3386f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_factor; i++) {
3396f3b1558SSergio Paracuellos 		int idx = idx_start + i;
3406f3b1558SSergio Paracuellos 
3416f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_factor[i];
3426f3b1558SSergio Paracuellos 		sclk->hw = clk_hw_register_fixed_factor(NULL, sclk->name,
3436f3b1558SSergio Paracuellos 						  sclk->parent, sclk->flags,
3446f3b1558SSergio Paracuellos 						  sclk->mult, sclk->div);
3456f3b1558SSergio Paracuellos 		if (IS_ERR(sclk->hw)) {
3466e68dae9SNathan Chancellor 			ret = PTR_ERR(sclk->hw);
3476f3b1558SSergio Paracuellos 			pr_err("Couldn't register factor clock %d\n", idx);
3486f3b1558SSergio Paracuellos 			goto err_clk_unreg;
3496f3b1558SSergio Paracuellos 		}
3506f3b1558SSergio Paracuellos 
3516f3b1558SSergio Paracuellos 		hws[idx] = sclk->hw;
3526f3b1558SSergio Paracuellos 	}
3536f3b1558SSergio Paracuellos 
3546f3b1558SSergio Paracuellos 	return 0;
3556f3b1558SSergio Paracuellos 
3566f3b1558SSergio Paracuellos err_clk_unreg:
3576f3b1558SSergio Paracuellos 	while (--i >= 0) {
3586f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_factor[i];
3596f3b1558SSergio Paracuellos 		clk_hw_unregister_fixed_factor(sclk->hw);
3606f3b1558SSergio Paracuellos 	}
3616f3b1558SSergio Paracuellos 	return ret;
3626f3b1558SSergio Paracuellos }
3636f3b1558SSergio Paracuellos 
to_mtmips_clk(struct clk_hw * hw)3646f3b1558SSergio Paracuellos static inline struct mtmips_clk *to_mtmips_clk(struct clk_hw *hw)
3656f3b1558SSergio Paracuellos {
3666f3b1558SSergio Paracuellos 	return container_of(hw, struct mtmips_clk, hw);
3676f3b1558SSergio Paracuellos }
3686f3b1558SSergio Paracuellos 
rt2880_xtal_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)369*fbb13732SSergio Paracuellos static unsigned long rt2880_xtal_recalc_rate(struct clk_hw *hw,
370*fbb13732SSergio Paracuellos 					     unsigned long parent_rate)
371*fbb13732SSergio Paracuellos {
372*fbb13732SSergio Paracuellos 	return 40000000;
373*fbb13732SSergio Paracuellos }
374*fbb13732SSergio Paracuellos 
rt5350_xtal_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)3756f3b1558SSergio Paracuellos static unsigned long rt5350_xtal_recalc_rate(struct clk_hw *hw,
3766f3b1558SSergio Paracuellos 					     unsigned long parent_rate)
3776f3b1558SSergio Paracuellos {
3786f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
3796f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
3806f3b1558SSergio Paracuellos 	u32 val;
3816f3b1558SSergio Paracuellos 
3826f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &val);
3836f3b1558SSergio Paracuellos 	if (!(val & RT5350_CLKCFG0_XTAL_SEL))
3846f3b1558SSergio Paracuellos 		return 20000000;
3856f3b1558SSergio Paracuellos 
3866f3b1558SSergio Paracuellos 	return 40000000;
3876f3b1558SSergio Paracuellos }
3886f3b1558SSergio Paracuellos 
rt5350_cpu_recalc_rate(struct clk_hw * hw,unsigned long xtal_clk)3896f3b1558SSergio Paracuellos static unsigned long rt5350_cpu_recalc_rate(struct clk_hw *hw,
3906f3b1558SSergio Paracuellos 					    unsigned long xtal_clk)
3916f3b1558SSergio Paracuellos {
3926f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
3936f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
3946f3b1558SSergio Paracuellos 	u32 t;
3956f3b1558SSergio Paracuellos 
3966f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
3976f3b1558SSergio Paracuellos 	t = (t >> RT5350_SYSCFG0_CPUCLK_SHIFT) & RT5350_SYSCFG0_CPUCLK_MASK;
3986f3b1558SSergio Paracuellos 
3996f3b1558SSergio Paracuellos 	switch (t) {
4006f3b1558SSergio Paracuellos 	case RT5350_SYSCFG0_CPUCLK_360:
4016f3b1558SSergio Paracuellos 		return 360000000;
4026f3b1558SSergio Paracuellos 	case RT5350_SYSCFG0_CPUCLK_320:
4036f3b1558SSergio Paracuellos 		return 320000000;
4046f3b1558SSergio Paracuellos 	case RT5350_SYSCFG0_CPUCLK_300:
4056f3b1558SSergio Paracuellos 		return 300000000;
4066f3b1558SSergio Paracuellos 	default:
4076f3b1558SSergio Paracuellos 		BUG();
4086f3b1558SSergio Paracuellos 	}
4096f3b1558SSergio Paracuellos }
4106f3b1558SSergio Paracuellos 
rt5350_bus_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)4116f3b1558SSergio Paracuellos static unsigned long rt5350_bus_recalc_rate(struct clk_hw *hw,
4126f3b1558SSergio Paracuellos 					    unsigned long parent_rate)
4136f3b1558SSergio Paracuellos {
4146f3b1558SSergio Paracuellos 	if (parent_rate == 320000000)
4156f3b1558SSergio Paracuellos 		return parent_rate / 4;
4166f3b1558SSergio Paracuellos 
4176f3b1558SSergio Paracuellos 	return parent_rate / 3;
4186f3b1558SSergio Paracuellos }
4196f3b1558SSergio Paracuellos 
rt3352_cpu_recalc_rate(struct clk_hw * hw,unsigned long xtal_clk)4206f3b1558SSergio Paracuellos static unsigned long rt3352_cpu_recalc_rate(struct clk_hw *hw,
4216f3b1558SSergio Paracuellos 					    unsigned long xtal_clk)
4226f3b1558SSergio Paracuellos {
4236f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
4246f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
4256f3b1558SSergio Paracuellos 	u32 t;
4266f3b1558SSergio Paracuellos 
4276f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
4286f3b1558SSergio Paracuellos 	t = (t >> RT3352_SYSCFG0_CPUCLK_SHIFT) & RT3352_SYSCFG0_CPUCLK_MASK;
4296f3b1558SSergio Paracuellos 
4306f3b1558SSergio Paracuellos 	switch (t) {
4316f3b1558SSergio Paracuellos 	case RT3352_SYSCFG0_CPUCLK_LOW:
4326f3b1558SSergio Paracuellos 		return 384000000;
4336f3b1558SSergio Paracuellos 	case RT3352_SYSCFG0_CPUCLK_HIGH:
4346f3b1558SSergio Paracuellos 		return 400000000;
4356f3b1558SSergio Paracuellos 	default:
4366f3b1558SSergio Paracuellos 		BUG();
4376f3b1558SSergio Paracuellos 	}
4386f3b1558SSergio Paracuellos }
4396f3b1558SSergio Paracuellos 
rt305x_cpu_recalc_rate(struct clk_hw * hw,unsigned long xtal_clk)4406f3b1558SSergio Paracuellos static unsigned long rt305x_cpu_recalc_rate(struct clk_hw *hw,
4416f3b1558SSergio Paracuellos 					    unsigned long xtal_clk)
4426f3b1558SSergio Paracuellos {
4436f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
4446f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
4456f3b1558SSergio Paracuellos 	u32 t;
4466f3b1558SSergio Paracuellos 
4476f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
4486f3b1558SSergio Paracuellos 	t = (t >> RT305X_SYSCFG_CPUCLK_SHIFT) & RT305X_SYSCFG_CPUCLK_MASK;
4496f3b1558SSergio Paracuellos 
4506f3b1558SSergio Paracuellos 	switch (t) {
4516f3b1558SSergio Paracuellos 	case RT305X_SYSCFG_CPUCLK_LOW:
4526f3b1558SSergio Paracuellos 		return 320000000;
4536f3b1558SSergio Paracuellos 	case RT305X_SYSCFG_CPUCLK_HIGH:
4546f3b1558SSergio Paracuellos 		return 384000000;
4556f3b1558SSergio Paracuellos 	default:
4566f3b1558SSergio Paracuellos 		BUG();
4576f3b1558SSergio Paracuellos 	}
4586f3b1558SSergio Paracuellos }
4596f3b1558SSergio Paracuellos 
rt3883_cpu_recalc_rate(struct clk_hw * hw,unsigned long xtal_clk)4606f3b1558SSergio Paracuellos static unsigned long rt3883_cpu_recalc_rate(struct clk_hw *hw,
4616f3b1558SSergio Paracuellos 					    unsigned long xtal_clk)
4626f3b1558SSergio Paracuellos {
4636f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
4646f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
4656f3b1558SSergio Paracuellos 	u32 t;
4666f3b1558SSergio Paracuellos 
4676f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
4686f3b1558SSergio Paracuellos 	t = (t >> RT3883_SYSCFG0_CPUCLK_SHIFT) & RT3883_SYSCFG0_CPUCLK_MASK;
4696f3b1558SSergio Paracuellos 
4706f3b1558SSergio Paracuellos 	switch (t) {
4716f3b1558SSergio Paracuellos 	case RT3883_SYSCFG0_CPUCLK_250:
4726f3b1558SSergio Paracuellos 		return 250000000;
4736f3b1558SSergio Paracuellos 	case RT3883_SYSCFG0_CPUCLK_384:
4746f3b1558SSergio Paracuellos 		return 384000000;
4756f3b1558SSergio Paracuellos 	case RT3883_SYSCFG0_CPUCLK_480:
4766f3b1558SSergio Paracuellos 		return 480000000;
4776f3b1558SSergio Paracuellos 	case RT3883_SYSCFG0_CPUCLK_500:
4786f3b1558SSergio Paracuellos 		return 500000000;
4796f3b1558SSergio Paracuellos 	default:
4806f3b1558SSergio Paracuellos 		BUG();
4816f3b1558SSergio Paracuellos 	}
4826f3b1558SSergio Paracuellos }
4836f3b1558SSergio Paracuellos 
rt3883_bus_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)4846f3b1558SSergio Paracuellos static unsigned long rt3883_bus_recalc_rate(struct clk_hw *hw,
4856f3b1558SSergio Paracuellos 					    unsigned long parent_rate)
4866f3b1558SSergio Paracuellos {
4876f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
4886f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
4896f3b1558SSergio Paracuellos 	u32 ddr2;
4906f3b1558SSergio Paracuellos 	u32 t;
4916f3b1558SSergio Paracuellos 
4926f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
4936f3b1558SSergio Paracuellos 	ddr2 = t & RT3883_SYSCFG0_DRAM_TYPE_DDR2;
4946f3b1558SSergio Paracuellos 
4956f3b1558SSergio Paracuellos 	switch (parent_rate) {
4966f3b1558SSergio Paracuellos 	case 250000000:
4976f3b1558SSergio Paracuellos 		return (ddr2) ? 125000000 : 83000000;
4986f3b1558SSergio Paracuellos 	case 384000000:
4996f3b1558SSergio Paracuellos 		return (ddr2) ? 128000000 : 96000000;
5006f3b1558SSergio Paracuellos 	case 480000000:
5016f3b1558SSergio Paracuellos 		return (ddr2) ? 160000000 : 120000000;
5026f3b1558SSergio Paracuellos 	case 500000000:
5036f3b1558SSergio Paracuellos 		return (ddr2) ? 166000000 : 125000000;
5046f3b1558SSergio Paracuellos 	default:
5056f3b1558SSergio Paracuellos 		WARN_ON_ONCE(parent_rate == 0);
5066f3b1558SSergio Paracuellos 		return parent_rate / 4;
5076f3b1558SSergio Paracuellos 	}
5086f3b1558SSergio Paracuellos }
5096f3b1558SSergio Paracuellos 
rt2880_cpu_recalc_rate(struct clk_hw * hw,unsigned long xtal_clk)5106f3b1558SSergio Paracuellos static unsigned long rt2880_cpu_recalc_rate(struct clk_hw *hw,
5116f3b1558SSergio Paracuellos 					    unsigned long xtal_clk)
5126f3b1558SSergio Paracuellos {
5136f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
5146f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
5156f3b1558SSergio Paracuellos 	u32 t;
5166f3b1558SSergio Paracuellos 
5176f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
5186f3b1558SSergio Paracuellos 	t = (t >> RT2880_CONFIG_CPUCLK_SHIFT) & RT2880_CONFIG_CPUCLK_MASK;
5196f3b1558SSergio Paracuellos 
5206f3b1558SSergio Paracuellos 	switch (t) {
5216f3b1558SSergio Paracuellos 	case RT2880_CONFIG_CPUCLK_250:
5226f3b1558SSergio Paracuellos 		return 250000000;
5236f3b1558SSergio Paracuellos 	case RT2880_CONFIG_CPUCLK_266:
5246f3b1558SSergio Paracuellos 		return 266000000;
5256f3b1558SSergio Paracuellos 	case RT2880_CONFIG_CPUCLK_280:
5266f3b1558SSergio Paracuellos 		return 280000000;
5276f3b1558SSergio Paracuellos 	case RT2880_CONFIG_CPUCLK_300:
5286f3b1558SSergio Paracuellos 		return 300000000;
5296f3b1558SSergio Paracuellos 	default:
5306f3b1558SSergio Paracuellos 		BUG();
5316f3b1558SSergio Paracuellos 	}
5326f3b1558SSergio Paracuellos }
5336f3b1558SSergio Paracuellos 
mt7620_calc_rate(u32 ref_rate,u32 mul,u32 div)5346f3b1558SSergio Paracuellos static u32 mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div)
5356f3b1558SSergio Paracuellos {
5366f3b1558SSergio Paracuellos 	u64 t;
5376f3b1558SSergio Paracuellos 
5386f3b1558SSergio Paracuellos 	t = ref_rate;
5396f3b1558SSergio Paracuellos 	t *= mul;
5406f3b1558SSergio Paracuellos 	t = div_u64(t, div);
5416f3b1558SSergio Paracuellos 
5426f3b1558SSergio Paracuellos 	return t;
5436f3b1558SSergio Paracuellos }
5446f3b1558SSergio Paracuellos 
mt7620_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)5456f3b1558SSergio Paracuellos static unsigned long mt7620_pll_recalc_rate(struct clk_hw *hw,
5466f3b1558SSergio Paracuellos 					    unsigned long parent_rate)
5476f3b1558SSergio Paracuellos {
5486f3b1558SSergio Paracuellos 	static const u32 clk_divider[] = { 2, 3, 4, 8 };
5496f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
5506f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
5516f3b1558SSergio Paracuellos 	unsigned long cpu_pll;
5526f3b1558SSergio Paracuellos 	u32 t;
5536f3b1558SSergio Paracuellos 	u32 mul;
5546f3b1558SSergio Paracuellos 	u32 div;
5556f3b1558SSergio Paracuellos 
5566f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_CPLL_CONFIG0, &t);
5576f3b1558SSergio Paracuellos 	if (t & CPLL_CFG0_BYPASS_REF_CLK) {
5586f3b1558SSergio Paracuellos 		cpu_pll = parent_rate;
5596f3b1558SSergio Paracuellos 	} else if ((t & CPLL_CFG0_SW_CFG) == 0) {
5606f3b1558SSergio Paracuellos 		cpu_pll = 600000000;
5616f3b1558SSergio Paracuellos 	} else {
5626f3b1558SSergio Paracuellos 		mul = (t >> CPLL_CFG0_PLL_MULT_RATIO_SHIFT) &
5636f3b1558SSergio Paracuellos 			CPLL_CFG0_PLL_MULT_RATIO_MASK;
5646f3b1558SSergio Paracuellos 		mul += 24;
5656f3b1558SSergio Paracuellos 		if (t & CPLL_CFG0_LC_CURFCK)
5666f3b1558SSergio Paracuellos 			mul *= 2;
5676f3b1558SSergio Paracuellos 
5686f3b1558SSergio Paracuellos 		div = (t >> CPLL_CFG0_PLL_DIV_RATIO_SHIFT) &
5696f3b1558SSergio Paracuellos 			CPLL_CFG0_PLL_DIV_RATIO_MASK;
5706f3b1558SSergio Paracuellos 
5716f3b1558SSergio Paracuellos 		WARN_ON_ONCE(div >= ARRAY_SIZE(clk_divider));
5726f3b1558SSergio Paracuellos 
5736f3b1558SSergio Paracuellos 		cpu_pll = mt7620_calc_rate(parent_rate, mul, clk_divider[div]);
5746f3b1558SSergio Paracuellos 	}
5756f3b1558SSergio Paracuellos 
5766f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_CPLL_CONFIG1, &t);
5776f3b1558SSergio Paracuellos 	if (t & CPLL_CFG1_CPU_AUX1)
5786f3b1558SSergio Paracuellos 		return parent_rate;
5796f3b1558SSergio Paracuellos 
5806f3b1558SSergio Paracuellos 	if (t & CPLL_CFG1_CPU_AUX0)
5816f3b1558SSergio Paracuellos 		return 480000000;
5826f3b1558SSergio Paracuellos 
5836f3b1558SSergio Paracuellos 	return cpu_pll;
5846f3b1558SSergio Paracuellos }
5856f3b1558SSergio Paracuellos 
mt7620_cpu_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)5866f3b1558SSergio Paracuellos static unsigned long mt7620_cpu_recalc_rate(struct clk_hw *hw,
5876f3b1558SSergio Paracuellos 					    unsigned long parent_rate)
5886f3b1558SSergio Paracuellos {
5896f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
5906f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
5916f3b1558SSergio Paracuellos 	u32 t;
5926f3b1558SSergio Paracuellos 	u32 mul;
5936f3b1558SSergio Paracuellos 	u32 div;
5946f3b1558SSergio Paracuellos 
5956f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
5966f3b1558SSergio Paracuellos 	mul = t & CPU_SYS_CLKCFG_CPU_FFRAC_MASK;
5976f3b1558SSergio Paracuellos 	div = (t >> CPU_SYS_CLKCFG_CPU_FDIV_SHIFT) &
5986f3b1558SSergio Paracuellos 		CPU_SYS_CLKCFG_CPU_FDIV_MASK;
5996f3b1558SSergio Paracuellos 
6006f3b1558SSergio Paracuellos 	return mt7620_calc_rate(parent_rate, mul, div);
6016f3b1558SSergio Paracuellos }
6026f3b1558SSergio Paracuellos 
mt7620_bus_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)6036f3b1558SSergio Paracuellos static unsigned long mt7620_bus_recalc_rate(struct clk_hw *hw,
6046f3b1558SSergio Paracuellos 					    unsigned long parent_rate)
6056f3b1558SSergio Paracuellos {
6066f3b1558SSergio Paracuellos 	static const u32 ocp_dividers[16] = {
6076f3b1558SSergio Paracuellos 		[CPU_SYS_CLKCFG_OCP_RATIO_2] = 2,
6086f3b1558SSergio Paracuellos 		[CPU_SYS_CLKCFG_OCP_RATIO_3] = 3,
6096f3b1558SSergio Paracuellos 		[CPU_SYS_CLKCFG_OCP_RATIO_4] = 4,
6106f3b1558SSergio Paracuellos 		[CPU_SYS_CLKCFG_OCP_RATIO_5] = 5,
6116f3b1558SSergio Paracuellos 		[CPU_SYS_CLKCFG_OCP_RATIO_10] = 10,
6126f3b1558SSergio Paracuellos 	};
6136f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
6146f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
6156f3b1558SSergio Paracuellos 	u32 t;
6166f3b1558SSergio Paracuellos 	u32 ocp_ratio;
6176f3b1558SSergio Paracuellos 	u32 div;
6186f3b1558SSergio Paracuellos 
6196f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
6206f3b1558SSergio Paracuellos 	ocp_ratio = (t >> CPU_SYS_CLKCFG_OCP_RATIO_SHIFT) &
6216f3b1558SSergio Paracuellos 		CPU_SYS_CLKCFG_OCP_RATIO_MASK;
6226f3b1558SSergio Paracuellos 
6236f3b1558SSergio Paracuellos 	if (WARN_ON_ONCE(ocp_ratio >= ARRAY_SIZE(ocp_dividers)))
6246f3b1558SSergio Paracuellos 		return parent_rate;
6256f3b1558SSergio Paracuellos 
6266f3b1558SSergio Paracuellos 	div = ocp_dividers[ocp_ratio];
6276f3b1558SSergio Paracuellos 
6286f3b1558SSergio Paracuellos 	if (WARN(!div, "invalid divider for OCP ratio %u", ocp_ratio))
6296f3b1558SSergio Paracuellos 		return parent_rate;
6306f3b1558SSergio Paracuellos 
6316f3b1558SSergio Paracuellos 	return parent_rate / div;
6326f3b1558SSergio Paracuellos }
6336f3b1558SSergio Paracuellos 
mt7620_periph_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)6346f3b1558SSergio Paracuellos static unsigned long mt7620_periph_recalc_rate(struct clk_hw *hw,
6356f3b1558SSergio Paracuellos 					       unsigned long parent_rate)
6366f3b1558SSergio Paracuellos {
6376f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
6386f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
6396f3b1558SSergio Paracuellos 	u32 t;
6406f3b1558SSergio Paracuellos 
6416f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_CLKCFG0, &t);
6426f3b1558SSergio Paracuellos 	if (t & CLKCFG0_PERI_CLK_SEL)
6436f3b1558SSergio Paracuellos 		return parent_rate;
6446f3b1558SSergio Paracuellos 
6456f3b1558SSergio Paracuellos 	return 40000000;
6466f3b1558SSergio Paracuellos }
6476f3b1558SSergio Paracuellos 
mt76x8_xtal_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)6486f3b1558SSergio Paracuellos static unsigned long mt76x8_xtal_recalc_rate(struct clk_hw *hw,
6496f3b1558SSergio Paracuellos 					     unsigned long parent_rate)
6506f3b1558SSergio Paracuellos {
6516f3b1558SSergio Paracuellos 	struct mtmips_clk *clk = to_mtmips_clk(hw);
6526f3b1558SSergio Paracuellos 	struct regmap *sysc = clk->priv->sysc;
6536f3b1558SSergio Paracuellos 	u32 t;
6546f3b1558SSergio Paracuellos 
6556f3b1558SSergio Paracuellos 	regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
6566f3b1558SSergio Paracuellos 	if (t & MT7620_XTAL_FREQ_SEL)
6576f3b1558SSergio Paracuellos 		return 40000000;
6586f3b1558SSergio Paracuellos 
6596f3b1558SSergio Paracuellos 	return 20000000;
6606f3b1558SSergio Paracuellos }
6616f3b1558SSergio Paracuellos 
mt76x8_cpu_recalc_rate(struct clk_hw * hw,unsigned long xtal_clk)6626f3b1558SSergio Paracuellos static unsigned long mt76x8_cpu_recalc_rate(struct clk_hw *hw,
6636f3b1558SSergio Paracuellos 					    unsigned long xtal_clk)
6646f3b1558SSergio Paracuellos {
6656f3b1558SSergio Paracuellos 	if (xtal_clk == 40000000)
6666f3b1558SSergio Paracuellos 		return 580000000;
6676f3b1558SSergio Paracuellos 
6686f3b1558SSergio Paracuellos 	return 575000000;
6696f3b1558SSergio Paracuellos }
6706f3b1558SSergio Paracuellos 
6716f3b1558SSergio Paracuellos #define CLK_BASE(_name, _parent, _recalc) {				\
6726f3b1558SSergio Paracuellos 	.init = &(const struct clk_init_data) {				\
6736f3b1558SSergio Paracuellos 		.name = _name,						\
6746f3b1558SSergio Paracuellos 		.ops = &(const struct clk_ops) {			\
6756f3b1558SSergio Paracuellos 			.recalc_rate = _recalc,				\
6766f3b1558SSergio Paracuellos 		},							\
6776f3b1558SSergio Paracuellos 		.parent_data = &(const struct clk_parent_data) {	\
6786f3b1558SSergio Paracuellos 			.name = _parent,				\
6796f3b1558SSergio Paracuellos 			.fw_name = _parent				\
6806f3b1558SSergio Paracuellos 		},							\
6816f3b1558SSergio Paracuellos 		.num_parents = _parent ? 1 : 0				\
6826f3b1558SSergio Paracuellos 	},								\
6836f3b1558SSergio Paracuellos }
6846f3b1558SSergio Paracuellos 
6856f3b1558SSergio Paracuellos static struct mtmips_clk rt2880_clks_base[] = {
686*fbb13732SSergio Paracuellos 	{ CLK_BASE("xtal", NULL, rt2880_xtal_recalc_rate) },
6876f3b1558SSergio Paracuellos 	{ CLK_BASE("cpu", "xtal", rt2880_cpu_recalc_rate) }
6886f3b1558SSergio Paracuellos };
6896f3b1558SSergio Paracuellos 
6906f3b1558SSergio Paracuellos static struct mtmips_clk rt305x_clks_base[] = {
691*fbb13732SSergio Paracuellos 	{ CLK_BASE("xtal", NULL, rt2880_xtal_recalc_rate) },
6926f3b1558SSergio Paracuellos 	{ CLK_BASE("cpu", "xtal", rt305x_cpu_recalc_rate) }
6936f3b1558SSergio Paracuellos };
6946f3b1558SSergio Paracuellos 
6956f3b1558SSergio Paracuellos static struct mtmips_clk rt3352_clks_base[] = {
6966f3b1558SSergio Paracuellos 	{ CLK_BASE("xtal", NULL, rt5350_xtal_recalc_rate) },
6976f3b1558SSergio Paracuellos 	{ CLK_BASE("cpu", "xtal", rt3352_cpu_recalc_rate) }
6986f3b1558SSergio Paracuellos };
6996f3b1558SSergio Paracuellos 
7006f3b1558SSergio Paracuellos static struct mtmips_clk rt3883_clks_base[] = {
701*fbb13732SSergio Paracuellos 	{ CLK_BASE("xtal", NULL, rt2880_xtal_recalc_rate) },
7026f3b1558SSergio Paracuellos 	{ CLK_BASE("cpu", "xtal", rt3883_cpu_recalc_rate) },
7036f3b1558SSergio Paracuellos 	{ CLK_BASE("bus", "cpu", rt3883_bus_recalc_rate) }
7046f3b1558SSergio Paracuellos };
7056f3b1558SSergio Paracuellos 
7066f3b1558SSergio Paracuellos static struct mtmips_clk rt5350_clks_base[] = {
7076f3b1558SSergio Paracuellos 	{ CLK_BASE("xtal", NULL, rt5350_xtal_recalc_rate) },
7086f3b1558SSergio Paracuellos 	{ CLK_BASE("cpu", "xtal", rt5350_cpu_recalc_rate) },
7096f3b1558SSergio Paracuellos 	{ CLK_BASE("bus", "cpu", rt5350_bus_recalc_rate) }
7106f3b1558SSergio Paracuellos };
7116f3b1558SSergio Paracuellos 
7126f3b1558SSergio Paracuellos static struct mtmips_clk mt7620_clks_base[] = {
7136f3b1558SSergio Paracuellos 	{ CLK_BASE("xtal", NULL, mt76x8_xtal_recalc_rate) },
7146f3b1558SSergio Paracuellos 	{ CLK_BASE("pll", "xtal", mt7620_pll_recalc_rate) },
7156f3b1558SSergio Paracuellos 	{ CLK_BASE("cpu", "pll", mt7620_cpu_recalc_rate) },
7166f3b1558SSergio Paracuellos 	{ CLK_BASE("periph", "xtal", mt7620_periph_recalc_rate) },
7176f3b1558SSergio Paracuellos 	{ CLK_BASE("bus", "cpu", mt7620_bus_recalc_rate) }
7186f3b1558SSergio Paracuellos };
7196f3b1558SSergio Paracuellos 
7206f3b1558SSergio Paracuellos static struct mtmips_clk mt76x8_clks_base[] = {
7216f3b1558SSergio Paracuellos 	{ CLK_BASE("xtal", NULL, mt76x8_xtal_recalc_rate) },
7226f3b1558SSergio Paracuellos 	{ CLK_BASE("cpu", "xtal", mt76x8_cpu_recalc_rate) }
7236f3b1558SSergio Paracuellos };
7246f3b1558SSergio Paracuellos 
mtmips_register_clocks(struct device_node * np,struct clk_hw_onecell_data * clk_data,struct mtmips_clk_priv * priv)7256f3b1558SSergio Paracuellos static int mtmips_register_clocks(struct device_node *np,
7266f3b1558SSergio Paracuellos 				  struct clk_hw_onecell_data *clk_data,
7276f3b1558SSergio Paracuellos 				  struct mtmips_clk_priv *priv)
7286f3b1558SSergio Paracuellos {
7296f3b1558SSergio Paracuellos 	struct clk_hw **hws = clk_data->hws;
7306f3b1558SSergio Paracuellos 	struct mtmips_clk *sclk;
7316f3b1558SSergio Paracuellos 	int ret, i;
7326f3b1558SSergio Paracuellos 
7336f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_base; i++) {
7346f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_base[i];
7356f3b1558SSergio Paracuellos 		sclk->priv = priv;
7366f3b1558SSergio Paracuellos 		ret = of_clk_hw_register(np, &sclk->hw);
7376f3b1558SSergio Paracuellos 		if (ret) {
7386f3b1558SSergio Paracuellos 			pr_err("Couldn't register top clock %i\n", i);
7396f3b1558SSergio Paracuellos 			goto err_clk_unreg;
7406f3b1558SSergio Paracuellos 		}
7416f3b1558SSergio Paracuellos 
7426f3b1558SSergio Paracuellos 		hws[i] = &sclk->hw;
7436f3b1558SSergio Paracuellos 	}
7446f3b1558SSergio Paracuellos 
7456f3b1558SSergio Paracuellos 	return 0;
7466f3b1558SSergio Paracuellos 
7476f3b1558SSergio Paracuellos err_clk_unreg:
7486f3b1558SSergio Paracuellos 	while (--i >= 0) {
7496f3b1558SSergio Paracuellos 		sclk = &priv->data->clk_base[i];
7506f3b1558SSergio Paracuellos 		clk_hw_unregister(&sclk->hw);
7516f3b1558SSergio Paracuellos 	}
7526f3b1558SSergio Paracuellos 	return ret;
7536f3b1558SSergio Paracuellos }
7546f3b1558SSergio Paracuellos 
7556f3b1558SSergio Paracuellos static const struct mtmips_clk_data rt2880_clk_data = {
7566f3b1558SSergio Paracuellos 	.clk_base = rt2880_clks_base,
7576f3b1558SSergio Paracuellos 	.num_clk_base = ARRAY_SIZE(rt2880_clks_base),
758*fbb13732SSergio Paracuellos 	.clk_fixed = NULL,
759*fbb13732SSergio Paracuellos 	.num_clk_fixed = 0,
7606f3b1558SSergio Paracuellos 	.clk_factor = rt2880_factor_clocks,
7616f3b1558SSergio Paracuellos 	.num_clk_factor = ARRAY_SIZE(rt2880_factor_clocks),
7626f3b1558SSergio Paracuellos 	.clk_periph = rt2880_pherip_clks,
7636f3b1558SSergio Paracuellos 	.num_clk_periph = ARRAY_SIZE(rt2880_pherip_clks),
7646f3b1558SSergio Paracuellos };
7656f3b1558SSergio Paracuellos 
7666f3b1558SSergio Paracuellos static const struct mtmips_clk_data rt305x_clk_data = {
7676f3b1558SSergio Paracuellos 	.clk_base = rt305x_clks_base,
7686f3b1558SSergio Paracuellos 	.num_clk_base = ARRAY_SIZE(rt305x_clks_base),
769*fbb13732SSergio Paracuellos 	.clk_fixed = NULL,
770*fbb13732SSergio Paracuellos 	.num_clk_fixed = 0,
7716f3b1558SSergio Paracuellos 	.clk_factor = rt305x_factor_clocks,
7726f3b1558SSergio Paracuellos 	.num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks),
7736f3b1558SSergio Paracuellos 	.clk_periph = rt305x_pherip_clks,
7746f3b1558SSergio Paracuellos 	.num_clk_periph = ARRAY_SIZE(rt305x_pherip_clks),
7756f3b1558SSergio Paracuellos };
7766f3b1558SSergio Paracuellos 
7776f3b1558SSergio Paracuellos static const struct mtmips_clk_data rt3352_clk_data = {
7786f3b1558SSergio Paracuellos 	.clk_base = rt3352_clks_base,
7796f3b1558SSergio Paracuellos 	.num_clk_base = ARRAY_SIZE(rt3352_clks_base),
7806f3b1558SSergio Paracuellos 	.clk_fixed = rt3352_fixed_clocks,
7816f3b1558SSergio Paracuellos 	.num_clk_fixed = ARRAY_SIZE(rt3352_fixed_clocks),
7826f3b1558SSergio Paracuellos 	.clk_factor = rt305x_factor_clocks,
7836f3b1558SSergio Paracuellos 	.num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks),
7846f3b1558SSergio Paracuellos 	.clk_periph = rt5350_pherip_clks,
7856f3b1558SSergio Paracuellos 	.num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks),
7866f3b1558SSergio Paracuellos };
7876f3b1558SSergio Paracuellos 
7886f3b1558SSergio Paracuellos static const struct mtmips_clk_data rt3883_clk_data = {
7896f3b1558SSergio Paracuellos 	.clk_base = rt3883_clks_base,
7906f3b1558SSergio Paracuellos 	.num_clk_base = ARRAY_SIZE(rt3883_clks_base),
791f85a1d06SSergio Paracuellos 	.clk_fixed = rt3883_fixed_clocks,
792f85a1d06SSergio Paracuellos 	.num_clk_fixed = ARRAY_SIZE(rt3883_fixed_clocks),
7936f3b1558SSergio Paracuellos 	.clk_factor = NULL,
7946f3b1558SSergio Paracuellos 	.num_clk_factor = 0,
7956f3b1558SSergio Paracuellos 	.clk_periph = rt5350_pherip_clks,
7966f3b1558SSergio Paracuellos 	.num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks),
7976f3b1558SSergio Paracuellos };
7986f3b1558SSergio Paracuellos 
7996f3b1558SSergio Paracuellos static const struct mtmips_clk_data rt5350_clk_data = {
8006f3b1558SSergio Paracuellos 	.clk_base = rt5350_clks_base,
8016f3b1558SSergio Paracuellos 	.num_clk_base = ARRAY_SIZE(rt5350_clks_base),
8026f3b1558SSergio Paracuellos 	.clk_fixed = rt3352_fixed_clocks,
8036f3b1558SSergio Paracuellos 	.num_clk_fixed = ARRAY_SIZE(rt3352_fixed_clocks),
8046f3b1558SSergio Paracuellos 	.clk_factor = NULL,
8056f3b1558SSergio Paracuellos 	.num_clk_factor = 0,
8066f3b1558SSergio Paracuellos 	.clk_periph = rt5350_pherip_clks,
8076f3b1558SSergio Paracuellos 	.num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks),
8086f3b1558SSergio Paracuellos };
8096f3b1558SSergio Paracuellos 
8106f3b1558SSergio Paracuellos static const struct mtmips_clk_data mt7620_clk_data = {
8116f3b1558SSergio Paracuellos 	.clk_base = mt7620_clks_base,
8126f3b1558SSergio Paracuellos 	.num_clk_base = ARRAY_SIZE(mt7620_clks_base),
8136f3b1558SSergio Paracuellos 	.clk_fixed = NULL,
8146f3b1558SSergio Paracuellos 	.num_clk_fixed = 0,
8156f3b1558SSergio Paracuellos 	.clk_factor = NULL,
8166f3b1558SSergio Paracuellos 	.num_clk_factor = 0,
8176f3b1558SSergio Paracuellos 	.clk_periph = mt7620_pherip_clks,
8186f3b1558SSergio Paracuellos 	.num_clk_periph = ARRAY_SIZE(mt7620_pherip_clks),
8196f3b1558SSergio Paracuellos };
8206f3b1558SSergio Paracuellos 
8216f3b1558SSergio Paracuellos static const struct mtmips_clk_data mt76x8_clk_data = {
8226f3b1558SSergio Paracuellos 	.clk_base = mt76x8_clks_base,
8236f3b1558SSergio Paracuellos 	.num_clk_base = ARRAY_SIZE(mt76x8_clks_base),
8246f3b1558SSergio Paracuellos 	.clk_fixed = mt76x8_fixed_clocks,
8256f3b1558SSergio Paracuellos 	.num_clk_fixed = ARRAY_SIZE(mt76x8_fixed_clocks),
8266f3b1558SSergio Paracuellos 	.clk_factor = rt305x_factor_clocks,
8276f3b1558SSergio Paracuellos 	.num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks),
8286f3b1558SSergio Paracuellos 	.clk_periph = mt76x8_pherip_clks,
8296f3b1558SSergio Paracuellos 	.num_clk_periph = ARRAY_SIZE(mt76x8_pherip_clks),
8306f3b1558SSergio Paracuellos };
8316f3b1558SSergio Paracuellos 
8326f3b1558SSergio Paracuellos static const struct of_device_id mtmips_of_match[] = {
8336f3b1558SSergio Paracuellos 	{
8343634faabSSergio Paracuellos 		.compatible = "ralink,rt2880-reset",
8353634faabSSergio Paracuellos 		.data = NULL,
8363634faabSSergio Paracuellos 	},
8373634faabSSergio Paracuellos 	{
8386f3b1558SSergio Paracuellos 		.compatible = "ralink,rt2880-sysc",
8396f3b1558SSergio Paracuellos 		.data = &rt2880_clk_data,
8406f3b1558SSergio Paracuellos 	},
8416f3b1558SSergio Paracuellos 	{
8426f3b1558SSergio Paracuellos 		.compatible = "ralink,rt3050-sysc",
8436f3b1558SSergio Paracuellos 		.data = &rt305x_clk_data,
8446f3b1558SSergio Paracuellos 	},
8456f3b1558SSergio Paracuellos 	{
8466f3b1558SSergio Paracuellos 		.compatible = "ralink,rt3052-sysc",
8476f3b1558SSergio Paracuellos 		.data = &rt305x_clk_data,
8486f3b1558SSergio Paracuellos 	},
8496f3b1558SSergio Paracuellos 	{
8506f3b1558SSergio Paracuellos 		.compatible = "ralink,rt3352-sysc",
8516f3b1558SSergio Paracuellos 		.data = &rt3352_clk_data,
8526f3b1558SSergio Paracuellos 	},
8536f3b1558SSergio Paracuellos 	{
8546f3b1558SSergio Paracuellos 		.compatible = "ralink,rt3883-sysc",
8556f3b1558SSergio Paracuellos 		.data = &rt3883_clk_data,
8566f3b1558SSergio Paracuellos 	},
8576f3b1558SSergio Paracuellos 	{
8586f3b1558SSergio Paracuellos 		.compatible = "ralink,rt5350-sysc",
8596f3b1558SSergio Paracuellos 		.data = &rt5350_clk_data,
8606f3b1558SSergio Paracuellos 	},
8616f3b1558SSergio Paracuellos 	{
8626f3b1558SSergio Paracuellos 		.compatible = "ralink,mt7620-sysc",
8636f3b1558SSergio Paracuellos 		.data = &mt7620_clk_data,
8646f3b1558SSergio Paracuellos 	},
8656f3b1558SSergio Paracuellos 	{
8666f3b1558SSergio Paracuellos 		.compatible = "ralink,mt7628-sysc",
8676f3b1558SSergio Paracuellos 		.data = &mt76x8_clk_data,
8686f3b1558SSergio Paracuellos 	},
8696f3b1558SSergio Paracuellos 	{
8706f3b1558SSergio Paracuellos 		.compatible = "ralink,mt7688-sysc",
8716f3b1558SSergio Paracuellos 		.data = &mt76x8_clk_data,
8726f3b1558SSergio Paracuellos 	},
8736f3b1558SSergio Paracuellos 	{}
8746f3b1558SSergio Paracuellos };
8756f3b1558SSergio Paracuellos 
mtmips_clk_regs_init(struct device_node * node,struct mtmips_clk_priv * priv)8766f3b1558SSergio Paracuellos static void __init mtmips_clk_regs_init(struct device_node *node,
8776f3b1558SSergio Paracuellos 					struct mtmips_clk_priv *priv)
8786f3b1558SSergio Paracuellos {
8796f3b1558SSergio Paracuellos 	u32 t;
8806f3b1558SSergio Paracuellos 
8816f3b1558SSergio Paracuellos 	if (!of_device_is_compatible(node, "ralink,mt7620-sysc"))
8826f3b1558SSergio Paracuellos 		return;
8836f3b1558SSergio Paracuellos 
8846f3b1558SSergio Paracuellos 	/*
8856f3b1558SSergio Paracuellos 	 * When the CPU goes into sleep mode, the BUS
8866f3b1558SSergio Paracuellos 	 * clock will be too low for USB to function properly.
8876f3b1558SSergio Paracuellos 	 * Adjust the busses fractional divider to fix this
8886f3b1558SSergio Paracuellos 	 */
8896f3b1558SSergio Paracuellos 	regmap_read(priv->sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
8906f3b1558SSergio Paracuellos 	t &= ~(CLKCFG_FDIV_MASK | CLKCFG_FFRAC_MASK);
8916f3b1558SSergio Paracuellos 	t |= CLKCFG_FDIV_USB_VAL | CLKCFG_FFRAC_USB_VAL;
8926f3b1558SSergio Paracuellos 	regmap_write(priv->sysc, SYSC_REG_CPU_SYS_CLKCFG, t);
8936f3b1558SSergio Paracuellos }
8946f3b1558SSergio Paracuellos 
mtmips_clk_init(struct device_node * node)8956f3b1558SSergio Paracuellos static void __init mtmips_clk_init(struct device_node *node)
8966f3b1558SSergio Paracuellos {
8976f3b1558SSergio Paracuellos 	const struct of_device_id *match;
8986f3b1558SSergio Paracuellos 	const struct mtmips_clk_data *data;
8996f3b1558SSergio Paracuellos 	struct mtmips_clk_priv *priv;
9006f3b1558SSergio Paracuellos 	struct clk_hw_onecell_data *clk_data;
9016f3b1558SSergio Paracuellos 	int ret, i, count;
9026f3b1558SSergio Paracuellos 
9036f3b1558SSergio Paracuellos 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
9046f3b1558SSergio Paracuellos 	if (!priv)
9056f3b1558SSergio Paracuellos 		return;
9066f3b1558SSergio Paracuellos 
9076f3b1558SSergio Paracuellos 	priv->sysc = syscon_node_to_regmap(node);
9086f3b1558SSergio Paracuellos 	if (IS_ERR(priv->sysc)) {
9096f3b1558SSergio Paracuellos 		pr_err("Could not get sysc syscon regmap\n");
9106f3b1558SSergio Paracuellos 		goto free_clk_priv;
9116f3b1558SSergio Paracuellos 	}
9126f3b1558SSergio Paracuellos 
9136f3b1558SSergio Paracuellos 	mtmips_clk_regs_init(node, priv);
9146f3b1558SSergio Paracuellos 
9156f3b1558SSergio Paracuellos 	match = of_match_node(mtmips_of_match, node);
9166f3b1558SSergio Paracuellos 	if (WARN_ON(!match))
9176f3b1558SSergio Paracuellos 		return;
9186f3b1558SSergio Paracuellos 
9196f3b1558SSergio Paracuellos 	data = match->data;
9206f3b1558SSergio Paracuellos 	priv->data = data;
9216f3b1558SSergio Paracuellos 	count = priv->data->num_clk_base + priv->data->num_clk_fixed +
9226f3b1558SSergio Paracuellos 		priv->data->num_clk_factor + priv->data->num_clk_periph;
9236f3b1558SSergio Paracuellos 	clk_data = kzalloc(struct_size(clk_data, hws, count), GFP_KERNEL);
9246f3b1558SSergio Paracuellos 	if (!clk_data)
9256f3b1558SSergio Paracuellos 		goto free_clk_priv;
9266f3b1558SSergio Paracuellos 
9276f3b1558SSergio Paracuellos 	ret = mtmips_register_clocks(node, clk_data, priv);
9286f3b1558SSergio Paracuellos 	if (ret) {
9296f3b1558SSergio Paracuellos 		pr_err("Couldn't register top clocks\n");
9306f3b1558SSergio Paracuellos 		goto free_clk_data;
9316f3b1558SSergio Paracuellos 	}
9326f3b1558SSergio Paracuellos 
9336f3b1558SSergio Paracuellos 	ret = mtmips_register_fixed_clocks(clk_data, priv);
9346f3b1558SSergio Paracuellos 	if (ret) {
9356f3b1558SSergio Paracuellos 		pr_err("Couldn't register fixed clocks\n");
9366f3b1558SSergio Paracuellos 		goto unreg_clk_top;
9376f3b1558SSergio Paracuellos 	}
9386f3b1558SSergio Paracuellos 
9396f3b1558SSergio Paracuellos 	ret = mtmips_register_factor_clocks(clk_data, priv);
9406f3b1558SSergio Paracuellos 	if (ret) {
9416f3b1558SSergio Paracuellos 		pr_err("Couldn't register factor clocks\n");
9426f3b1558SSergio Paracuellos 		goto unreg_clk_fixed;
9436f3b1558SSergio Paracuellos 	}
9446f3b1558SSergio Paracuellos 
9456f3b1558SSergio Paracuellos 	ret = mtmips_register_pherip_clocks(node, clk_data, priv);
9466f3b1558SSergio Paracuellos 	if (ret) {
9476f3b1558SSergio Paracuellos 		pr_err("Couldn't register peripheral clocks\n");
9486f3b1558SSergio Paracuellos 		goto unreg_clk_factor;
9496f3b1558SSergio Paracuellos 	}
9506f3b1558SSergio Paracuellos 
9516f3b1558SSergio Paracuellos 	clk_data->num = count;
9526f3b1558SSergio Paracuellos 
9536f3b1558SSergio Paracuellos 	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
9546f3b1558SSergio Paracuellos 	if (ret) {
9556f3b1558SSergio Paracuellos 		pr_err("Couldn't add clk hw provider\n");
9566f3b1558SSergio Paracuellos 		goto unreg_clk_periph;
9576f3b1558SSergio Paracuellos 	}
9586f3b1558SSergio Paracuellos 
9596f3b1558SSergio Paracuellos 	return;
9606f3b1558SSergio Paracuellos 
9616f3b1558SSergio Paracuellos unreg_clk_periph:
9626f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_periph; i++) {
9636f3b1558SSergio Paracuellos 		struct mtmips_clk *sclk = &priv->data->clk_periph[i];
9646f3b1558SSergio Paracuellos 
9656f3b1558SSergio Paracuellos 		clk_hw_unregister(&sclk->hw);
9666f3b1558SSergio Paracuellos 	}
9676f3b1558SSergio Paracuellos 
9686f3b1558SSergio Paracuellos unreg_clk_factor:
9696f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_factor; i++) {
9706f3b1558SSergio Paracuellos 		struct mtmips_clk_factor *sclk = &priv->data->clk_factor[i];
9716f3b1558SSergio Paracuellos 
9726f3b1558SSergio Paracuellos 		clk_hw_unregister_fixed_factor(sclk->hw);
9736f3b1558SSergio Paracuellos 	}
9746f3b1558SSergio Paracuellos 
9756f3b1558SSergio Paracuellos unreg_clk_fixed:
9766f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_fixed; i++) {
9776f3b1558SSergio Paracuellos 		struct mtmips_clk_fixed *sclk = &priv->data->clk_fixed[i];
9786f3b1558SSergio Paracuellos 
9796f3b1558SSergio Paracuellos 		clk_hw_unregister_fixed_rate(sclk->hw);
9806f3b1558SSergio Paracuellos 	}
9816f3b1558SSergio Paracuellos 
9826f3b1558SSergio Paracuellos unreg_clk_top:
9836f3b1558SSergio Paracuellos 	for (i = 0; i < priv->data->num_clk_base; i++) {
9846f3b1558SSergio Paracuellos 		struct mtmips_clk *sclk = &priv->data->clk_base[i];
9856f3b1558SSergio Paracuellos 
9866f3b1558SSergio Paracuellos 		clk_hw_unregister(&sclk->hw);
9876f3b1558SSergio Paracuellos 	}
9886f3b1558SSergio Paracuellos 
9896f3b1558SSergio Paracuellos free_clk_data:
9906f3b1558SSergio Paracuellos 	kfree(clk_data);
9916f3b1558SSergio Paracuellos 
9926f3b1558SSergio Paracuellos free_clk_priv:
9936f3b1558SSergio Paracuellos 	kfree(priv);
9946f3b1558SSergio Paracuellos }
9956f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(rt2880_clk, "ralink,rt2880-sysc", mtmips_clk_init);
9966f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(rt3050_clk, "ralink,rt3050-sysc", mtmips_clk_init);
9976f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(rt3052_clk, "ralink,rt3052-sysc", mtmips_clk_init);
9986f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(rt3352_clk, "ralink,rt3352-sysc", mtmips_clk_init);
9996f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(rt3883_clk, "ralink,rt3883-sysc", mtmips_clk_init);
10006f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(rt5350_clk, "ralink,rt5350-sysc", mtmips_clk_init);
10016f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(mt7620_clk, "ralink,mt7620-sysc", mtmips_clk_init);
10026f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(mt7628_clk, "ralink,mt7628-sysc", mtmips_clk_init);
10036f3b1558SSergio Paracuellos CLK_OF_DECLARE_DRIVER(mt7688_clk, "ralink,mt7688-sysc", mtmips_clk_init);
10046f3b1558SSergio Paracuellos 
10056f3b1558SSergio Paracuellos struct mtmips_rst {
10066f3b1558SSergio Paracuellos 	struct reset_controller_dev rcdev;
10076f3b1558SSergio Paracuellos 	struct regmap *sysc;
10086f3b1558SSergio Paracuellos };
10096f3b1558SSergio Paracuellos 
to_mtmips_rst(struct reset_controller_dev * dev)10106f3b1558SSergio Paracuellos static struct mtmips_rst *to_mtmips_rst(struct reset_controller_dev *dev)
10116f3b1558SSergio Paracuellos {
10126f3b1558SSergio Paracuellos 	return container_of(dev, struct mtmips_rst, rcdev);
10136f3b1558SSergio Paracuellos }
10146f3b1558SSergio Paracuellos 
mtmips_assert_device(struct reset_controller_dev * rcdev,unsigned long id)10156f3b1558SSergio Paracuellos static int mtmips_assert_device(struct reset_controller_dev *rcdev,
10166f3b1558SSergio Paracuellos 				unsigned long id)
10176f3b1558SSergio Paracuellos {
10186f3b1558SSergio Paracuellos 	struct mtmips_rst *data = to_mtmips_rst(rcdev);
10196f3b1558SSergio Paracuellos 	struct regmap *sysc = data->sysc;
10206f3b1558SSergio Paracuellos 
10216f3b1558SSergio Paracuellos 	return regmap_update_bits(sysc, SYSC_REG_RESET_CTRL, BIT(id), BIT(id));
10226f3b1558SSergio Paracuellos }
10236f3b1558SSergio Paracuellos 
mtmips_deassert_device(struct reset_controller_dev * rcdev,unsigned long id)10246f3b1558SSergio Paracuellos static int mtmips_deassert_device(struct reset_controller_dev *rcdev,
10256f3b1558SSergio Paracuellos 				  unsigned long id)
10266f3b1558SSergio Paracuellos {
10276f3b1558SSergio Paracuellos 	struct mtmips_rst *data = to_mtmips_rst(rcdev);
10286f3b1558SSergio Paracuellos 	struct regmap *sysc = data->sysc;
10296f3b1558SSergio Paracuellos 
10306f3b1558SSergio Paracuellos 	return regmap_update_bits(sysc, SYSC_REG_RESET_CTRL, BIT(id), 0);
10316f3b1558SSergio Paracuellos }
10326f3b1558SSergio Paracuellos 
mtmips_reset_device(struct reset_controller_dev * rcdev,unsigned long id)10336f3b1558SSergio Paracuellos static int mtmips_reset_device(struct reset_controller_dev *rcdev,
10346f3b1558SSergio Paracuellos 			       unsigned long id)
10356f3b1558SSergio Paracuellos {
10366f3b1558SSergio Paracuellos 	int ret;
10376f3b1558SSergio Paracuellos 
10386f3b1558SSergio Paracuellos 	ret = mtmips_assert_device(rcdev, id);
10396f3b1558SSergio Paracuellos 	if (ret < 0)
10406f3b1558SSergio Paracuellos 		return ret;
10416f3b1558SSergio Paracuellos 
10426f3b1558SSergio Paracuellos 	return mtmips_deassert_device(rcdev, id);
10436f3b1558SSergio Paracuellos }
10446f3b1558SSergio Paracuellos 
mtmips_rst_xlate(struct reset_controller_dev * rcdev,const struct of_phandle_args * reset_spec)10456f3b1558SSergio Paracuellos static int mtmips_rst_xlate(struct reset_controller_dev *rcdev,
10466f3b1558SSergio Paracuellos 			    const struct of_phandle_args *reset_spec)
10476f3b1558SSergio Paracuellos {
10486f3b1558SSergio Paracuellos 	unsigned long id = reset_spec->args[0];
10496f3b1558SSergio Paracuellos 
10506f3b1558SSergio Paracuellos 	if (id == 0 || id >= rcdev->nr_resets)
10516f3b1558SSergio Paracuellos 		return -EINVAL;
10526f3b1558SSergio Paracuellos 
10536f3b1558SSergio Paracuellos 	return id;
10546f3b1558SSergio Paracuellos }
10556f3b1558SSergio Paracuellos 
10566f3b1558SSergio Paracuellos static const struct reset_control_ops reset_ops = {
10576f3b1558SSergio Paracuellos 	.reset = mtmips_reset_device,
10586f3b1558SSergio Paracuellos 	.assert = mtmips_assert_device,
10596f3b1558SSergio Paracuellos 	.deassert = mtmips_deassert_device
10606f3b1558SSergio Paracuellos };
10616f3b1558SSergio Paracuellos 
mtmips_reset_init(struct device * dev,struct regmap * sysc)10626f3b1558SSergio Paracuellos static int mtmips_reset_init(struct device *dev, struct regmap *sysc)
10636f3b1558SSergio Paracuellos {
10646f3b1558SSergio Paracuellos 	struct mtmips_rst *rst_data;
10656f3b1558SSergio Paracuellos 
10666f3b1558SSergio Paracuellos 	rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL);
10676f3b1558SSergio Paracuellos 	if (!rst_data)
10686f3b1558SSergio Paracuellos 		return -ENOMEM;
10696f3b1558SSergio Paracuellos 
10706f3b1558SSergio Paracuellos 	rst_data->sysc = sysc;
10716f3b1558SSergio Paracuellos 	rst_data->rcdev.ops = &reset_ops;
10726f3b1558SSergio Paracuellos 	rst_data->rcdev.owner = THIS_MODULE;
10736f3b1558SSergio Paracuellos 	rst_data->rcdev.nr_resets = 32;
10746f3b1558SSergio Paracuellos 	rst_data->rcdev.of_reset_n_cells = 1;
10756f3b1558SSergio Paracuellos 	rst_data->rcdev.of_xlate = mtmips_rst_xlate;
10766f3b1558SSergio Paracuellos 	rst_data->rcdev.of_node = dev_of_node(dev);
10776f3b1558SSergio Paracuellos 
10786f3b1558SSergio Paracuellos 	return devm_reset_controller_register(dev, &rst_data->rcdev);
10796f3b1558SSergio Paracuellos }
10806f3b1558SSergio Paracuellos 
mtmips_clk_probe(struct platform_device * pdev)10816f3b1558SSergio Paracuellos static int mtmips_clk_probe(struct platform_device *pdev)
10826f3b1558SSergio Paracuellos {
10836f3b1558SSergio Paracuellos 	struct device_node *np = pdev->dev.of_node;
10846f3b1558SSergio Paracuellos 	struct device *dev = &pdev->dev;
10856f3b1558SSergio Paracuellos 	struct mtmips_clk_priv *priv;
10866f3b1558SSergio Paracuellos 	int ret;
10876f3b1558SSergio Paracuellos 
10886f3b1558SSergio Paracuellos 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
10896f3b1558SSergio Paracuellos 	if (!priv)
10906f3b1558SSergio Paracuellos 		return -ENOMEM;
10916f3b1558SSergio Paracuellos 
10926f3b1558SSergio Paracuellos 	priv->sysc = syscon_node_to_regmap(np);
10936f3b1558SSergio Paracuellos 	if (IS_ERR(priv->sysc))
10946f3b1558SSergio Paracuellos 		return dev_err_probe(dev, PTR_ERR(priv->sysc),
10956f3b1558SSergio Paracuellos 				     "Could not get sysc syscon regmap\n");
10966f3b1558SSergio Paracuellos 
10976f3b1558SSergio Paracuellos 	ret = mtmips_reset_init(dev, priv->sysc);
10986f3b1558SSergio Paracuellos 	if (ret)
10996f3b1558SSergio Paracuellos 		return dev_err_probe(dev, ret, "Could not init reset controller\n");
11006f3b1558SSergio Paracuellos 
11016f3b1558SSergio Paracuellos 	return 0;
11026f3b1558SSergio Paracuellos }
11036f3b1558SSergio Paracuellos 
11046f3b1558SSergio Paracuellos static struct platform_driver mtmips_clk_driver = {
11056f3b1558SSergio Paracuellos 	.probe = mtmips_clk_probe,
11066f3b1558SSergio Paracuellos 	.driver = {
11076f3b1558SSergio Paracuellos 		.name = "mtmips-clk",
11083634faabSSergio Paracuellos 		.of_match_table = mtmips_of_match,
11096f3b1558SSergio Paracuellos 	},
11106f3b1558SSergio Paracuellos };
11116f3b1558SSergio Paracuellos 
mtmips_clk_reset_init(void)11126f3b1558SSergio Paracuellos static int __init mtmips_clk_reset_init(void)
11136f3b1558SSergio Paracuellos {
11146f3b1558SSergio Paracuellos 	return platform_driver_register(&mtmips_clk_driver);
11156f3b1558SSergio Paracuellos }
11166f3b1558SSergio Paracuellos arch_initcall(mtmips_clk_reset_init);
1117