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 16433c70c13SDing Xiang return PTR_ERR_OR_ZERO(gate); 1651e88a8d6SDavid Lechner } 1661e88a8d6SDavid Lechner 1671e88a8d6SDavid Lechner static int __init 1681e88a8d6SDavid Lechner of_da8xx_cfgchip_gate_clk_init(struct device *dev, 1691e88a8d6SDavid Lechner const struct da8xx_cfgchip_gate_clk_info *info, 1701e88a8d6SDavid Lechner struct regmap *regmap) 1711e88a8d6SDavid Lechner { 1721e88a8d6SDavid Lechner struct da8xx_cfgchip_gate_clk *gate; 1731e88a8d6SDavid Lechner 1741e88a8d6SDavid Lechner gate = da8xx_cfgchip_gate_clk_register(dev, info, regmap); 1751e88a8d6SDavid Lechner if (IS_ERR(gate)) 1761e88a8d6SDavid Lechner return PTR_ERR(gate); 1771e88a8d6SDavid Lechner 1781e88a8d6SDavid Lechner return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, gate); 1791e88a8d6SDavid Lechner } 1801e88a8d6SDavid Lechner 1811e88a8d6SDavid Lechner static int __init of_da8xx_tbclksync_init(struct device *dev, 1821e88a8d6SDavid Lechner struct regmap *regmap) 1831e88a8d6SDavid Lechner { 1841e88a8d6SDavid Lechner return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_tbclksync_info, regmap); 1851e88a8d6SDavid Lechner } 1861e88a8d6SDavid Lechner 1871e88a8d6SDavid Lechner static int __init of_da8xx_div4p5ena_init(struct device *dev, 1881e88a8d6SDavid Lechner struct regmap *regmap) 1891e88a8d6SDavid Lechner { 1901e88a8d6SDavid Lechner return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_div4p5ena_info, regmap); 1911e88a8d6SDavid Lechner } 1921e88a8d6SDavid Lechner 1931e88a8d6SDavid Lechner /* --- MUX clocks --- */ 1941e88a8d6SDavid Lechner 1951e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk_info { 1961e88a8d6SDavid Lechner const char *name; 1971e88a8d6SDavid Lechner const char *parent0; 1981e88a8d6SDavid Lechner const char *parent1; 1991e88a8d6SDavid Lechner u32 cfgchip; 2001e88a8d6SDavid Lechner u32 bit; 2011e88a8d6SDavid Lechner }; 2021e88a8d6SDavid Lechner 2031e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk { 2041e88a8d6SDavid Lechner struct clk_hw hw; 2051e88a8d6SDavid Lechner struct regmap *regmap; 2061e88a8d6SDavid Lechner u32 reg; 2071e88a8d6SDavid Lechner u32 mask; 2081e88a8d6SDavid Lechner }; 2091e88a8d6SDavid Lechner 2101e88a8d6SDavid Lechner #define to_da8xx_cfgchip_mux_clk(_hw) \ 2111e88a8d6SDavid Lechner container_of((_hw), struct da8xx_cfgchip_mux_clk, hw) 2121e88a8d6SDavid Lechner 2131e88a8d6SDavid Lechner static int da8xx_cfgchip_mux_clk_set_parent(struct clk_hw *hw, u8 index) 2141e88a8d6SDavid Lechner { 2151e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw); 2161e88a8d6SDavid Lechner unsigned int val = index ? clk->mask : 0; 2171e88a8d6SDavid Lechner 2181e88a8d6SDavid Lechner return regmap_write_bits(clk->regmap, clk->reg, clk->mask, val); 2191e88a8d6SDavid Lechner } 2201e88a8d6SDavid Lechner 2211e88a8d6SDavid Lechner static u8 da8xx_cfgchip_mux_clk_get_parent(struct clk_hw *hw) 2221e88a8d6SDavid Lechner { 2231e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw); 2241e88a8d6SDavid Lechner unsigned int val; 2251e88a8d6SDavid Lechner 2261e88a8d6SDavid Lechner regmap_read(clk->regmap, clk->reg, &val); 2271e88a8d6SDavid Lechner 2281e88a8d6SDavid Lechner return (val & clk->mask) ? 1 : 0; 2291e88a8d6SDavid Lechner } 2301e88a8d6SDavid Lechner 2311e88a8d6SDavid Lechner static const struct clk_ops da8xx_cfgchip_mux_clk_ops = { 232de9271f2SMaxime Ripard .determine_rate = clk_hw_determine_rate_no_reparent, 2331e88a8d6SDavid Lechner .set_parent = da8xx_cfgchip_mux_clk_set_parent, 2341e88a8d6SDavid Lechner .get_parent = da8xx_cfgchip_mux_clk_get_parent, 2351e88a8d6SDavid Lechner }; 2361e88a8d6SDavid Lechner 2371e88a8d6SDavid Lechner static struct da8xx_cfgchip_mux_clk * __init 2381e88a8d6SDavid Lechner da8xx_cfgchip_mux_clk_register(struct device *dev, 2391e88a8d6SDavid Lechner const struct da8xx_cfgchip_mux_clk_info *info, 2401e88a8d6SDavid Lechner struct regmap *regmap) 2411e88a8d6SDavid Lechner { 2421e88a8d6SDavid Lechner const char * const parent_names[] = { info->parent0, info->parent1 }; 2431e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 2441e88a8d6SDavid Lechner struct clk_init_data init; 2451e88a8d6SDavid Lechner int ret; 2461e88a8d6SDavid Lechner 2471e88a8d6SDavid Lechner mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); 2481e88a8d6SDavid Lechner if (!mux) 2491e88a8d6SDavid Lechner return ERR_PTR(-ENOMEM); 2501e88a8d6SDavid Lechner 2511e88a8d6SDavid Lechner init.name = info->name; 2521e88a8d6SDavid Lechner init.ops = &da8xx_cfgchip_mux_clk_ops; 2531e88a8d6SDavid Lechner init.parent_names = parent_names; 2541e88a8d6SDavid Lechner init.num_parents = 2; 2551e88a8d6SDavid Lechner init.flags = 0; 2561e88a8d6SDavid Lechner 2571e88a8d6SDavid Lechner mux->hw.init = &init; 2581e88a8d6SDavid Lechner mux->regmap = regmap; 2591e88a8d6SDavid Lechner mux->reg = info->cfgchip; 2601e88a8d6SDavid Lechner mux->mask = info->bit; 2611e88a8d6SDavid Lechner 2621e88a8d6SDavid Lechner ret = devm_clk_hw_register(dev, &mux->hw); 2631e88a8d6SDavid Lechner if (ret < 0) 2641e88a8d6SDavid Lechner return ERR_PTR(ret); 2651e88a8d6SDavid Lechner 2661e88a8d6SDavid Lechner return mux; 2671e88a8d6SDavid Lechner } 2681e88a8d6SDavid Lechner 2691e88a8d6SDavid Lechner static const struct da8xx_cfgchip_mux_clk_info da850_async1_info __initconst = { 2701e88a8d6SDavid Lechner .name = "async1", 2711e88a8d6SDavid Lechner .parent0 = "pll0_sysclk3", 2721e88a8d6SDavid Lechner .parent1 = "div4.5", 2731e88a8d6SDavid Lechner .cfgchip = CFGCHIP(3), 2741e88a8d6SDavid Lechner .bit = CFGCHIP3_EMA_CLKSRC, 2751e88a8d6SDavid Lechner }; 2761e88a8d6SDavid Lechner 2771e88a8d6SDavid Lechner static int __init da8xx_cfgchip_register_async1(struct device *dev, 2781e88a8d6SDavid Lechner struct regmap *regmap) 2791e88a8d6SDavid Lechner { 2801e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 2811e88a8d6SDavid Lechner 2821e88a8d6SDavid Lechner mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async1_info, regmap); 2831e88a8d6SDavid Lechner if (IS_ERR(mux)) 2841e88a8d6SDavid Lechner return PTR_ERR(mux); 2851e88a8d6SDavid Lechner 2861e88a8d6SDavid Lechner clk_hw_register_clkdev(&mux->hw, "async1", "da850-psc0"); 2871e88a8d6SDavid Lechner 2881e88a8d6SDavid Lechner return 0; 2891e88a8d6SDavid Lechner } 2901e88a8d6SDavid Lechner 2911e88a8d6SDavid Lechner static const struct da8xx_cfgchip_mux_clk_info da850_async3_info __initconst = { 2921e88a8d6SDavid Lechner .name = "async3", 2931e88a8d6SDavid Lechner .parent0 = "pll0_sysclk2", 2941e88a8d6SDavid Lechner .parent1 = "pll1_sysclk2", 2951e88a8d6SDavid Lechner .cfgchip = CFGCHIP(3), 2961e88a8d6SDavid Lechner .bit = CFGCHIP3_ASYNC3_CLKSRC, 2971e88a8d6SDavid Lechner }; 2981e88a8d6SDavid Lechner 2991e88a8d6SDavid Lechner static int __init da850_cfgchip_register_async3(struct device *dev, 3001e88a8d6SDavid Lechner struct regmap *regmap) 3011e88a8d6SDavid Lechner { 3021e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 3031e88a8d6SDavid Lechner struct clk_hw *parent; 3041e88a8d6SDavid Lechner 3051e88a8d6SDavid Lechner mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async3_info, regmap); 3061e88a8d6SDavid Lechner if (IS_ERR(mux)) 3071e88a8d6SDavid Lechner return PTR_ERR(mux); 3081e88a8d6SDavid Lechner 3091e88a8d6SDavid Lechner clk_hw_register_clkdev(&mux->hw, "async3", "da850-psc1"); 3101e88a8d6SDavid Lechner 3111e88a8d6SDavid Lechner /* pll1_sysclk2 is not affected by CPU scaling, so use it for async3 */ 3121e88a8d6SDavid Lechner parent = clk_hw_get_parent_by_index(&mux->hw, 1); 3131e88a8d6SDavid Lechner if (parent) 3141e88a8d6SDavid Lechner clk_set_parent(mux->hw.clk, parent->clk); 3151e88a8d6SDavid Lechner else 3161e88a8d6SDavid Lechner dev_warn(dev, "Failed to find async3 parent clock\n"); 3171e88a8d6SDavid Lechner 3181e88a8d6SDavid Lechner return 0; 3191e88a8d6SDavid Lechner } 3201e88a8d6SDavid Lechner 3211e88a8d6SDavid Lechner static int __init 3221e88a8d6SDavid Lechner of_da8xx_cfgchip_init_mux_clock(struct device *dev, 3231e88a8d6SDavid Lechner const struct da8xx_cfgchip_mux_clk_info *info, 3241e88a8d6SDavid Lechner struct regmap *regmap) 3251e88a8d6SDavid Lechner { 3261e88a8d6SDavid Lechner struct da8xx_cfgchip_mux_clk *mux; 3271e88a8d6SDavid Lechner 3281e88a8d6SDavid Lechner mux = da8xx_cfgchip_mux_clk_register(dev, info, regmap); 3291e88a8d6SDavid Lechner if (IS_ERR(mux)) 3301e88a8d6SDavid Lechner return PTR_ERR(mux); 3311e88a8d6SDavid Lechner 3321e88a8d6SDavid Lechner return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &mux->hw); 3331e88a8d6SDavid Lechner } 3341e88a8d6SDavid Lechner 3351e88a8d6SDavid Lechner static int __init of_da850_async1_init(struct device *dev, struct regmap *regmap) 3361e88a8d6SDavid Lechner { 3371e88a8d6SDavid Lechner return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async1_info, regmap); 3381e88a8d6SDavid Lechner } 3391e88a8d6SDavid Lechner 3401e88a8d6SDavid Lechner static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap) 3411e88a8d6SDavid Lechner { 3421e88a8d6SDavid Lechner return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async3_info, regmap); 3431e88a8d6SDavid Lechner } 3441e88a8d6SDavid Lechner 34558e1e2d2SDavid Lechner /* --- USB 2.0 PHY clock --- */ 34658e1e2d2SDavid Lechner 34758e1e2d2SDavid Lechner struct da8xx_usb0_clk48 { 34858e1e2d2SDavid Lechner struct clk_hw hw; 34958e1e2d2SDavid Lechner struct clk *fck; 35058e1e2d2SDavid Lechner struct regmap *regmap; 35158e1e2d2SDavid Lechner }; 35258e1e2d2SDavid Lechner 35358e1e2d2SDavid Lechner #define to_da8xx_usb0_clk48(_hw) \ 35458e1e2d2SDavid Lechner container_of((_hw), struct da8xx_usb0_clk48, hw) 35558e1e2d2SDavid Lechner 35658e1e2d2SDavid Lechner static int da8xx_usb0_clk48_prepare(struct clk_hw *hw) 35758e1e2d2SDavid Lechner { 35858e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 35958e1e2d2SDavid Lechner 36058e1e2d2SDavid Lechner /* The USB 2.0 PSC clock is only needed temporarily during the USB 2.0 36158e1e2d2SDavid Lechner * PHY clock enable, but since clk_prepare() can't be called in an 36258e1e2d2SDavid Lechner * atomic context (i.e. in clk_enable()), we have to prepare it here. 36358e1e2d2SDavid Lechner */ 36458e1e2d2SDavid Lechner return clk_prepare(usb0->fck); 36558e1e2d2SDavid Lechner } 36658e1e2d2SDavid Lechner 36758e1e2d2SDavid Lechner static void da8xx_usb0_clk48_unprepare(struct clk_hw *hw) 36858e1e2d2SDavid Lechner { 36958e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 37058e1e2d2SDavid Lechner 37158e1e2d2SDavid Lechner clk_unprepare(usb0->fck); 37258e1e2d2SDavid Lechner } 37358e1e2d2SDavid Lechner 37458e1e2d2SDavid Lechner static int da8xx_usb0_clk48_enable(struct clk_hw *hw) 37558e1e2d2SDavid Lechner { 37658e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 37758e1e2d2SDavid Lechner unsigned int mask, val; 37858e1e2d2SDavid Lechner int ret; 37958e1e2d2SDavid Lechner 38058e1e2d2SDavid Lechner /* Locking the USB 2.O PLL requires that the USB 2.O PSC is enabled 38158e1e2d2SDavid Lechner * temporaily. It can be turned back off once the PLL is locked. 38258e1e2d2SDavid Lechner */ 38358e1e2d2SDavid Lechner clk_enable(usb0->fck); 38458e1e2d2SDavid Lechner 38558e1e2d2SDavid Lechner /* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 38658e1e2d2SDavid Lechner * PHY may use the USB 2.0 PLL clock without USB 2.0 OTG being used. 38758e1e2d2SDavid Lechner */ 38858e1e2d2SDavid Lechner mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_PHY_PLLON; 38958e1e2d2SDavid Lechner val = CFGCHIP2_PHY_PLLON; 39058e1e2d2SDavid Lechner 39158e1e2d2SDavid Lechner regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); 39258e1e2d2SDavid Lechner ret = regmap_read_poll_timeout(usb0->regmap, CFGCHIP(2), val, 39358e1e2d2SDavid Lechner val & CFGCHIP2_PHYCLKGD, 0, 500000); 39458e1e2d2SDavid Lechner 39558e1e2d2SDavid Lechner clk_disable(usb0->fck); 39658e1e2d2SDavid Lechner 39758e1e2d2SDavid Lechner return ret; 39858e1e2d2SDavid Lechner } 39958e1e2d2SDavid Lechner 40058e1e2d2SDavid Lechner static void da8xx_usb0_clk48_disable(struct clk_hw *hw) 40158e1e2d2SDavid Lechner { 40258e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 40358e1e2d2SDavid Lechner unsigned int val; 40458e1e2d2SDavid Lechner 40558e1e2d2SDavid Lechner val = CFGCHIP2_PHYPWRDN; 40658e1e2d2SDavid Lechner regmap_write_bits(usb0->regmap, CFGCHIP(2), val, val); 40758e1e2d2SDavid Lechner } 40858e1e2d2SDavid Lechner 40958e1e2d2SDavid Lechner static int da8xx_usb0_clk48_is_enabled(struct clk_hw *hw) 41058e1e2d2SDavid Lechner { 41158e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 41258e1e2d2SDavid Lechner unsigned int val; 41358e1e2d2SDavid Lechner 41458e1e2d2SDavid Lechner regmap_read(usb0->regmap, CFGCHIP(2), &val); 41558e1e2d2SDavid Lechner 41658e1e2d2SDavid Lechner return !!(val & CFGCHIP2_PHYCLKGD); 41758e1e2d2SDavid Lechner } 41858e1e2d2SDavid Lechner 41958e1e2d2SDavid Lechner static unsigned long da8xx_usb0_clk48_recalc_rate(struct clk_hw *hw, 42058e1e2d2SDavid Lechner unsigned long parent_rate) 42158e1e2d2SDavid Lechner { 42258e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 42358e1e2d2SDavid Lechner unsigned int mask, val; 42458e1e2d2SDavid Lechner 42558e1e2d2SDavid Lechner /* The parent clock rate must be one of the following */ 42658e1e2d2SDavid Lechner mask = CFGCHIP2_REFFREQ_MASK; 42758e1e2d2SDavid Lechner switch (parent_rate) { 42858e1e2d2SDavid Lechner case 12000000: 42958e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_12MHZ; 43058e1e2d2SDavid Lechner break; 43158e1e2d2SDavid Lechner case 13000000: 43258e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_13MHZ; 43358e1e2d2SDavid Lechner break; 43458e1e2d2SDavid Lechner case 19200000: 43558e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_19_2MHZ; 43658e1e2d2SDavid Lechner break; 43758e1e2d2SDavid Lechner case 20000000: 43858e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_20MHZ; 43958e1e2d2SDavid Lechner break; 44058e1e2d2SDavid Lechner case 24000000: 44158e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_24MHZ; 44258e1e2d2SDavid Lechner break; 44358e1e2d2SDavid Lechner case 26000000: 44458e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_26MHZ; 44558e1e2d2SDavid Lechner break; 44658e1e2d2SDavid Lechner case 38400000: 44758e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_38_4MHZ; 44858e1e2d2SDavid Lechner break; 44958e1e2d2SDavid Lechner case 40000000: 45058e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_40MHZ; 45158e1e2d2SDavid Lechner break; 45258e1e2d2SDavid Lechner case 48000000: 45358e1e2d2SDavid Lechner val = CFGCHIP2_REFFREQ_48MHZ; 45458e1e2d2SDavid Lechner break; 45558e1e2d2SDavid Lechner default: 45658e1e2d2SDavid Lechner return 0; 45758e1e2d2SDavid Lechner } 45858e1e2d2SDavid Lechner 45958e1e2d2SDavid Lechner regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); 46058e1e2d2SDavid Lechner 46158e1e2d2SDavid Lechner /* USB 2.0 PLL always supplies 48MHz */ 46258e1e2d2SDavid Lechner return 48000000; 46358e1e2d2SDavid Lechner } 46458e1e2d2SDavid Lechner 46558e1e2d2SDavid Lechner static long da8xx_usb0_clk48_round_rate(struct clk_hw *hw, unsigned long rate, 46658e1e2d2SDavid Lechner unsigned long *parent_rate) 46758e1e2d2SDavid Lechner { 46858e1e2d2SDavid Lechner return 48000000; 46958e1e2d2SDavid Lechner } 47058e1e2d2SDavid Lechner 47158e1e2d2SDavid Lechner static int da8xx_usb0_clk48_set_parent(struct clk_hw *hw, u8 index) 47258e1e2d2SDavid Lechner { 47358e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 47458e1e2d2SDavid Lechner 47558e1e2d2SDavid Lechner return regmap_write_bits(usb0->regmap, CFGCHIP(2), 47658e1e2d2SDavid Lechner CFGCHIP2_USB2PHYCLKMUX, 47758e1e2d2SDavid Lechner index ? CFGCHIP2_USB2PHYCLKMUX : 0); 47858e1e2d2SDavid Lechner } 47958e1e2d2SDavid Lechner 48058e1e2d2SDavid Lechner static u8 da8xx_usb0_clk48_get_parent(struct clk_hw *hw) 48158e1e2d2SDavid Lechner { 48258e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); 48358e1e2d2SDavid Lechner unsigned int val; 48458e1e2d2SDavid Lechner 48558e1e2d2SDavid Lechner regmap_read(usb0->regmap, CFGCHIP(2), &val); 48658e1e2d2SDavid Lechner 48758e1e2d2SDavid Lechner return (val & CFGCHIP2_USB2PHYCLKMUX) ? 1 : 0; 48858e1e2d2SDavid Lechner } 48958e1e2d2SDavid Lechner 49058e1e2d2SDavid Lechner static const struct clk_ops da8xx_usb0_clk48_ops = { 49158e1e2d2SDavid Lechner .prepare = da8xx_usb0_clk48_prepare, 49258e1e2d2SDavid Lechner .unprepare = da8xx_usb0_clk48_unprepare, 49358e1e2d2SDavid Lechner .enable = da8xx_usb0_clk48_enable, 49458e1e2d2SDavid Lechner .disable = da8xx_usb0_clk48_disable, 49558e1e2d2SDavid Lechner .is_enabled = da8xx_usb0_clk48_is_enabled, 49658e1e2d2SDavid Lechner .recalc_rate = da8xx_usb0_clk48_recalc_rate, 49758e1e2d2SDavid Lechner .round_rate = da8xx_usb0_clk48_round_rate, 49858e1e2d2SDavid Lechner .set_parent = da8xx_usb0_clk48_set_parent, 49958e1e2d2SDavid Lechner .get_parent = da8xx_usb0_clk48_get_parent, 50058e1e2d2SDavid Lechner }; 50158e1e2d2SDavid Lechner 50258e1e2d2SDavid Lechner static struct da8xx_usb0_clk48 * 50358e1e2d2SDavid Lechner da8xx_cfgchip_register_usb0_clk48(struct device *dev, 50458e1e2d2SDavid Lechner struct regmap *regmap) 50558e1e2d2SDavid Lechner { 50658e1e2d2SDavid Lechner const char * const parent_names[] = { "usb_refclkin", "pll0_auxclk" }; 50758e1e2d2SDavid Lechner struct clk *fck_clk; 50858e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0; 50958e1e2d2SDavid Lechner struct clk_init_data init; 51058e1e2d2SDavid Lechner int ret; 51158e1e2d2SDavid Lechner 51258e1e2d2SDavid Lechner fck_clk = devm_clk_get(dev, "fck"); 51358e1e2d2SDavid Lechner if (IS_ERR(fck_clk)) { 5143475c885SYang Yingliang dev_err_probe(dev, PTR_ERR(fck_clk), "Missing fck clock\n"); 51558e1e2d2SDavid Lechner return ERR_CAST(fck_clk); 51658e1e2d2SDavid Lechner } 51758e1e2d2SDavid Lechner 51858e1e2d2SDavid Lechner usb0 = devm_kzalloc(dev, sizeof(*usb0), GFP_KERNEL); 51958e1e2d2SDavid Lechner if (!usb0) 52058e1e2d2SDavid Lechner return ERR_PTR(-ENOMEM); 52158e1e2d2SDavid Lechner 52258e1e2d2SDavid Lechner init.name = "usb0_clk48"; 52358e1e2d2SDavid Lechner init.ops = &da8xx_usb0_clk48_ops; 52458e1e2d2SDavid Lechner init.parent_names = parent_names; 52558e1e2d2SDavid Lechner init.num_parents = 2; 52658e1e2d2SDavid Lechner 52758e1e2d2SDavid Lechner usb0->hw.init = &init; 52858e1e2d2SDavid Lechner usb0->fck = fck_clk; 52958e1e2d2SDavid Lechner usb0->regmap = regmap; 53058e1e2d2SDavid Lechner 53158e1e2d2SDavid Lechner ret = devm_clk_hw_register(dev, &usb0->hw); 53258e1e2d2SDavid Lechner if (ret < 0) 53358e1e2d2SDavid Lechner return ERR_PTR(ret); 53458e1e2d2SDavid Lechner 53558e1e2d2SDavid Lechner return usb0; 53658e1e2d2SDavid Lechner } 53758e1e2d2SDavid Lechner 53858e1e2d2SDavid Lechner /* --- USB 1.1 PHY clock --- */ 53958e1e2d2SDavid Lechner 54058e1e2d2SDavid Lechner struct da8xx_usb1_clk48 { 54158e1e2d2SDavid Lechner struct clk_hw hw; 54258e1e2d2SDavid Lechner struct regmap *regmap; 54358e1e2d2SDavid Lechner }; 54458e1e2d2SDavid Lechner 54558e1e2d2SDavid Lechner #define to_da8xx_usb1_clk48(_hw) \ 54658e1e2d2SDavid Lechner container_of((_hw), struct da8xx_usb1_clk48, hw) 54758e1e2d2SDavid Lechner 54858e1e2d2SDavid Lechner static int da8xx_usb1_clk48_set_parent(struct clk_hw *hw, u8 index) 54958e1e2d2SDavid Lechner { 55058e1e2d2SDavid Lechner struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw); 55158e1e2d2SDavid Lechner 55258e1e2d2SDavid Lechner return regmap_write_bits(usb1->regmap, CFGCHIP(2), 55358e1e2d2SDavid Lechner CFGCHIP2_USB1PHYCLKMUX, 55458e1e2d2SDavid Lechner index ? CFGCHIP2_USB1PHYCLKMUX : 0); 55558e1e2d2SDavid Lechner } 55658e1e2d2SDavid Lechner 55758e1e2d2SDavid Lechner static u8 da8xx_usb1_clk48_get_parent(struct clk_hw *hw) 55858e1e2d2SDavid Lechner { 55958e1e2d2SDavid Lechner struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw); 56058e1e2d2SDavid Lechner unsigned int val; 56158e1e2d2SDavid Lechner 56258e1e2d2SDavid Lechner regmap_read(usb1->regmap, CFGCHIP(2), &val); 56358e1e2d2SDavid Lechner 56458e1e2d2SDavid Lechner return (val & CFGCHIP2_USB1PHYCLKMUX) ? 1 : 0; 56558e1e2d2SDavid Lechner } 56658e1e2d2SDavid Lechner 56758e1e2d2SDavid Lechner static const struct clk_ops da8xx_usb1_clk48_ops = { 568*4d8aa2a3SMaxime Ripard .determine_rate = clk_hw_determine_rate_no_reparent, 56958e1e2d2SDavid Lechner .set_parent = da8xx_usb1_clk48_set_parent, 57058e1e2d2SDavid Lechner .get_parent = da8xx_usb1_clk48_get_parent, 57158e1e2d2SDavid Lechner }; 57258e1e2d2SDavid Lechner 57358e1e2d2SDavid Lechner /** 57458e1e2d2SDavid Lechner * da8xx_cfgchip_register_usb1_clk48 - Register a new USB 1.1 PHY clock 575faeda014SKrzysztof Kozlowski * @dev: The device 57658e1e2d2SDavid Lechner * @regmap: The CFGCHIP regmap 57758e1e2d2SDavid Lechner */ 57858e1e2d2SDavid Lechner static struct da8xx_usb1_clk48 * 57958e1e2d2SDavid Lechner da8xx_cfgchip_register_usb1_clk48(struct device *dev, 58058e1e2d2SDavid Lechner struct regmap *regmap) 58158e1e2d2SDavid Lechner { 58258e1e2d2SDavid Lechner const char * const parent_names[] = { "usb0_clk48", "usb_refclkin" }; 58358e1e2d2SDavid Lechner struct da8xx_usb1_clk48 *usb1; 58458e1e2d2SDavid Lechner struct clk_init_data init; 58558e1e2d2SDavid Lechner int ret; 58658e1e2d2SDavid Lechner 58758e1e2d2SDavid Lechner usb1 = devm_kzalloc(dev, sizeof(*usb1), GFP_KERNEL); 58858e1e2d2SDavid Lechner if (!usb1) 58958e1e2d2SDavid Lechner return ERR_PTR(-ENOMEM); 59058e1e2d2SDavid Lechner 59158e1e2d2SDavid Lechner init.name = "usb1_clk48"; 59258e1e2d2SDavid Lechner init.ops = &da8xx_usb1_clk48_ops; 59358e1e2d2SDavid Lechner init.parent_names = parent_names; 59458e1e2d2SDavid Lechner init.num_parents = 2; 59558e1e2d2SDavid Lechner 59658e1e2d2SDavid Lechner usb1->hw.init = &init; 59758e1e2d2SDavid Lechner usb1->regmap = regmap; 59858e1e2d2SDavid Lechner 59958e1e2d2SDavid Lechner ret = devm_clk_hw_register(dev, &usb1->hw); 60058e1e2d2SDavid Lechner if (ret < 0) 60158e1e2d2SDavid Lechner return ERR_PTR(ret); 60258e1e2d2SDavid Lechner 60358e1e2d2SDavid Lechner return usb1; 60458e1e2d2SDavid Lechner } 60558e1e2d2SDavid Lechner 60658e1e2d2SDavid Lechner static int da8xx_cfgchip_register_usb_phy_clk(struct device *dev, 60758e1e2d2SDavid Lechner struct regmap *regmap) 60858e1e2d2SDavid Lechner { 60958e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0; 61058e1e2d2SDavid Lechner struct da8xx_usb1_clk48 *usb1; 61158e1e2d2SDavid Lechner struct clk_hw *parent; 61258e1e2d2SDavid Lechner 61358e1e2d2SDavid Lechner usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap); 61458e1e2d2SDavid Lechner if (IS_ERR(usb0)) 61558e1e2d2SDavid Lechner return PTR_ERR(usb0); 61658e1e2d2SDavid Lechner 61758e1e2d2SDavid Lechner /* 61858e1e2d2SDavid Lechner * All existing boards use pll0_auxclk as the parent and new boards 61958e1e2d2SDavid Lechner * should use device tree, so hard-coding the value (1) here. 62058e1e2d2SDavid Lechner */ 62158e1e2d2SDavid Lechner parent = clk_hw_get_parent_by_index(&usb0->hw, 1); 62258e1e2d2SDavid Lechner if (parent) 62358e1e2d2SDavid Lechner clk_set_parent(usb0->hw.clk, parent->clk); 62458e1e2d2SDavid Lechner else 62558e1e2d2SDavid Lechner dev_warn(dev, "Failed to find usb0 parent clock\n"); 62658e1e2d2SDavid Lechner 62758e1e2d2SDavid Lechner usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap); 62858e1e2d2SDavid Lechner if (IS_ERR(usb1)) 62958e1e2d2SDavid Lechner return PTR_ERR(usb1); 63058e1e2d2SDavid Lechner 63158e1e2d2SDavid Lechner /* 63258e1e2d2SDavid Lechner * All existing boards use usb0_clk48 as the parent and new boards 63358e1e2d2SDavid Lechner * should use device tree, so hard-coding the value (0) here. 63458e1e2d2SDavid Lechner */ 63558e1e2d2SDavid Lechner parent = clk_hw_get_parent_by_index(&usb1->hw, 0); 63658e1e2d2SDavid Lechner if (parent) 63758e1e2d2SDavid Lechner clk_set_parent(usb1->hw.clk, parent->clk); 63858e1e2d2SDavid Lechner else 63958e1e2d2SDavid Lechner dev_warn(dev, "Failed to find usb1 parent clock\n"); 64058e1e2d2SDavid Lechner 64158e1e2d2SDavid Lechner clk_hw_register_clkdev(&usb0->hw, "usb0_clk48", "da8xx-usb-phy"); 64258e1e2d2SDavid Lechner clk_hw_register_clkdev(&usb1->hw, "usb1_clk48", "da8xx-usb-phy"); 64358e1e2d2SDavid Lechner 64458e1e2d2SDavid Lechner return 0; 64558e1e2d2SDavid Lechner } 64658e1e2d2SDavid Lechner 64758e1e2d2SDavid Lechner static int of_da8xx_usb_phy_clk_init(struct device *dev, struct regmap *regmap) 64858e1e2d2SDavid Lechner { 64958e1e2d2SDavid Lechner struct clk_hw_onecell_data *clk_data; 65058e1e2d2SDavid Lechner struct da8xx_usb0_clk48 *usb0; 65158e1e2d2SDavid Lechner struct da8xx_usb1_clk48 *usb1; 65258e1e2d2SDavid Lechner 6530ed2dd03SKees Cook clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, 2), 6540ed2dd03SKees Cook GFP_KERNEL); 65558e1e2d2SDavid Lechner if (!clk_data) 65658e1e2d2SDavid Lechner return -ENOMEM; 65758e1e2d2SDavid Lechner 65858e1e2d2SDavid Lechner clk_data->num = 2; 65958e1e2d2SDavid Lechner 66058e1e2d2SDavid Lechner usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap); 66158e1e2d2SDavid Lechner if (IS_ERR(usb0)) { 66258e1e2d2SDavid Lechner if (PTR_ERR(usb0) == -EPROBE_DEFER) 66358e1e2d2SDavid Lechner return -EPROBE_DEFER; 66458e1e2d2SDavid Lechner 66558e1e2d2SDavid Lechner dev_warn(dev, "Failed to register usb0_clk48 (%ld)\n", 66658e1e2d2SDavid Lechner PTR_ERR(usb0)); 66758e1e2d2SDavid Lechner 66858e1e2d2SDavid Lechner clk_data->hws[0] = ERR_PTR(-ENOENT); 66958e1e2d2SDavid Lechner } else { 67058e1e2d2SDavid Lechner clk_data->hws[0] = &usb0->hw; 67158e1e2d2SDavid Lechner } 67258e1e2d2SDavid Lechner 67358e1e2d2SDavid Lechner usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap); 67458e1e2d2SDavid Lechner if (IS_ERR(usb1)) { 6750613de37SDan Carpenter if (PTR_ERR(usb1) == -EPROBE_DEFER) 67658e1e2d2SDavid Lechner return -EPROBE_DEFER; 67758e1e2d2SDavid Lechner 67858e1e2d2SDavid Lechner dev_warn(dev, "Failed to register usb1_clk48 (%ld)\n", 67958e1e2d2SDavid Lechner PTR_ERR(usb1)); 68058e1e2d2SDavid Lechner 68158e1e2d2SDavid Lechner clk_data->hws[1] = ERR_PTR(-ENOENT); 68258e1e2d2SDavid Lechner } else { 68358e1e2d2SDavid Lechner clk_data->hws[1] = &usb1->hw; 68458e1e2d2SDavid Lechner } 68558e1e2d2SDavid Lechner 68658e1e2d2SDavid Lechner return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); 68758e1e2d2SDavid Lechner } 68858e1e2d2SDavid Lechner 6891e88a8d6SDavid Lechner /* --- platform device --- */ 6901e88a8d6SDavid Lechner 6911e88a8d6SDavid Lechner static const struct of_device_id da8xx_cfgchip_of_match[] = { 6921e88a8d6SDavid Lechner { 6931e88a8d6SDavid Lechner .compatible = "ti,da830-tbclksync", 6941e88a8d6SDavid Lechner .data = of_da8xx_tbclksync_init, 6951e88a8d6SDavid Lechner }, 6961e88a8d6SDavid Lechner { 6971e88a8d6SDavid Lechner .compatible = "ti,da830-div4p5ena", 6981e88a8d6SDavid Lechner .data = of_da8xx_div4p5ena_init, 6991e88a8d6SDavid Lechner }, 7001e88a8d6SDavid Lechner { 7011e88a8d6SDavid Lechner .compatible = "ti,da850-async1-clksrc", 7021e88a8d6SDavid Lechner .data = of_da850_async1_init, 7031e88a8d6SDavid Lechner }, 7041e88a8d6SDavid Lechner { 7051e88a8d6SDavid Lechner .compatible = "ti,da850-async3-clksrc", 7061e88a8d6SDavid Lechner .data = of_da850_async3_init, 7071e88a8d6SDavid Lechner }, 70858e1e2d2SDavid Lechner { 70958e1e2d2SDavid Lechner .compatible = "ti,da830-usb-phy-clocks", 71058e1e2d2SDavid Lechner .data = of_da8xx_usb_phy_clk_init, 71158e1e2d2SDavid Lechner }, 7121e88a8d6SDavid Lechner { } 7131e88a8d6SDavid Lechner }; 7141e88a8d6SDavid Lechner 7151e88a8d6SDavid Lechner static const struct platform_device_id da8xx_cfgchip_id_table[] = { 7161e88a8d6SDavid Lechner { 7171e88a8d6SDavid Lechner .name = "da830-tbclksync", 7181e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_tbclk, 7191e88a8d6SDavid Lechner }, 7201e88a8d6SDavid Lechner { 7211e88a8d6SDavid Lechner .name = "da830-div4p5ena", 7221e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_div4p5, 7231e88a8d6SDavid Lechner }, 7241e88a8d6SDavid Lechner { 7251e88a8d6SDavid Lechner .name = "da850-async1-clksrc", 7261e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_async1, 7271e88a8d6SDavid Lechner }, 7281e88a8d6SDavid Lechner { 7291e88a8d6SDavid Lechner .name = "da850-async3-clksrc", 7301e88a8d6SDavid Lechner .driver_data = (kernel_ulong_t)da850_cfgchip_register_async3, 7311e88a8d6SDavid Lechner }, 73258e1e2d2SDavid Lechner { 73358e1e2d2SDavid Lechner .name = "da830-usb-phy-clks", 73458e1e2d2SDavid Lechner .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_usb_phy_clk, 73558e1e2d2SDavid Lechner }, 7361e88a8d6SDavid Lechner { } 7371e88a8d6SDavid Lechner }; 7381e88a8d6SDavid Lechner 7391e88a8d6SDavid Lechner typedef int (*da8xx_cfgchip_init)(struct device *dev, struct regmap *regmap); 7401e88a8d6SDavid Lechner 7411e88a8d6SDavid Lechner static int da8xx_cfgchip_probe(struct platform_device *pdev) 7421e88a8d6SDavid Lechner { 7431e88a8d6SDavid Lechner struct device *dev = &pdev->dev; 7441e88a8d6SDavid Lechner struct da8xx_cfgchip_clk_platform_data *pdata = dev->platform_data; 7451e88a8d6SDavid Lechner const struct of_device_id *of_id; 7461e88a8d6SDavid Lechner da8xx_cfgchip_init clk_init = NULL; 7471e88a8d6SDavid Lechner struct regmap *regmap = NULL; 7481e88a8d6SDavid Lechner 7491e88a8d6SDavid Lechner of_id = of_match_device(da8xx_cfgchip_of_match, dev); 7501e88a8d6SDavid Lechner if (of_id) { 7511e88a8d6SDavid Lechner struct device_node *parent; 7521e88a8d6SDavid Lechner 7531e88a8d6SDavid Lechner clk_init = of_id->data; 7541e88a8d6SDavid Lechner parent = of_get_parent(dev->of_node); 7551e88a8d6SDavid Lechner regmap = syscon_node_to_regmap(parent); 7561e88a8d6SDavid Lechner of_node_put(parent); 7571e88a8d6SDavid Lechner } else if (pdev->id_entry && pdata) { 7581e88a8d6SDavid Lechner clk_init = (void *)pdev->id_entry->driver_data; 7591e88a8d6SDavid Lechner regmap = pdata->cfgchip; 7601e88a8d6SDavid Lechner } 7611e88a8d6SDavid Lechner 7621e88a8d6SDavid Lechner if (!clk_init) { 7631e88a8d6SDavid Lechner dev_err(dev, "unable to find driver data\n"); 7641e88a8d6SDavid Lechner return -EINVAL; 7651e88a8d6SDavid Lechner } 7661e88a8d6SDavid Lechner 7671e88a8d6SDavid Lechner if (IS_ERR_OR_NULL(regmap)) { 7681e88a8d6SDavid Lechner dev_err(dev, "no regmap for CFGCHIP syscon\n"); 7691e88a8d6SDavid Lechner return regmap ? PTR_ERR(regmap) : -ENOENT; 7701e88a8d6SDavid Lechner } 7711e88a8d6SDavid Lechner 7721e88a8d6SDavid Lechner return clk_init(dev, regmap); 7731e88a8d6SDavid Lechner } 7741e88a8d6SDavid Lechner 7751e88a8d6SDavid Lechner static struct platform_driver da8xx_cfgchip_driver = { 7761e88a8d6SDavid Lechner .probe = da8xx_cfgchip_probe, 7771e88a8d6SDavid Lechner .driver = { 7781e88a8d6SDavid Lechner .name = "da8xx-cfgchip-clk", 7791e88a8d6SDavid Lechner .of_match_table = da8xx_cfgchip_of_match, 7801e88a8d6SDavid Lechner }, 7811e88a8d6SDavid Lechner .id_table = da8xx_cfgchip_id_table, 7821e88a8d6SDavid Lechner }; 7831e88a8d6SDavid Lechner 7841e88a8d6SDavid Lechner static int __init da8xx_cfgchip_driver_init(void) 7851e88a8d6SDavid Lechner { 7861e88a8d6SDavid Lechner return platform_driver_register(&da8xx_cfgchip_driver); 7871e88a8d6SDavid Lechner } 7881e88a8d6SDavid Lechner 7891e88a8d6SDavid Lechner /* has to be postcore_initcall because PSC devices depend on the async3 clock */ 7901e88a8d6SDavid Lechner postcore_initcall(da8xx_cfgchip_driver_init); 791