11e88a8d6SDavid Lechner // SPDX-License-Identifier: GPL-2.0 21e88a8d6SDavid Lechner /* 31e88a8d6SDavid Lechner * Clock driver for DA8xx/AM17xx/AM18xx/OMAP-L13x CFGCHIP 41e88a8d6SDavid Lechner * 51e88a8d6SDavid Lechner * Copyright (C) 2018 David Lechner <david@lechnology.com> 61e88a8d6SDavid Lechner */ 71e88a8d6SDavid Lechner 81e88a8d6SDavid Lechner #include <linux/clk-provider.h> 91e88a8d6SDavid Lechner #include <linux/clk.h> 101e88a8d6SDavid Lechner #include <linux/clkdev.h> 111e88a8d6SDavid Lechner #include <linux/init.h> 121e88a8d6SDavid Lechner #include <linux/mfd/da8xx-cfgchip.h> 131e88a8d6SDavid Lechner #include <linux/mfd/syscon.h> 141e88a8d6SDavid Lechner #include <linux/of_device.h> 151e88a8d6SDavid Lechner #include <linux/of.h> 161e88a8d6SDavid Lechner #include <linux/platform_data/clk-da8xx-cfgchip.h> 171e88a8d6SDavid Lechner #include <linux/platform_device.h> 181e88a8d6SDavid Lechner #include <linux/regmap.h> 191e88a8d6SDavid Lechner #include <linux/slab.h> 201e88a8d6SDavid Lechner 211e88a8d6SDavid Lechner /* --- Gate clocks --- */ 221e88a8d6SDavid Lechner 231e88a8d6SDavid Lechner #define DA8XX_GATE_CLOCK_IS_DIV4P5 BIT(1) 241e88a8d6SDavid Lechner 251e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk_info { 261e88a8d6SDavid Lechner const char *name; 271e88a8d6SDavid Lechner u32 cfgchip; 281e88a8d6SDavid Lechner u32 bit; 291e88a8d6SDavid Lechner u32 flags; 301e88a8d6SDavid Lechner }; 311e88a8d6SDavid Lechner 321e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk { 331e88a8d6SDavid Lechner struct clk_hw hw; 341e88a8d6SDavid Lechner struct regmap *regmap; 351e88a8d6SDavid Lechner u32 reg; 361e88a8d6SDavid Lechner u32 mask; 371e88a8d6SDavid Lechner }; 381e88a8d6SDavid Lechner 391e88a8d6SDavid Lechner #define to_da8xx_cfgchip_gate_clk(_hw) \ 401e88a8d6SDavid Lechner container_of((_hw), struct da8xx_cfgchip_gate_clk, hw) 411e88a8d6SDavid Lechner 421e88a8d6SDavid Lechner static int da8xx_cfgchip_gate_clk_enable(struct clk_hw *hw) 431e88a8d6SDavid Lechner { 441e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw); 451e88a8d6SDavid Lechner 461e88a8d6SDavid Lechner return regmap_write_bits(clk->regmap, clk->reg, clk->mask, clk->mask); 471e88a8d6SDavid Lechner } 481e88a8d6SDavid Lechner 491e88a8d6SDavid Lechner static void da8xx_cfgchip_gate_clk_disable(struct clk_hw *hw) 501e88a8d6SDavid Lechner { 511e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw); 521e88a8d6SDavid Lechner 531e88a8d6SDavid Lechner regmap_write_bits(clk->regmap, clk->reg, clk->mask, 0); 541e88a8d6SDavid Lechner } 551e88a8d6SDavid Lechner 561e88a8d6SDavid Lechner static int da8xx_cfgchip_gate_clk_is_enabled(struct clk_hw *hw) 571e88a8d6SDavid Lechner { 581e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw); 591e88a8d6SDavid Lechner unsigned int val; 601e88a8d6SDavid Lechner 611e88a8d6SDavid Lechner regmap_read(clk->regmap, clk->reg, &val); 621e88a8d6SDavid Lechner 631e88a8d6SDavid Lechner return !!(val & clk->mask); 641e88a8d6SDavid Lechner } 651e88a8d6SDavid Lechner 661e88a8d6SDavid Lechner static unsigned long da8xx_cfgchip_div4p5_recalc_rate(struct clk_hw *hw, 671e88a8d6SDavid Lechner unsigned long parent_rate) 681e88a8d6SDavid Lechner { 691e88a8d6SDavid Lechner /* this clock divides by 4.5 */ 701e88a8d6SDavid Lechner return parent_rate * 2 / 9; 711e88a8d6SDavid Lechner } 721e88a8d6SDavid Lechner 731e88a8d6SDavid Lechner static const struct clk_ops da8xx_cfgchip_gate_clk_ops = { 741e88a8d6SDavid Lechner .enable = da8xx_cfgchip_gate_clk_enable, 751e88a8d6SDavid Lechner .disable = da8xx_cfgchip_gate_clk_disable, 761e88a8d6SDavid Lechner .is_enabled = da8xx_cfgchip_gate_clk_is_enabled, 771e88a8d6SDavid Lechner }; 781e88a8d6SDavid Lechner 791e88a8d6SDavid Lechner static const struct clk_ops da8xx_cfgchip_div4p5_clk_ops = { 801e88a8d6SDavid Lechner .enable = da8xx_cfgchip_gate_clk_enable, 811e88a8d6SDavid Lechner .disable = da8xx_cfgchip_gate_clk_disable, 821e88a8d6SDavid Lechner .is_enabled = da8xx_cfgchip_gate_clk_is_enabled, 831e88a8d6SDavid Lechner .recalc_rate = da8xx_cfgchip_div4p5_recalc_rate, 841e88a8d6SDavid Lechner }; 851e88a8d6SDavid Lechner 861e88a8d6SDavid Lechner static struct da8xx_cfgchip_gate_clk * __init 871e88a8d6SDavid Lechner da8xx_cfgchip_gate_clk_register(struct device *dev, 881e88a8d6SDavid Lechner const struct da8xx_cfgchip_gate_clk_info *info, 891e88a8d6SDavid Lechner struct regmap *regmap) 901e88a8d6SDavid Lechner { 911e88a8d6SDavid Lechner struct clk *parent; 921e88a8d6SDavid Lechner const char *parent_name; 931e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *gate; 941e88a8d6SDavid Lechner struct clk_init_data init; 951e88a8d6SDavid Lechner int ret; 961e88a8d6SDavid Lechner 971e88a8d6SDavid Lechner parent = devm_clk_get(dev, NULL); 981e88a8d6SDavid Lechner if (IS_ERR(parent)) 991e88a8d6SDavid Lechner return ERR_CAST(parent); 1001e88a8d6SDavid Lechner 1011e88a8d6SDavid Lechner parent_name = __clk_get_name(parent); 1021e88a8d6SDavid Lechner 1031e88a8d6SDavid Lechner gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); 1041e88a8d6SDavid Lechner if (!gate) 1051e88a8d6SDavid Lechner return ERR_PTR(-ENOMEM); 1061e88a8d6SDavid Lechner 1071e88a8d6SDavid Lechner init.name = info->name; 1081e88a8d6SDavid Lechner if (info->flags & DA8XX_GATE_CLOCK_IS_DIV4P5) 1091e88a8d6SDavid Lechner init.ops = &da8xx_cfgchip_div4p5_clk_ops; 1101e88a8d6SDavid Lechner else 1111e88a8d6SDavid Lechner init.ops = &da8xx_cfgchip_gate_clk_ops; 1121e88a8d6SDavid Lechner init.parent_names = &parent_name; 1131e88a8d6SDavid Lechner init.num_parents = 1; 1141e88a8d6SDavid Lechner init.flags = 0; 1151e88a8d6SDavid Lechner 1161e88a8d6SDavid Lechner gate->hw.init = &init; 1171e88a8d6SDavid Lechner gate->regmap = regmap; 1181e88a8d6SDavid Lechner gate->reg = info->cfgchip; 1191e88a8d6SDavid Lechner gate->mask = info->bit; 1201e88a8d6SDavid Lechner 1211e88a8d6SDavid Lechner ret = devm_clk_hw_register(dev, &gate->hw); 1221e88a8d6SDavid Lechner if (ret < 0) 1231e88a8d6SDavid Lechner return ERR_PTR(ret); 1241e88a8d6SDavid Lechner 1251e88a8d6SDavid Lechner return gate; 1261e88a8d6SDavid Lechner } 1271e88a8d6SDavid Lechner 1281e88a8d6SDavid Lechner static const struct da8xx_cfgchip_gate_clk_info da8xx_tbclksync_info __initconst = { 1291e88a8d6SDavid Lechner .name = "ehrpwm_tbclk", 1301e88a8d6SDavid Lechner .cfgchip = CFGCHIP(1), 1311e88a8d6SDavid Lechner .bit = CFGCHIP1_TBCLKSYNC, 1321e88a8d6SDavid Lechner }; 1331e88a8d6SDavid Lechner 1341e88a8d6SDavid Lechner static int __init da8xx_cfgchip_register_tbclk(struct device *dev, 1351e88a8d6SDavid Lechner struct regmap *regmap) 1361e88a8d6SDavid Lechner { 1371e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *gate; 1381e88a8d6SDavid Lechner 1391e88a8d6SDavid Lechner gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_tbclksync_info, 1401e88a8d6SDavid Lechner regmap); 1411e88a8d6SDavid Lechner if (IS_ERR(gate)) 1421e88a8d6SDavid Lechner return PTR_ERR(gate); 1431e88a8d6SDavid Lechner 1441e88a8d6SDavid Lechner clk_hw_register_clkdev(&gate->hw, "tbclk", "ehrpwm.0"); 1451e88a8d6SDavid Lechner clk_hw_register_clkdev(&gate->hw, "tbclk", "ehrpwm.1"); 1461e88a8d6SDavid Lechner 1471e88a8d6SDavid Lechner return 0; 1481e88a8d6SDavid Lechner } 1491e88a8d6SDavid Lechner 1501e88a8d6SDavid Lechner static const struct da8xx_cfgchip_gate_clk_info da8xx_div4p5ena_info __initconst = { 1511e88a8d6SDavid Lechner .name = "div4.5", 1521e88a8d6SDavid Lechner .cfgchip = CFGCHIP(3), 1531e88a8d6SDavid Lechner .bit = CFGCHIP3_DIV45PENA, 1541e88a8d6SDavid Lechner .flags = DA8XX_GATE_CLOCK_IS_DIV4P5, 1551e88a8d6SDavid Lechner }; 1561e88a8d6SDavid Lechner 1571e88a8d6SDavid Lechner static int __init da8xx_cfgchip_register_div4p5(struct device *dev, 1581e88a8d6SDavid Lechner struct regmap *regmap) 1591e88a8d6SDavid Lechner { 1601e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *gate; 1611e88a8d6SDavid Lechner 1621e88a8d6SDavid Lechner gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_div4p5ena_info, regmap); 1631e88a8d6SDavid Lechner if (IS_ERR(gate)) 1641e88a8d6SDavid Lechner return PTR_ERR(gate); 1651e88a8d6SDavid Lechner 1661e88a8d6SDavid Lechner return 0; 1671e88a8d6SDavid Lechner } 1681e88a8d6SDavid Lechner 1691e88a8d6SDavid Lechner static int __init 1701e88a8d6SDavid Lechner of_da8xx_cfgchip_gate_clk_init(struct device *dev, 1711e88a8d6SDavid Lechner const struct da8xx_cfgchip_gate_clk_info *info, 1721e88a8d6SDavid Lechner struct regmap *regmap) 1731e88a8d6SDavid Lechner { 1741e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *gate; 1751e88a8d6SDavid Lechner 1761e88a8d6SDavid Lechner gate = da8xx_cfgchip_gate_clk_register(dev, info, regmap); 1771e88a8d6SDavid Lechner if (IS_ERR(gate)) 1781e88a8d6SDavid Lechner return PTR_ERR(gate); 1791e88a8d6SDavid Lechner 1801e88a8d6SDavid Lechner return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, gate); 1811e88a8d6SDavid Lechner } 1821e88a8d6SDavid Lechner 1831e88a8d6SDavid Lechner static int __init of_da8xx_tbclksync_init(struct device *dev, 1841e88a8d6SDavid Lechner struct regmap *regmap) 1851e88a8d6SDavid Lechner { 1861e88a8d6SDavid Lechner return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_tbclksync_info, regmap); 1871e88a8d6SDavid Lechner } 1881e88a8d6SDavid Lechner 1891e88a8d6SDavid Lechner static int __init of_da8xx_div4p5ena_init(struct device *dev, 1901e88a8d6SDavid Lechner struct regmap *regmap) 1911e88a8d6SDavid Lechner { 1921e88a8d6SDavid Lechner return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_div4p5ena_info, regmap); 1931e88a8d6SDavid Lechner } 1941e88a8d6SDavid Lechner 1951e88a8d6SDavid Lechner /* --- MUX clocks --- */ 1961e88a8d6SDavid Lechner 1971e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk_info { 1981e88a8d6SDavid Lechner const char *name; 1991e88a8d6SDavid Lechner const char *parent0; 2001e88a8d6SDavid Lechner const char *parent1; 2011e88a8d6SDavid Lechner u32 cfgchip; 2021e88a8d6SDavid Lechner u32 bit; 2031e88a8d6SDavid Lechner }; 2041e88a8d6SDavid Lechner 2051e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk { 2061e88a8d6SDavid Lechner struct clk_hw hw; 2071e88a8d6SDavid Lechner struct regmap *regmap; 2081e88a8d6SDavid Lechner u32 reg; 2091e88a8d6SDavid Lechner u32 mask; 2101e88a8d6SDavid Lechner }; 2111e88a8d6SDavid Lechner 2121e88a8d6SDavid Lechner #define to_da8xx_cfgchip_mux_clk(_hw) \ 2131e88a8d6SDavid Lechner container_of((_hw), struct da8xx_cfgchip_mux_clk, hw) 2141e88a8d6SDavid Lechner 2151e88a8d6SDavid Lechner static int da8xx_cfgchip_mux_clk_set_parent(struct clk_hw *hw, u8 index) 2161e88a8d6SDavid Lechner { 2171e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw); 2181e88a8d6SDavid Lechner unsigned int val = index ? clk->mask : 0; 2191e88a8d6SDavid Lechner 2201e88a8d6SDavid Lechner return regmap_write_bits(clk->regmap, clk->reg, clk->mask, val); 2211e88a8d6SDavid Lechner } 2221e88a8d6SDavid Lechner 2231e88a8d6SDavid Lechner static u8 da8xx_cfgchip_mux_clk_get_parent(struct clk_hw *hw) 2241e88a8d6SDavid Lechner { 2251e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw); 2261e88a8d6SDavid Lechner unsigned int val; 2271e88a8d6SDavid Lechner 2281e88a8d6SDavid Lechner regmap_read(clk->regmap, clk->reg, &val); 2291e88a8d6SDavid Lechner 2301e88a8d6SDavid Lechner return (val & clk->mask) ? 1 : 0; 2311e88a8d6SDavid Lechner } 2321e88a8d6SDavid Lechner 2331e88a8d6SDavid Lechner static const struct clk_ops da8xx_cfgchip_mux_clk_ops = { 2341e88a8d6SDavid Lechner .set_parent = da8xx_cfgchip_mux_clk_set_parent, 2351e88a8d6SDavid Lechner .get_parent = da8xx_cfgchip_mux_clk_get_parent, 2361e88a8d6SDavid Lechner }; 2371e88a8d6SDavid Lechner 2381e88a8d6SDavid Lechner static struct da8xx_cfgchip_mux_clk * __init 2391e88a8d6SDavid Lechner da8xx_cfgchip_mux_clk_register(struct device *dev, 2401e88a8d6SDavid Lechner const struct da8xx_cfgchip_mux_clk_info *info, 2411e88a8d6SDavid Lechner struct regmap *regmap) 2421e88a8d6SDavid Lechner { 2431e88a8d6SDavid Lechner const char * const parent_names[] = { info->parent0, info->parent1 }; 2441e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 2451e88a8d6SDavid Lechner struct clk_init_data init; 2461e88a8d6SDavid Lechner int ret; 2471e88a8d6SDavid Lechner 2481e88a8d6SDavid Lechner mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); 2491e88a8d6SDavid Lechner if (!mux) 2501e88a8d6SDavid Lechner return ERR_PTR(-ENOMEM); 2511e88a8d6SDavid Lechner 2521e88a8d6SDavid Lechner init.name = info->name; 2531e88a8d6SDavid Lechner init.ops = &da8xx_cfgchip_mux_clk_ops; 2541e88a8d6SDavid Lechner init.parent_names = parent_names; 2551e88a8d6SDavid Lechner init.num_parents = 2; 2561e88a8d6SDavid Lechner init.flags = 0; 2571e88a8d6SDavid Lechner 2581e88a8d6SDavid Lechner mux->hw.init = &init; 2591e88a8d6SDavid Lechner mux->regmap = regmap; 2601e88a8d6SDavid Lechner mux->reg = info->cfgchip; 2611e88a8d6SDavid Lechner mux->mask = info->bit; 2621e88a8d6SDavid Lechner 2631e88a8d6SDavid Lechner ret = devm_clk_hw_register(dev, &mux->hw); 2641e88a8d6SDavid Lechner if (ret < 0) 2651e88a8d6SDavid Lechner return ERR_PTR(ret); 2661e88a8d6SDavid Lechner 2671e88a8d6SDavid Lechner return mux; 2681e88a8d6SDavid Lechner } 2691e88a8d6SDavid Lechner 2701e88a8d6SDavid Lechner static const struct da8xx_cfgchip_mux_clk_info da850_async1_info __initconst = { 2711e88a8d6SDavid Lechner .name = "async1", 2721e88a8d6SDavid Lechner .parent0 = "pll0_sysclk3", 2731e88a8d6SDavid Lechner .parent1 = "div4.5", 2741e88a8d6SDavid Lechner .cfgchip = CFGCHIP(3), 2751e88a8d6SDavid Lechner .bit = CFGCHIP3_EMA_CLKSRC, 2761e88a8d6SDavid Lechner }; 2771e88a8d6SDavid Lechner 2781e88a8d6SDavid Lechner static int __init da8xx_cfgchip_register_async1(struct device *dev, 2791e88a8d6SDavid Lechner struct regmap *regmap) 2801e88a8d6SDavid Lechner { 2811e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 2821e88a8d6SDavid Lechner 2831e88a8d6SDavid Lechner mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async1_info, regmap); 2841e88a8d6SDavid Lechner if (IS_ERR(mux)) 2851e88a8d6SDavid Lechner return PTR_ERR(mux); 2861e88a8d6SDavid Lechner 2871e88a8d6SDavid Lechner clk_hw_register_clkdev(&mux->hw, "async1", "da850-psc0"); 2881e88a8d6SDavid Lechner 2891e88a8d6SDavid Lechner return 0; 2901e88a8d6SDavid Lechner } 2911e88a8d6SDavid Lechner 2921e88a8d6SDavid Lechner static const struct da8xx_cfgchip_mux_clk_info da850_async3_info __initconst = { 2931e88a8d6SDavid Lechner .name = "async3", 2941e88a8d6SDavid Lechner .parent0 = "pll0_sysclk2", 2951e88a8d6SDavid Lechner .parent1 = "pll1_sysclk2", 2961e88a8d6SDavid Lechner .cfgchip = CFGCHIP(3), 2971e88a8d6SDavid Lechner .bit = CFGCHIP3_ASYNC3_CLKSRC, 2981e88a8d6SDavid Lechner }; 2991e88a8d6SDavid Lechner 3001e88a8d6SDavid Lechner static int __init da850_cfgchip_register_async3(struct device *dev, 3011e88a8d6SDavid Lechner struct regmap *regmap) 3021e88a8d6SDavid Lechner { 3031e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 3041e88a8d6SDavid Lechner struct clk_hw *parent; 3051e88a8d6SDavid Lechner 3061e88a8d6SDavid Lechner mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async3_info, regmap); 3071e88a8d6SDavid Lechner if (IS_ERR(mux)) 3081e88a8d6SDavid Lechner return PTR_ERR(mux); 3091e88a8d6SDavid Lechner 3101e88a8d6SDavid Lechner clk_hw_register_clkdev(&mux->hw, "async3", "da850-psc1"); 3111e88a8d6SDavid Lechner 3121e88a8d6SDavid Lechner /* pll1_sysclk2 is not affected by CPU scaling, so use it for async3 */ 3131e88a8d6SDavid Lechner parent = clk_hw_get_parent_by_index(&mux->hw, 1); 3141e88a8d6SDavid Lechner if (parent) 3151e88a8d6SDavid Lechner clk_set_parent(mux->hw.clk, parent->clk); 3161e88a8d6SDavid Lechner else 3171e88a8d6SDavid Lechner dev_warn(dev, "Failed to find async3 parent clock\n"); 3181e88a8d6SDavid Lechner 3191e88a8d6SDavid Lechner return 0; 3201e88a8d6SDavid Lechner } 3211e88a8d6SDavid Lechner 3221e88a8d6SDavid Lechner static int __init 3231e88a8d6SDavid Lechner of_da8xx_cfgchip_init_mux_clock(struct device *dev, 3241e88a8d6SDavid Lechner const struct da8xx_cfgchip_mux_clk_info *info, 3251e88a8d6SDavid Lechner struct regmap *regmap) 3261e88a8d6SDavid Lechner { 3271e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 3281e88a8d6SDavid Lechner 3291e88a8d6SDavid Lechner mux = da8xx_cfgchip_mux_clk_register(dev, info, regmap); 3301e88a8d6SDavid Lechner if (IS_ERR(mux)) 3311e88a8d6SDavid Lechner return PTR_ERR(mux); 3321e88a8d6SDavid Lechner 3331e88a8d6SDavid Lechner return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &mux->hw); 3341e88a8d6SDavid Lechner } 3351e88a8d6SDavid Lechner 3361e88a8d6SDavid Lechner static int __init of_da850_async1_init(struct device *dev, struct regmap *regmap) 3371e88a8d6SDavid Lechner { 3381e88a8d6SDavid Lechner return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async1_info, regmap); 3391e88a8d6SDavid Lechner } 3401e88a8d6SDavid Lechner 3411e88a8d6SDavid Lechner static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap) 3421e88a8d6SDavid Lechner { 3431e88a8d6SDavid Lechner return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async3_info, regmap); 3441e88a8d6SDavid Lechner } 3451e88a8d6SDavid Lechner 3461e88a8d6SDavid Lechner /* --- platform device --- */ 3471e88a8d6SDavid Lechner 3481e88a8d6SDavid Lechner static const struct of_device_id da8xx_cfgchip_of_match[] = { 3491e88a8d6SDavid Lechner { 3501e88a8d6SDavid Lechner .compatible = "ti,da830-tbclksync", 3511e88a8d6SDavid Lechner .data = of_da8xx_tbclksync_init, 3521e88a8d6SDavid Lechner }, 3531e88a8d6SDavid Lechner { 3541e88a8d6SDavid Lechner .compatible = "ti,da830-div4p5ena", 3551e88a8d6SDavid Lechner .data = of_da8xx_div4p5ena_init, 3561e88a8d6SDavid Lechner }, 3571e88a8d6SDavid Lechner { 3581e88a8d6SDavid Lechner .compatible = "ti,da850-async1-clksrc", 3591e88a8d6SDavid Lechner .data = of_da850_async1_init, 3601e88a8d6SDavid Lechner }, 3611e88a8d6SDavid Lechner { 3621e88a8d6SDavid Lechner .compatible = "ti,da850-async3-clksrc", 3631e88a8d6SDavid Lechner .data = of_da850_async3_init, 3641e88a8d6SDavid Lechner }, 3651e88a8d6SDavid Lechner { } 3661e88a8d6SDavid Lechner }; 3671e88a8d6SDavid Lechner 3681e88a8d6SDavid Lechner static const struct platform_device_id da8xx_cfgchip_id_table[] = { 3691e88a8d6SDavid Lechner { 3701e88a8d6SDavid Lechner .name = "da830-tbclksync", 3711e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_tbclk, 3721e88a8d6SDavid Lechner }, 3731e88a8d6SDavid Lechner { 3741e88a8d6SDavid Lechner .name = "da830-div4p5ena", 3751e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_div4p5, 3761e88a8d6SDavid Lechner }, 3771e88a8d6SDavid Lechner { 3781e88a8d6SDavid Lechner .name = "da850-async1-clksrc", 3791e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_async1, 3801e88a8d6SDavid Lechner }, 3811e88a8d6SDavid Lechner { 3821e88a8d6SDavid Lechner .name = "da850-async3-clksrc", 3831e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da850_cfgchip_register_async3, 3841e88a8d6SDavid Lechner }, 3851e88a8d6SDavid Lechner { } 3861e88a8d6SDavid Lechner }; 3871e88a8d6SDavid Lechner 3881e88a8d6SDavid Lechner typedef int (*da8xx_cfgchip_init)(struct device *dev, struct regmap *regmap); 3891e88a8d6SDavid Lechner 3901e88a8d6SDavid Lechner static int da8xx_cfgchip_probe(struct platform_device *pdev) 3911e88a8d6SDavid Lechner { 3921e88a8d6SDavid Lechner struct device *dev = &pdev->dev; 3931e88a8d6SDavid Lechner struct da8xx_cfgchip_clk_platform_data *pdata = dev->platform_data; 3941e88a8d6SDavid Lechner const struct of_device_id *of_id; 3951e88a8d6SDavid Lechner da8xx_cfgchip_init clk_init = NULL; 3961e88a8d6SDavid Lechner struct regmap *regmap = NULL; 3971e88a8d6SDavid Lechner 3981e88a8d6SDavid Lechner of_id = of_match_device(da8xx_cfgchip_of_match, dev); 3991e88a8d6SDavid Lechner if (of_id) { 4001e88a8d6SDavid Lechner struct device_node *parent; 4011e88a8d6SDavid Lechner 4021e88a8d6SDavid Lechner clk_init = of_id->data; 4031e88a8d6SDavid Lechner parent = of_get_parent(dev->of_node); 4041e88a8d6SDavid Lechner regmap = syscon_node_to_regmap(parent); 4051e88a8d6SDavid Lechner of_node_put(parent); 4061e88a8d6SDavid Lechner } else if (pdev->id_entry && pdata) { 4071e88a8d6SDavid Lechner clk_init = (void *)pdev->id_entry->driver_data; 4081e88a8d6SDavid Lechner regmap = pdata->cfgchip; 4091e88a8d6SDavid Lechner } 4101e88a8d6SDavid Lechner 4111e88a8d6SDavid Lechner if (!clk_init) { 4121e88a8d6SDavid Lechner dev_err(dev, "unable to find driver data\n"); 4131e88a8d6SDavid Lechner return -EINVAL; 4141e88a8d6SDavid Lechner } 4151e88a8d6SDavid Lechner 4161e88a8d6SDavid Lechner if (IS_ERR_OR_NULL(regmap)) { 4171e88a8d6SDavid Lechner dev_err(dev, "no regmap for CFGCHIP syscon\n"); 4181e88a8d6SDavid Lechner return regmap ? PTR_ERR(regmap) : -ENOENT; 4191e88a8d6SDavid Lechner } 4201e88a8d6SDavid Lechner 4211e88a8d6SDavid Lechner return clk_init(dev, regmap); 4221e88a8d6SDavid Lechner } 4231e88a8d6SDavid Lechner 4241e88a8d6SDavid Lechner static struct platform_driver da8xx_cfgchip_driver = { 4251e88a8d6SDavid Lechner .probe = da8xx_cfgchip_probe, 4261e88a8d6SDavid Lechner .driver = { 4271e88a8d6SDavid Lechner .name = "da8xx-cfgchip-clk", 4281e88a8d6SDavid Lechner .of_match_table = da8xx_cfgchip_of_match, 4291e88a8d6SDavid Lechner }, 4301e88a8d6SDavid Lechner .id_table = da8xx_cfgchip_id_table, 4311e88a8d6SDavid Lechner }; 4321e88a8d6SDavid Lechner 4331e88a8d6SDavid Lechner static int __init da8xx_cfgchip_driver_init(void) 4341e88a8d6SDavid Lechner { 4351e88a8d6SDavid Lechner return platform_driver_register(&da8xx_cfgchip_driver); 4361e88a8d6SDavid Lechner } 4371e88a8d6SDavid Lechner 4381e88a8d6SDavid Lechner /* has to be postcore_initcall because PSC devices depend on the async3 clock */ 4391e88a8d6SDavid Lechner postcore_initcall(da8xx_cfgchip_driver_init); 440