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 int ret; 184 185 d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL); 186 if (!d_phy) 187 return -ENOMEM; 188 189 d_phy->dev = dev; 190 191 if (pdata) 192 d_phy->regmap = pdata->cfgchip; 193 else 194 d_phy->regmap = syscon_regmap_lookup_by_compatible( 195 "ti,da830-cfgchip"); 196 if (IS_ERR(d_phy->regmap)) { 197 dev_err(dev, "Failed to get syscon\n"); 198 return PTR_ERR(d_phy->regmap); 199 } 200 201 d_phy->usb11_clk = devm_clk_get(dev, "usb1_clk48"); 202 if (IS_ERR(d_phy->usb11_clk)) { 203 dev_err(dev, "Failed to get usb1_clk48\n"); 204 return PTR_ERR(d_phy->usb11_clk); 205 } 206 207 d_phy->usb20_clk = devm_clk_get(dev, "usb0_clk48"); 208 if (IS_ERR(d_phy->usb20_clk)) { 209 dev_err(dev, "Failed to get usb0_clk48\n"); 210 return PTR_ERR(d_phy->usb20_clk); 211 } 212 213 d_phy->usb11_phy = devm_phy_create(dev, node, &da8xx_usb11_phy_ops); 214 if (IS_ERR(d_phy->usb11_phy)) { 215 dev_err(dev, "Failed to create usb11 phy\n"); 216 return PTR_ERR(d_phy->usb11_phy); 217 } 218 219 d_phy->usb20_phy = devm_phy_create(dev, node, &da8xx_usb20_phy_ops); 220 if (IS_ERR(d_phy->usb20_phy)) { 221 dev_err(dev, "Failed to create usb20 phy\n"); 222 return PTR_ERR(d_phy->usb20_phy); 223 } 224 225 platform_set_drvdata(pdev, d_phy); 226 phy_set_drvdata(d_phy->usb11_phy, d_phy); 227 phy_set_drvdata(d_phy->usb20_phy, d_phy); 228 229 if (node) { 230 d_phy->phy_provider = devm_of_phy_provider_register(dev, 231 da8xx_usb_phy_of_xlate); 232 if (IS_ERR(d_phy->phy_provider)) { 233 dev_err(dev, "Failed to create phy provider\n"); 234 return PTR_ERR(d_phy->phy_provider); 235 } 236 } else { 237 ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", 238 "ohci-da8xx"); 239 if (ret) 240 dev_warn(dev, "Failed to create usb11 phy lookup\n"); 241 ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy", 242 "musb-da8xx"); 243 if (ret) 244 dev_warn(dev, "Failed to create usb20 phy lookup\n"); 245 } 246 247 regmap_write_bits(d_phy->regmap, CFGCHIP(2), 248 PHY_INIT_BITS, PHY_INIT_BITS); 249 250 pm_runtime_set_active(dev); 251 ret = devm_pm_runtime_enable(dev); 252 if (ret) 253 return ret; 254 /* 255 * Prevent runtime pm from being ON by default. Users can enable 256 * it using power/control in sysfs. 257 */ 258 pm_runtime_forbid(dev); 259 260 return 0; 261 } 262 263 static void da8xx_usb_phy_remove(struct platform_device *pdev) 264 { 265 struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev); 266 267 if (!pdev->dev.of_node) { 268 phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx"); 269 phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx"); 270 } 271 } 272 273 static const struct of_device_id da8xx_usb_phy_ids[] = { 274 { .compatible = "ti,da830-usb-phy" }, 275 { } 276 }; 277 MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids); 278 279 static struct platform_driver da8xx_usb_phy_driver = { 280 .probe = da8xx_usb_phy_probe, 281 .remove = da8xx_usb_phy_remove, 282 .driver = { 283 .name = "da8xx-usb-phy", 284 .pm = &da8xx_usb_phy_pm_ops, 285 .of_match_table = da8xx_usb_phy_ids, 286 }, 287 }; 288 289 module_platform_driver(da8xx_usb_phy_driver); 290 291 MODULE_ALIAS("platform:da8xx-usb-phy"); 292 MODULE_AUTHOR("David Lechner <david@lechnology.com>"); 293 MODULE_DESCRIPTION("TI DA8xx USB PHY driver"); 294 MODULE_LICENSE("GPL v2"); 295