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