1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * phy-da8xx-usb - TI DaVinci DA8xx USB PHY driver 4 * 5 * Copyright (C) 2016 David Lechner <david@lechnology.com> 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/io.h> 10 #include <linux/of.h> 11 #include <linux/mfd/da8xx-cfgchip.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/module.h> 14 #include <linux/phy/phy.h> 15 #include <linux/platform_data/phy-da8xx-usb.h> 16 #include <linux/platform_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/regmap.h> 19 20 #define PHY_INIT_BITS (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN) 21 22 struct da8xx_usb_phy { 23 struct device *dev; 24 struct phy_provider *phy_provider; 25 struct phy *usb11_phy; 26 struct phy *usb20_phy; 27 struct clk *usb11_clk; 28 struct clk *usb20_clk; 29 struct regmap *regmap; 30 }; 31 32 static int da8xx_usb11_phy_power_on(struct phy *phy) 33 { 34 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); 35 int ret; 36 37 ret = clk_prepare_enable(d_phy->usb11_clk); 38 if (ret) 39 return ret; 40 41 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 42 CFGCHIP2_USB1SUSPENDM); 43 44 /* 45 * USB1.1 can used USB2.0 output clock as reference clock so this is here to prevent USB2.0 46 * from shutting PHY's power when USB1.1 might use it 47 */ 48 pm_runtime_get_sync(d_phy->dev); 49 50 return 0; 51 } 52 53 static int da8xx_usb11_phy_power_off(struct phy *phy) 54 { 55 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); 56 57 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0); 58 59 clk_disable_unprepare(d_phy->usb11_clk); 60 pm_runtime_put_sync(d_phy->dev); 61 62 return 0; 63 } 64 65 static const struct phy_ops da8xx_usb11_phy_ops = { 66 .power_on = da8xx_usb11_phy_power_on, 67 .power_off = da8xx_usb11_phy_power_off, 68 .owner = THIS_MODULE, 69 }; 70 71 static int da8xx_usb20_phy_power_on(struct phy *phy) 72 { 73 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); 74 int ret; 75 76 ret = clk_prepare_enable(d_phy->usb20_clk); 77 if (ret) 78 return ret; 79 80 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, 0); 81 82 return 0; 83 } 84 85 static int da8xx_usb20_phy_power_off(struct phy *phy) 86 { 87 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); 88 89 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, 90 CFGCHIP2_OTGPWRDN); 91 92 clk_disable_unprepare(d_phy->usb20_clk); 93 94 return 0; 95 } 96 97 static int da8xx_usb20_phy_set_mode(struct phy *phy, 98 enum phy_mode mode, int submode) 99 { 100 struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); 101 u32 val; 102 103 switch (mode) { 104 case PHY_MODE_USB_HOST: /* Force VBUS valid, ID = 0 */ 105 val = CFGCHIP2_OTGMODE_FORCE_HOST; 106 break; 107 case PHY_MODE_USB_DEVICE: /* Force VBUS valid, ID = 1 */ 108 val = CFGCHIP2_OTGMODE_FORCE_DEVICE; 109 break; 110 case PHY_MODE_USB_OTG: /* Don't override the VBUS/ID comparators */ 111 val = CFGCHIP2_OTGMODE_NO_OVERRIDE; 112 break; 113 default: 114 return -EINVAL; 115 } 116 117 regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGMODE_MASK, 118 val); 119 120 return 0; 121 } 122 123 static const struct phy_ops da8xx_usb20_phy_ops = { 124 .power_on = da8xx_usb20_phy_power_on, 125 .power_off = da8xx_usb20_phy_power_off, 126 .set_mode = da8xx_usb20_phy_set_mode, 127 .owner = THIS_MODULE, 128 }; 129 130 static int __maybe_unused da8xx_runtime_suspend(struct device *dev) 131 { 132 struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); 133 134 dev_dbg(dev, "Suspending ...\n"); 135 136 regmap_set_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN); 137 138 return 0; 139 } 140 141 static int __maybe_unused da8xx_runtime_resume(struct device *dev) 142 { 143 u32 mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | CFGCHIP2_PHY_PLLON; 144 struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); 145 u32 pll_status; 146 147 regmap_update_bits(d_phy->regmap, CFGCHIP(2), mask, CFGCHIP2_PHY_PLLON); 148 149 dev_dbg(dev, "Resuming ...\n"); 150 151 return regmap_read_poll_timeout(d_phy->regmap, CFGCHIP(2), pll_status, 152 pll_status & CFGCHIP2_PHYCLKGD, 1000, 500000); 153 } 154 155 static const struct dev_pm_ops da8xx_usb_phy_pm_ops = { 156 SET_RUNTIME_PM_OPS(da8xx_runtime_suspend, da8xx_runtime_resume, NULL) 157 }; 158 159 static struct phy *da8xx_usb_phy_of_xlate(struct device *dev, 160 const struct of_phandle_args *args) 161 { 162 struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); 163 164 if (!d_phy) 165 return ERR_PTR(-ENODEV); 166 167 switch (args->args[0]) { 168 case 0: 169 return d_phy->usb20_phy; 170 case 1: 171 return d_phy->usb11_phy; 172 default: 173 return ERR_PTR(-EINVAL); 174 } 175 } 176 177 static int da8xx_usb_phy_probe(struct platform_device *pdev) 178 { 179 struct device *dev = &pdev->dev; 180 struct da8xx_usb_phy_platform_data *pdata = dev->platform_data; 181 struct device_node *node = dev->of_node; 182 struct da8xx_usb_phy *d_phy; 183 184 d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL); 185 if (!d_phy) 186 return -ENOMEM; 187 188 d_phy->dev = dev; 189 190 if (pdata) 191 d_phy->regmap = pdata->cfgchip; 192 else 193 d_phy->regmap = syscon_regmap_lookup_by_compatible( 194 "ti,da830-cfgchip"); 195 if (IS_ERR(d_phy->regmap)) { 196 dev_err(dev, "Failed to get syscon\n"); 197 return PTR_ERR(d_phy->regmap); 198 } 199 200 d_phy->usb11_clk = devm_clk_get(dev, "usb1_clk48"); 201 if (IS_ERR(d_phy->usb11_clk)) { 202 dev_err(dev, "Failed to get usb1_clk48\n"); 203 return PTR_ERR(d_phy->usb11_clk); 204 } 205 206 d_phy->usb20_clk = devm_clk_get(dev, "usb0_clk48"); 207 if (IS_ERR(d_phy->usb20_clk)) { 208 dev_err(dev, "Failed to get usb0_clk48\n"); 209 return PTR_ERR(d_phy->usb20_clk); 210 } 211 212 d_phy->usb11_phy = devm_phy_create(dev, node, &da8xx_usb11_phy_ops); 213 if (IS_ERR(d_phy->usb11_phy)) { 214 dev_err(dev, "Failed to create usb11 phy\n"); 215 return PTR_ERR(d_phy->usb11_phy); 216 } 217 218 d_phy->usb20_phy = devm_phy_create(dev, node, &da8xx_usb20_phy_ops); 219 if (IS_ERR(d_phy->usb20_phy)) { 220 dev_err(dev, "Failed to create usb20 phy\n"); 221 return PTR_ERR(d_phy->usb20_phy); 222 } 223 224 platform_set_drvdata(pdev, d_phy); 225 phy_set_drvdata(d_phy->usb11_phy, d_phy); 226 phy_set_drvdata(d_phy->usb20_phy, d_phy); 227 228 if (node) { 229 d_phy->phy_provider = devm_of_phy_provider_register(dev, 230 da8xx_usb_phy_of_xlate); 231 if (IS_ERR(d_phy->phy_provider)) { 232 dev_err(dev, "Failed to create phy provider\n"); 233 return PTR_ERR(d_phy->phy_provider); 234 } 235 } else { 236 int ret; 237 238 ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", 239 "ohci-da8xx"); 240 if (ret) 241 dev_warn(dev, "Failed to create usb11 phy lookup\n"); 242 ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy", 243 "musb-da8xx"); 244 if (ret) 245 dev_warn(dev, "Failed to create usb20 phy lookup\n"); 246 } 247 248 regmap_write_bits(d_phy->regmap, CFGCHIP(2), 249 PHY_INIT_BITS, PHY_INIT_BITS); 250 251 pm_runtime_set_active(dev); 252 devm_pm_runtime_enable(dev); 253 /* 254 * Prevent runtime pm from being ON by default. Users can enable 255 * it using power/control in sysfs. 256 */ 257 pm_runtime_forbid(dev); 258 259 return 0; 260 } 261 262 static void da8xx_usb_phy_remove(struct platform_device *pdev) 263 { 264 struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev); 265 266 if (!pdev->dev.of_node) { 267 phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx"); 268 phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx"); 269 } 270 } 271 272 static const struct of_device_id da8xx_usb_phy_ids[] = { 273 { .compatible = "ti,da830-usb-phy" }, 274 { } 275 }; 276 MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids); 277 278 static struct platform_driver da8xx_usb_phy_driver = { 279 .probe = da8xx_usb_phy_probe, 280 .remove_new = da8xx_usb_phy_remove, 281 .driver = { 282 .name = "da8xx-usb-phy", 283 .pm = &da8xx_usb_phy_pm_ops, 284 .of_match_table = da8xx_usb_phy_ids, 285 }, 286 }; 287 288 module_platform_driver(da8xx_usb_phy_driver); 289 290 MODULE_ALIAS("platform:da8xx-usb-phy"); 291 MODULE_AUTHOR("David Lechner <david@lechnology.com>"); 292 MODULE_DESCRIPTION("TI DA8xx USB PHY driver"); 293 MODULE_LICENSE("GPL v2"); 294