Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Sergio Paracuellos | 5004 | 99.64% | 2 | 66.67% |
Nathan Chancellor | 18 | 0.36% | 1 | 33.33% |
Total | 5022 | 3 |
// SPDX-License-Identifier: GPL-2.0 /* * MTMIPS SoCs Clock Driver * Author: Sergio Paracuellos <sergio.paracuellos@gmail.com> */ #include <linux/bitops.h> #include <linux/clk-provider.h> #include <linux/mfd/syscon.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/reset-controller.h> #include <linux/slab.h> /* Configuration registers */ #define SYSC_REG_SYSTEM_CONFIG 0x10 #define SYSC_REG_CLKCFG0 0x2c #define SYSC_REG_RESET_CTRL 0x34 #define SYSC_REG_CPU_SYS_CLKCFG 0x3c #define SYSC_REG_CPLL_CONFIG0 0x54 #define SYSC_REG_CPLL_CONFIG1 0x58 /* RT2880 SoC */ #define RT2880_CONFIG_CPUCLK_SHIFT 20 #define RT2880_CONFIG_CPUCLK_MASK 0x3 #define RT2880_CONFIG_CPUCLK_250 0x0 #define RT2880_CONFIG_CPUCLK_266 0x1 #define RT2880_CONFIG_CPUCLK_280 0x2 #define RT2880_CONFIG_CPUCLK_300 0x3 /* RT305X SoC */ #define RT305X_SYSCFG_CPUCLK_SHIFT 18 #define RT305X_SYSCFG_CPUCLK_MASK 0x1 #define RT305X_SYSCFG_CPUCLK_LOW 0x0 #define RT305X_SYSCFG_CPUCLK_HIGH 0x1 /* RT3352 SoC */ #define RT3352_SYSCFG0_CPUCLK_SHIFT 8 #define RT3352_SYSCFG0_CPUCLK_MASK 0x1 #define RT3352_SYSCFG0_CPUCLK_LOW 0x0 #define RT3352_SYSCFG0_CPUCLK_HIGH 0x1 /* RT3383 SoC */ #define RT3883_SYSCFG0_DRAM_TYPE_DDR2 BIT(17) #define RT3883_SYSCFG0_CPUCLK_SHIFT 8 #define RT3883_SYSCFG0_CPUCLK_MASK 0x3 #define RT3883_SYSCFG0_CPUCLK_250 0x0 #define RT3883_SYSCFG0_CPUCLK_384 0x1 #define RT3883_SYSCFG0_CPUCLK_480 0x2 #define RT3883_SYSCFG0_CPUCLK_500 0x3 /* RT5350 SoC */ #define RT5350_CLKCFG0_XTAL_SEL BIT(20) #define RT5350_SYSCFG0_CPUCLK_SHIFT 8 #define RT5350_SYSCFG0_CPUCLK_MASK 0x3 #define RT5350_SYSCFG0_CPUCLK_360 0x0 #define RT5350_SYSCFG0_CPUCLK_320 0x2 #define RT5350_SYSCFG0_CPUCLK_300 0x3 /* MT7620 and MT76x8 SoCs */ #define MT7620_XTAL_FREQ_SEL BIT(6) #define CPLL_CFG0_SW_CFG BIT(31) #define CPLL_CFG0_PLL_MULT_RATIO_SHIFT 16 #define CPLL_CFG0_PLL_MULT_RATIO_MASK 0x7 #define CPLL_CFG0_LC_CURFCK BIT(15) #define CPLL_CFG0_BYPASS_REF_CLK BIT(14) #define CPLL_CFG0_PLL_DIV_RATIO_SHIFT 10 #define CPLL_CFG0_PLL_DIV_RATIO_MASK 0x3 #define CPLL_CFG1_CPU_AUX1 BIT(25) #define CPLL_CFG1_CPU_AUX0 BIT(24) #define CLKCFG0_PERI_CLK_SEL BIT(4) #define CPU_SYS_CLKCFG_OCP_RATIO_SHIFT 16 #define CPU_SYS_CLKCFG_OCP_RATIO_MASK 0xf #define CPU_SYS_CLKCFG_OCP_RATIO_1 0 /* 1:1 (Reserved) */ #define CPU_SYS_CLKCFG_OCP_RATIO_1_5 1 /* 1:1.5 (Reserved) */ #define CPU_SYS_CLKCFG_OCP_RATIO_2 2 /* 1:2 */ #define CPU_SYS_CLKCFG_OCP_RATIO_2_5 3 /* 1:2.5 (Reserved) */ #define CPU_SYS_CLKCFG_OCP_RATIO_3 4 /* 1:3 */ #define CPU_SYS_CLKCFG_OCP_RATIO_3_5 5 /* 1:3.5 (Reserved) */ #define CPU_SYS_CLKCFG_OCP_RATIO_4 6 /* 1:4 */ #define CPU_SYS_CLKCFG_OCP_RATIO_5 7 /* 1:5 */ #define CPU_SYS_CLKCFG_OCP_RATIO_10 8 /* 1:10 */ #define CPU_SYS_CLKCFG_CPU_FDIV_SHIFT 8 #define CPU_SYS_CLKCFG_CPU_FDIV_MASK 0x1f #define CPU_SYS_CLKCFG_CPU_FFRAC_SHIFT 0 #define CPU_SYS_CLKCFG_CPU_FFRAC_MASK 0x1f /* clock scaling */ #define CLKCFG_FDIV_MASK 0x1f00 #define CLKCFG_FDIV_USB_VAL 0x0300 #define CLKCFG_FFRAC_MASK 0x001f #define CLKCFG_FFRAC_USB_VAL 0x0003 struct mtmips_clk; struct mtmips_clk_fixed; struct mtmips_clk_factor; struct mtmips_clk_data { struct mtmips_clk *clk_base; size_t num_clk_base; struct mtmips_clk_fixed *clk_fixed; size_t num_clk_fixed; struct mtmips_clk_factor *clk_factor; size_t num_clk_factor; struct mtmips_clk *clk_periph; size_t num_clk_periph; }; struct mtmips_clk_priv { struct regmap *sysc; const struct mtmips_clk_data *data; }; struct mtmips_clk { struct clk_hw hw; struct mtmips_clk_priv *priv; }; struct mtmips_clk_fixed { const char *name; const char *parent; unsigned long rate; struct clk_hw *hw; }; struct mtmips_clk_factor { const char *name; const char *parent; int mult; int div; unsigned long flags; struct clk_hw *hw; }; static unsigned long mtmips_pherip_clk_rate(struct clk_hw *hw, unsigned long parent_rate) { return parent_rate; } static const struct clk_ops mtmips_periph_clk_ops = { .recalc_rate = mtmips_pherip_clk_rate, }; #define CLK_PERIPH(_name, _parent) { \ .init = &(const struct clk_init_data) { \ .name = _name, \ .ops = &mtmips_periph_clk_ops, \ .parent_data = &(const struct clk_parent_data) {\ .name = _parent, \ .fw_name = _parent \ }, \ .num_parents = 1, \ /* \ * There are drivers for these SoCs that are \ * older than clock driver and are not prepared \ * for the clock. We don't want the kernel to \ * disable anything so we add CLK_IS_CRITICAL \ * flag here. \ */ \ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL \ }, \ } static struct mtmips_clk rt2880_pherip_clks[] = { { CLK_PERIPH("300100.timer", "bus") }, { CLK_PERIPH("300120.watchdog", "bus") }, { CLK_PERIPH("300500.uart", "bus") }, { CLK_PERIPH("300900.i2c", "bus") }, { CLK_PERIPH("300c00.uartlite", "bus") }, { CLK_PERIPH("400000.ethernet", "bus") }, { CLK_PERIPH("480000.wmac", "xtal") } }; static struct mtmips_clk rt305x_pherip_clks[] = { { CLK_PERIPH("10000100.timer", "bus") }, { CLK_PERIPH("10000120.watchdog", "bus") }, { CLK_PERIPH("10000500.uart", "bus") }, { CLK_PERIPH("10000900.i2c", "bus") }, { CLK_PERIPH("10000a00.i2s", "bus") }, { CLK_PERIPH("10000b00.spi", "bus") }, { CLK_PERIPH("10000b40.spi", "bus") }, { CLK_PERIPH("10000c00.uartlite", "bus") }, { CLK_PERIPH("10100000.ethernet", "bus") }, { CLK_PERIPH("10180000.wmac", "xtal") } }; static struct mtmips_clk rt5350_pherip_clks[] = { { CLK_PERIPH("10000100.timer", "bus") }, { CLK_PERIPH("10000120.watchdog", "bus") }, { CLK_PERIPH("10000500.uart", "periph") }, { CLK_PERIPH("10000900.i2c", "periph") }, { CLK_PERIPH("10000a00.i2s", "periph") }, { CLK_PERIPH("10000b00.spi", "bus") }, { CLK_PERIPH("10000b40.spi", "bus") }, { CLK_PERIPH("10000c00.uartlite", "periph") }, { CLK_PERIPH("10100000.ethernet", "bus") }, { CLK_PERIPH("10180000.wmac", "xtal") } }; static struct mtmips_clk mt7620_pherip_clks[] = { { CLK_PERIPH("10000100.timer", "periph") }, { CLK_PERIPH("10000120.watchdog", "periph") }, { CLK_PERIPH("10000500.uart", "periph") }, { CLK_PERIPH("10000900.i2c", "periph") }, { CLK_PERIPH("10000a00.i2s", "periph") }, { CLK_PERIPH("10000b00.spi", "bus") }, { CLK_PERIPH("10000b40.spi", "bus") }, { CLK_PERIPH("10000c00.uartlite", "periph") }, { CLK_PERIPH("10180000.wmac", "xtal") } }; static struct mtmips_clk mt76x8_pherip_clks[] = { { CLK_PERIPH("10000100.timer", "periph") }, { CLK_PERIPH("10000120.watchdog", "periph") }, { CLK_PERIPH("10000900.i2c", "periph") }, { CLK_PERIPH("10000a00.i2s", "pcmi2s") }, { CLK_PERIPH("10000b00.spi", "bus") }, { CLK_PERIPH("10000b40.spi", "bus") }, { CLK_PERIPH("10000c00.uart0", "periph") }, { CLK_PERIPH("10000d00.uart1", "periph") }, { CLK_PERIPH("10000e00.uart2", "periph") }, { CLK_PERIPH("10300000.wmac", "xtal") } }; static int mtmips_register_pherip_clocks(struct device_node *np, struct clk_hw_onecell_data *clk_data, struct mtmips_clk_priv *priv) { struct clk_hw **hws = clk_data->hws; struct mtmips_clk *sclk; size_t idx_start = priv->data->num_clk_base + priv->data->num_clk_fixed + priv->data->num_clk_factor; int ret, i; for (i = 0; i < priv->data->num_clk_periph; i++) { int idx = idx_start + i; sclk = &priv->data->clk_periph[i]; ret = of_clk_hw_register(np, &sclk->hw); if (ret) { pr_err("Couldn't register peripheral clock %d\n", idx); goto err_clk_unreg; } hws[idx] = &sclk->hw; } return 0; err_clk_unreg: while (--i >= 0) { sclk = &priv->data->clk_periph[i]; clk_hw_unregister(&sclk->hw); } return ret; } #define CLK_FIXED(_name, _parent, _rate) \ { \ .name = _name, \ .parent = _parent, \ .rate = _rate \ } static struct mtmips_clk_fixed rt305x_fixed_clocks[] = { CLK_FIXED("xtal", NULL, 40000000) }; static struct mtmips_clk_fixed rt3352_fixed_clocks[] = { CLK_FIXED("periph", "xtal", 40000000) }; static struct mtmips_clk_fixed mt76x8_fixed_clocks[] = { CLK_FIXED("pcmi2s", "xtal", 480000000), CLK_FIXED("periph", "xtal", 40000000) }; static int mtmips_register_fixed_clocks(struct clk_hw_onecell_data *clk_data, struct mtmips_clk_priv *priv) { struct clk_hw **hws = clk_data->hws; struct mtmips_clk_fixed *sclk; size_t idx_start = priv->data->num_clk_base; int ret, i; for (i = 0; i < priv->data->num_clk_fixed; i++) { int idx = idx_start + i; sclk = &priv->data->clk_fixed[i]; sclk->hw = clk_hw_register_fixed_rate(NULL, sclk->name, sclk->parent, 0, sclk->rate); if (IS_ERR(sclk->hw)) { ret = PTR_ERR(sclk->hw); pr_err("Couldn't register fixed clock %d\n", idx); goto err_clk_unreg; } hws[idx] = sclk->hw; } return 0; err_clk_unreg: while (--i >= 0) { sclk = &priv->data->clk_fixed[i]; clk_hw_unregister_fixed_rate(sclk->hw); } return ret; } #define CLK_FACTOR(_name, _parent, _mult, _div) \ { \ .name = _name, \ .parent = _parent, \ .mult = _mult, \ .div = _div, \ .flags = CLK_SET_RATE_PARENT \ } static struct mtmips_clk_factor rt2880_factor_clocks[] = { CLK_FACTOR("bus", "cpu", 1, 2) }; static struct mtmips_clk_factor rt305x_factor_clocks[] = { CLK_FACTOR("bus", "cpu", 1, 3) }; static int mtmips_register_factor_clocks(struct clk_hw_onecell_data *clk_data, struct mtmips_clk_priv *priv) { struct clk_hw **hws = clk_data->hws; struct mtmips_clk_factor *sclk; size_t idx_start = priv->data->num_clk_base + priv->data->num_clk_fixed; int ret, i; for (i = 0; i < priv->data->num_clk_factor; i++) { int idx = idx_start + i; sclk = &priv->data->clk_factor[i]; sclk->hw = clk_hw_register_fixed_factor(NULL, sclk->name, sclk->parent, sclk->flags, sclk->mult, sclk->div); if (IS_ERR(sclk->hw)) { ret = PTR_ERR(sclk->hw); pr_err("Couldn't register factor clock %d\n", idx); goto err_clk_unreg; } hws[idx] = sclk->hw; } return 0; err_clk_unreg: while (--i >= 0) { sclk = &priv->data->clk_factor[i]; clk_hw_unregister_fixed_factor(sclk->hw); } return ret; } static inline struct mtmips_clk *to_mtmips_clk(struct clk_hw *hw) { return container_of(hw, struct mtmips_clk, hw); } static unsigned long rt5350_xtal_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 val; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &val); if (!(val & RT5350_CLKCFG0_XTAL_SEL)) return 20000000; return 40000000; } static unsigned long rt5350_cpu_recalc_rate(struct clk_hw *hw, unsigned long xtal_clk) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t); t = (t >> RT5350_SYSCFG0_CPUCLK_SHIFT) & RT5350_SYSCFG0_CPUCLK_MASK; switch (t) { case RT5350_SYSCFG0_CPUCLK_360: return 360000000; case RT5350_SYSCFG0_CPUCLK_320: return 320000000; case RT5350_SYSCFG0_CPUCLK_300: return 300000000; default: BUG(); } } static unsigned long rt5350_bus_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { if (parent_rate == 320000000) return parent_rate / 4; return parent_rate / 3; } static unsigned long rt3352_cpu_recalc_rate(struct clk_hw *hw, unsigned long xtal_clk) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t); t = (t >> RT3352_SYSCFG0_CPUCLK_SHIFT) & RT3352_SYSCFG0_CPUCLK_MASK; switch (t) { case RT3352_SYSCFG0_CPUCLK_LOW: return 384000000; case RT3352_SYSCFG0_CPUCLK_HIGH: return 400000000; default: BUG(); } } static unsigned long rt305x_cpu_recalc_rate(struct clk_hw *hw, unsigned long xtal_clk) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t); t = (t >> RT305X_SYSCFG_CPUCLK_SHIFT) & RT305X_SYSCFG_CPUCLK_MASK; switch (t) { case RT305X_SYSCFG_CPUCLK_LOW: return 320000000; case RT305X_SYSCFG_CPUCLK_HIGH: return 384000000; default: BUG(); } } static unsigned long rt3883_cpu_recalc_rate(struct clk_hw *hw, unsigned long xtal_clk) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t); t = (t >> RT3883_SYSCFG0_CPUCLK_SHIFT) & RT3883_SYSCFG0_CPUCLK_MASK; switch (t) { case RT3883_SYSCFG0_CPUCLK_250: return 250000000; case RT3883_SYSCFG0_CPUCLK_384: return 384000000; case RT3883_SYSCFG0_CPUCLK_480: return 480000000; case RT3883_SYSCFG0_CPUCLK_500: return 500000000; default: BUG(); } } static unsigned long rt3883_bus_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 ddr2; u32 t; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t); ddr2 = t & RT3883_SYSCFG0_DRAM_TYPE_DDR2; switch (parent_rate) { case 250000000: return (ddr2) ? 125000000 : 83000000; case 384000000: return (ddr2) ? 128000000 : 96000000; case 480000000: return (ddr2) ? 160000000 : 120000000; case 500000000: return (ddr2) ? 166000000 : 125000000; default: WARN_ON_ONCE(parent_rate == 0); return parent_rate / 4; } } static unsigned long rt2880_cpu_recalc_rate(struct clk_hw *hw, unsigned long xtal_clk) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t); t = (t >> RT2880_CONFIG_CPUCLK_SHIFT) & RT2880_CONFIG_CPUCLK_MASK; switch (t) { case RT2880_CONFIG_CPUCLK_250: return 250000000; case RT2880_CONFIG_CPUCLK_266: return 266000000; case RT2880_CONFIG_CPUCLK_280: return 280000000; case RT2880_CONFIG_CPUCLK_300: return 300000000; default: BUG(); } } static u32 mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div) { u64 t; t = ref_rate; t *= mul; t = div_u64(t, div); return t; } static unsigned long mt7620_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { static const u32 clk_divider[] = { 2, 3, 4, 8 }; struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; unsigned long cpu_pll; u32 t; u32 mul; u32 div; regmap_read(sysc, SYSC_REG_CPLL_CONFIG0, &t); if (t & CPLL_CFG0_BYPASS_REF_CLK) { cpu_pll = parent_rate; } else if ((t & CPLL_CFG0_SW_CFG) == 0) { cpu_pll = 600000000; } else { mul = (t >> CPLL_CFG0_PLL_MULT_RATIO_SHIFT) & CPLL_CFG0_PLL_MULT_RATIO_MASK; mul += 24; if (t & CPLL_CFG0_LC_CURFCK) mul *= 2; div = (t >> CPLL_CFG0_PLL_DIV_RATIO_SHIFT) & CPLL_CFG0_PLL_DIV_RATIO_MASK; WARN_ON_ONCE(div >= ARRAY_SIZE(clk_divider)); cpu_pll = mt7620_calc_rate(parent_rate, mul, clk_divider[div]); } regmap_read(sysc, SYSC_REG_CPLL_CONFIG1, &t); if (t & CPLL_CFG1_CPU_AUX1) return parent_rate; if (t & CPLL_CFG1_CPU_AUX0) return 480000000; return cpu_pll; } static unsigned long mt7620_cpu_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; u32 mul; u32 div; regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t); mul = t & CPU_SYS_CLKCFG_CPU_FFRAC_MASK; div = (t >> CPU_SYS_CLKCFG_CPU_FDIV_SHIFT) & CPU_SYS_CLKCFG_CPU_FDIV_MASK; return mt7620_calc_rate(parent_rate, mul, div); } static unsigned long mt7620_bus_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { static const u32 ocp_dividers[16] = { [CPU_SYS_CLKCFG_OCP_RATIO_2] = 2, [CPU_SYS_CLKCFG_OCP_RATIO_3] = 3, [CPU_SYS_CLKCFG_OCP_RATIO_4] = 4, [CPU_SYS_CLKCFG_OCP_RATIO_5] = 5, [CPU_SYS_CLKCFG_OCP_RATIO_10] = 10, }; struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; u32 ocp_ratio; u32 div; regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t); ocp_ratio = (t >> CPU_SYS_CLKCFG_OCP_RATIO_SHIFT) & CPU_SYS_CLKCFG_OCP_RATIO_MASK; if (WARN_ON_ONCE(ocp_ratio >= ARRAY_SIZE(ocp_dividers))) return parent_rate; div = ocp_dividers[ocp_ratio]; if (WARN(!div, "invalid divider for OCP ratio %u", ocp_ratio)) return parent_rate; return parent_rate / div; } static unsigned long mt7620_periph_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; regmap_read(sysc, SYSC_REG_CLKCFG0, &t); if (t & CLKCFG0_PERI_CLK_SEL) return parent_rate; return 40000000; } static unsigned long mt76x8_xtal_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct mtmips_clk *clk = to_mtmips_clk(hw); struct regmap *sysc = clk->priv->sysc; u32 t; regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t); if (t & MT7620_XTAL_FREQ_SEL) return 40000000; return 20000000; } static unsigned long mt76x8_cpu_recalc_rate(struct clk_hw *hw, unsigned long xtal_clk) { if (xtal_clk == 40000000) return 580000000; return 575000000; } #define CLK_BASE(_name, _parent, _recalc) { \ .init = &(const struct clk_init_data) { \ .name = _name, \ .ops = &(const struct clk_ops) { \ .recalc_rate = _recalc, \ }, \ .parent_data = &(const struct clk_parent_data) { \ .name = _parent, \ .fw_name = _parent \ }, \ .num_parents = _parent ? 1 : 0 \ }, \ } static struct mtmips_clk rt2880_clks_base[] = { { CLK_BASE("cpu", "xtal", rt2880_cpu_recalc_rate) } }; static struct mtmips_clk rt305x_clks_base[] = { { CLK_BASE("cpu", "xtal", rt305x_cpu_recalc_rate) } }; static struct mtmips_clk rt3352_clks_base[] = { { CLK_BASE("xtal", NULL, rt5350_xtal_recalc_rate) }, { CLK_BASE("cpu", "xtal", rt3352_cpu_recalc_rate) } }; static struct mtmips_clk rt3883_clks_base[] = { { CLK_BASE("cpu", "xtal", rt3883_cpu_recalc_rate) }, { CLK_BASE("bus", "cpu", rt3883_bus_recalc_rate) } }; static struct mtmips_clk rt5350_clks_base[] = { { CLK_BASE("xtal", NULL, rt5350_xtal_recalc_rate) }, { CLK_BASE("cpu", "xtal", rt5350_cpu_recalc_rate) }, { CLK_BASE("bus", "cpu", rt5350_bus_recalc_rate) } }; static struct mtmips_clk mt7620_clks_base[] = { { CLK_BASE("xtal", NULL, mt76x8_xtal_recalc_rate) }, { CLK_BASE("pll", "xtal", mt7620_pll_recalc_rate) }, { CLK_BASE("cpu", "pll", mt7620_cpu_recalc_rate) }, { CLK_BASE("periph", "xtal", mt7620_periph_recalc_rate) }, { CLK_BASE("bus", "cpu", mt7620_bus_recalc_rate) } }; static struct mtmips_clk mt76x8_clks_base[] = { { CLK_BASE("xtal", NULL, mt76x8_xtal_recalc_rate) }, { CLK_BASE("cpu", "xtal", mt76x8_cpu_recalc_rate) } }; static int mtmips_register_clocks(struct device_node *np, struct clk_hw_onecell_data *clk_data, struct mtmips_clk_priv *priv) { struct clk_hw **hws = clk_data->hws; struct mtmips_clk *sclk; int ret, i; for (i = 0; i < priv->data->num_clk_base; i++) { sclk = &priv->data->clk_base[i]; sclk->priv = priv; ret = of_clk_hw_register(np, &sclk->hw); if (ret) { pr_err("Couldn't register top clock %i\n", i); goto err_clk_unreg; } hws[i] = &sclk->hw; } return 0; err_clk_unreg: while (--i >= 0) { sclk = &priv->data->clk_base[i]; clk_hw_unregister(&sclk->hw); } return ret; } static const struct mtmips_clk_data rt2880_clk_data = { .clk_base = rt2880_clks_base, .num_clk_base = ARRAY_SIZE(rt2880_clks_base), .clk_fixed = rt305x_fixed_clocks, .num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks), .clk_factor = rt2880_factor_clocks, .num_clk_factor = ARRAY_SIZE(rt2880_factor_clocks), .clk_periph = rt2880_pherip_clks, .num_clk_periph = ARRAY_SIZE(rt2880_pherip_clks), }; static const struct mtmips_clk_data rt305x_clk_data = { .clk_base = rt305x_clks_base, .num_clk_base = ARRAY_SIZE(rt305x_clks_base), .clk_fixed = rt305x_fixed_clocks, .num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks), .clk_factor = rt305x_factor_clocks, .num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks), .clk_periph = rt305x_pherip_clks, .num_clk_periph = ARRAY_SIZE(rt305x_pherip_clks), }; static const struct mtmips_clk_data rt3352_clk_data = { .clk_base = rt3352_clks_base, .num_clk_base = ARRAY_SIZE(rt3352_clks_base), .clk_fixed = rt3352_fixed_clocks, .num_clk_fixed = ARRAY_SIZE(rt3352_fixed_clocks), .clk_factor = rt305x_factor_clocks, .num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks), .clk_periph = rt5350_pherip_clks, .num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks), }; static const struct mtmips_clk_data rt3883_clk_data = { .clk_base = rt3883_clks_base, .num_clk_base = ARRAY_SIZE(rt3883_clks_base), .clk_fixed = rt305x_fixed_clocks, .num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks), .clk_factor = NULL, .num_clk_factor = 0, .clk_periph = rt5350_pherip_clks, .num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks), }; static const struct mtmips_clk_data rt5350_clk_data = { .clk_base = rt5350_clks_base, .num_clk_base = ARRAY_SIZE(rt5350_clks_base), .clk_fixed = rt3352_fixed_clocks, .num_clk_fixed = ARRAY_SIZE(rt3352_fixed_clocks), .clk_factor = NULL, .num_clk_factor = 0, .clk_periph = rt5350_pherip_clks, .num_clk_periph = ARRAY_SIZE(rt5350_pherip_clks), }; static const struct mtmips_clk_data mt7620_clk_data = { .clk_base = mt7620_clks_base, .num_clk_base = ARRAY_SIZE(mt7620_clks_base), .clk_fixed = NULL, .num_clk_fixed = 0, .clk_factor = NULL, .num_clk_factor = 0, .clk_periph = mt7620_pherip_clks, .num_clk_periph = ARRAY_SIZE(mt7620_pherip_clks), }; static const struct mtmips_clk_data mt76x8_clk_data = { .clk_base = mt76x8_clks_base, .num_clk_base = ARRAY_SIZE(mt76x8_clks_base), .clk_fixed = mt76x8_fixed_clocks, .num_clk_fixed = ARRAY_SIZE(mt76x8_fixed_clocks), .clk_factor = rt305x_factor_clocks, .num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks), .clk_periph = mt76x8_pherip_clks, .num_clk_periph = ARRAY_SIZE(mt76x8_pherip_clks), }; static const struct of_device_id mtmips_of_match[] = { { .compatible = "ralink,rt2880-reset", .data = NULL, }, { .compatible = "ralink,rt2880-sysc", .data = &rt2880_clk_data, }, { .compatible = "ralink,rt3050-sysc", .data = &rt305x_clk_data, }, { .compatible = "ralink,rt3052-sysc", .data = &rt305x_clk_data, }, { .compatible = "ralink,rt3352-sysc", .data = &rt3352_clk_data, }, { .compatible = "ralink,rt3883-sysc", .data = &rt3883_clk_data, }, { .compatible = "ralink,rt5350-sysc", .data = &rt5350_clk_data, }, { .compatible = "ralink,mt7620-sysc", .data = &mt7620_clk_data, }, { .compatible = "ralink,mt7628-sysc", .data = &mt76x8_clk_data, }, { .compatible = "ralink,mt7688-sysc", .data = &mt76x8_clk_data, }, {} }; static void __init mtmips_clk_regs_init(struct device_node *node, struct mtmips_clk_priv *priv) { u32 t; if (!of_device_is_compatible(node, "ralink,mt7620-sysc")) return; /* * When the CPU goes into sleep mode, the BUS * clock will be too low for USB to function properly. * Adjust the busses fractional divider to fix this */ regmap_read(priv->sysc, SYSC_REG_CPU_SYS_CLKCFG, &t); t &= ~(CLKCFG_FDIV_MASK | CLKCFG_FFRAC_MASK); t |= CLKCFG_FDIV_USB_VAL | CLKCFG_FFRAC_USB_VAL; regmap_write(priv->sysc, SYSC_REG_CPU_SYS_CLKCFG, t); } static void __init mtmips_clk_init(struct device_node *node) { const struct of_device_id *match; const struct mtmips_clk_data *data; struct mtmips_clk_priv *priv; struct clk_hw_onecell_data *clk_data; int ret, i, count; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return; priv->sysc = syscon_node_to_regmap(node); if (IS_ERR(priv->sysc)) { pr_err("Could not get sysc syscon regmap\n"); goto free_clk_priv; } mtmips_clk_regs_init(node, priv); match = of_match_node(mtmips_of_match, node); if (WARN_ON(!match)) return; data = match->data; priv->data = data; count = priv->data->num_clk_base + priv->data->num_clk_fixed + priv->data->num_clk_factor + priv->data->num_clk_periph; clk_data = kzalloc(struct_size(clk_data, hws, count), GFP_KERNEL); if (!clk_data) goto free_clk_priv; ret = mtmips_register_clocks(node, clk_data, priv); if (ret) { pr_err("Couldn't register top clocks\n"); goto free_clk_data; } ret = mtmips_register_fixed_clocks(clk_data, priv); if (ret) { pr_err("Couldn't register fixed clocks\n"); goto unreg_clk_top; } ret = mtmips_register_factor_clocks(clk_data, priv); if (ret) { pr_err("Couldn't register factor clocks\n"); goto unreg_clk_fixed; } ret = mtmips_register_pherip_clocks(node, clk_data, priv); if (ret) { pr_err("Couldn't register peripheral clocks\n"); goto unreg_clk_factor; } clk_data->num = count; ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); if (ret) { pr_err("Couldn't add clk hw provider\n"); goto unreg_clk_periph; } return; unreg_clk_periph: for (i = 0; i < priv->data->num_clk_periph; i++) { struct mtmips_clk *sclk = &priv->data->clk_periph[i]; clk_hw_unregister(&sclk->hw); } unreg_clk_factor: for (i = 0; i < priv->data->num_clk_factor; i++) { struct mtmips_clk_factor *sclk = &priv->data->clk_factor[i]; clk_hw_unregister_fixed_factor(sclk->hw); } unreg_clk_fixed: for (i = 0; i < priv->data->num_clk_fixed; i++) { struct mtmips_clk_fixed *sclk = &priv->data->clk_fixed[i]; clk_hw_unregister_fixed_rate(sclk->hw); } unreg_clk_top: for (i = 0; i < priv->data->num_clk_base; i++) { struct mtmips_clk *sclk = &priv->data->clk_base[i]; clk_hw_unregister(&sclk->hw); } free_clk_data: kfree(clk_data); free_clk_priv: kfree(priv); } CLK_OF_DECLARE_DRIVER(rt2880_clk, "ralink,rt2880-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(rt3050_clk, "ralink,rt3050-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(rt3052_clk, "ralink,rt3052-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(rt3352_clk, "ralink,rt3352-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(rt3883_clk, "ralink,rt3883-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(rt5350_clk, "ralink,rt5350-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(mt7620_clk, "ralink,mt7620-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(mt7628_clk, "ralink,mt7628-sysc", mtmips_clk_init); CLK_OF_DECLARE_DRIVER(mt7688_clk, "ralink,mt7688-sysc", mtmips_clk_init); struct mtmips_rst { struct reset_controller_dev rcdev; struct regmap *sysc; }; static struct mtmips_rst *to_mtmips_rst(struct reset_controller_dev *dev) { return container_of(dev, struct mtmips_rst, rcdev); } static int mtmips_assert_device(struct reset_controller_dev *rcdev, unsigned long id) { struct mtmips_rst *data = to_mtmips_rst(rcdev); struct regmap *sysc = data->sysc; return regmap_update_bits(sysc, SYSC_REG_RESET_CTRL, BIT(id), BIT(id)); } static int mtmips_deassert_device(struct reset_controller_dev *rcdev, unsigned long id) { struct mtmips_rst *data = to_mtmips_rst(rcdev); struct regmap *sysc = data->sysc; return regmap_update_bits(sysc, SYSC_REG_RESET_CTRL, BIT(id), 0); } static int mtmips_reset_device(struct reset_controller_dev *rcdev, unsigned long id) { int ret; ret = mtmips_assert_device(rcdev, id); if (ret < 0) return ret; return mtmips_deassert_device(rcdev, id); } static int mtmips_rst_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec) { unsigned long id = reset_spec->args[0]; if (id == 0 || id >= rcdev->nr_resets) return -EINVAL; return id; } static const struct reset_control_ops reset_ops = { .reset = mtmips_reset_device, .assert = mtmips_assert_device, .deassert = mtmips_deassert_device }; static int mtmips_reset_init(struct device *dev, struct regmap *sysc) { struct mtmips_rst *rst_data; rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL); if (!rst_data) return -ENOMEM; rst_data->sysc = sysc; rst_data->rcdev.ops = &reset_ops; rst_data->rcdev.owner = THIS_MODULE; rst_data->rcdev.nr_resets = 32; rst_data->rcdev.of_reset_n_cells = 1; rst_data->rcdev.of_xlate = mtmips_rst_xlate; rst_data->rcdev.of_node = dev_of_node(dev); return devm_reset_controller_register(dev, &rst_data->rcdev); } static int mtmips_clk_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct mtmips_clk_priv *priv; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->sysc = syscon_node_to_regmap(np); if (IS_ERR(priv->sysc)) return dev_err_probe(dev, PTR_ERR(priv->sysc), "Could not get sysc syscon regmap\n"); ret = mtmips_reset_init(dev, priv->sysc); if (ret) return dev_err_probe(dev, ret, "Could not init reset controller\n"); return 0; } static struct platform_driver mtmips_clk_driver = { .probe = mtmips_clk_probe, .driver = { .name = "mtmips-clk", .of_match_table = mtmips_of_match, }, }; static int __init mtmips_clk_reset_init(void) { return platform_driver_register(&mtmips_clk_driver); } arch_initcall(mtmips_clk_reset_init);
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1