1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * phy-brcm-usb.c - Broadcom USB Phy Driver 4 * 5 * Copyright (C) 2015-2017 Broadcom 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/delay.h> 10 #include <linux/err.h> 11 #include <linux/io.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/phy/phy.h> 15 #include <linux/platform_device.h> 16 #include <linux/interrupt.h> 17 #include <linux/soc/brcmstb/brcmstb.h> 18 #include <dt-bindings/phy/phy.h> 19 20 #include "phy-brcm-usb-init.h" 21 22 static DEFINE_MUTEX(sysfs_lock); 23 24 enum brcm_usb_phy_id { 25 BRCM_USB_PHY_2_0 = 0, 26 BRCM_USB_PHY_3_0, 27 BRCM_USB_PHY_ID_MAX 28 }; 29 30 struct value_to_name_map { 31 int value; 32 const char *name; 33 }; 34 35 static struct value_to_name_map brcm_dr_mode_to_name[] = { 36 { USB_CTLR_MODE_HOST, "host" }, 37 { USB_CTLR_MODE_DEVICE, "peripheral" }, 38 { USB_CTLR_MODE_DRD, "drd" }, 39 { USB_CTLR_MODE_TYPEC_PD, "typec-pd" } 40 }; 41 42 static struct value_to_name_map brcm_dual_mode_to_name[] = { 43 { 0, "host" }, 44 { 1, "device" }, 45 { 2, "auto" }, 46 }; 47 48 struct brcm_usb_phy { 49 struct phy *phy; 50 unsigned int id; 51 bool inited; 52 }; 53 54 struct brcm_usb_phy_data { 55 struct brcm_usb_init_params ini; 56 bool has_eohci; 57 bool has_xhci; 58 struct clk *usb_20_clk; 59 struct clk *usb_30_clk; 60 struct mutex mutex; /* serialize phy init */ 61 int init_count; 62 struct brcm_usb_phy phys[BRCM_USB_PHY_ID_MAX]; 63 }; 64 65 static int brcm_usb_phy_init(struct phy *gphy) 66 { 67 struct brcm_usb_phy *phy = phy_get_drvdata(gphy); 68 struct brcm_usb_phy_data *priv = 69 container_of(phy, struct brcm_usb_phy_data, phys[phy->id]); 70 71 /* 72 * Use a lock to make sure a second caller waits until 73 * the base phy is inited before using it. 74 */ 75 mutex_lock(&priv->mutex); 76 if (priv->init_count++ == 0) { 77 clk_enable(priv->usb_20_clk); 78 clk_enable(priv->usb_30_clk); 79 brcm_usb_init_common(&priv->ini); 80 } 81 mutex_unlock(&priv->mutex); 82 if (phy->id == BRCM_USB_PHY_2_0) 83 brcm_usb_init_eohci(&priv->ini); 84 else if (phy->id == BRCM_USB_PHY_3_0) 85 brcm_usb_init_xhci(&priv->ini); 86 phy->inited = true; 87 dev_dbg(&gphy->dev, "INIT, id: %d, total: %d\n", phy->id, 88 priv->init_count); 89 90 return 0; 91 } 92 93 static int brcm_usb_phy_exit(struct phy *gphy) 94 { 95 struct brcm_usb_phy *phy = phy_get_drvdata(gphy); 96 struct brcm_usb_phy_data *priv = 97 container_of(phy, struct brcm_usb_phy_data, phys[phy->id]); 98 99 dev_dbg(&gphy->dev, "EXIT\n"); 100 if (phy->id == BRCM_USB_PHY_2_0) 101 brcm_usb_uninit_eohci(&priv->ini); 102 if (phy->id == BRCM_USB_PHY_3_0) 103 brcm_usb_uninit_xhci(&priv->ini); 104 105 /* If both xhci and eohci are gone, reset everything else */ 106 mutex_lock(&priv->mutex); 107 if (--priv->init_count == 0) { 108 brcm_usb_uninit_common(&priv->ini); 109 clk_disable(priv->usb_20_clk); 110 clk_disable(priv->usb_30_clk); 111 } 112 mutex_unlock(&priv->mutex); 113 phy->inited = false; 114 return 0; 115 } 116 117 static struct phy_ops brcm_usb_phy_ops = { 118 .init = brcm_usb_phy_init, 119 .exit = brcm_usb_phy_exit, 120 .owner = THIS_MODULE, 121 }; 122 123 static struct phy *brcm_usb_phy_xlate(struct device *dev, 124 struct of_phandle_args *args) 125 { 126 struct brcm_usb_phy_data *data = dev_get_drvdata(dev); 127 128 /* 129 * values 0 and 1 are for backward compatibility with 130 * device tree nodes from older bootloaders. 131 */ 132 switch (args->args[0]) { 133 case 0: 134 case PHY_TYPE_USB2: 135 if (data->phys[BRCM_USB_PHY_2_0].phy) 136 return data->phys[BRCM_USB_PHY_2_0].phy; 137 dev_warn(dev, "Error, 2.0 Phy not found\n"); 138 break; 139 case 1: 140 case PHY_TYPE_USB3: 141 if (data->phys[BRCM_USB_PHY_3_0].phy) 142 return data->phys[BRCM_USB_PHY_3_0].phy; 143 dev_warn(dev, "Error, 3.0 Phy not found\n"); 144 break; 145 } 146 return ERR_PTR(-ENODEV); 147 } 148 149 static int name_to_value(struct value_to_name_map *table, int count, 150 const char *name, int *value) 151 { 152 int x; 153 154 *value = 0; 155 for (x = 0; x < count; x++) { 156 if (sysfs_streq(name, table[x].name)) { 157 *value = x; 158 return 0; 159 } 160 } 161 return -EINVAL; 162 } 163 164 static const char *value_to_name(struct value_to_name_map *table, int count, 165 int value) 166 { 167 if (value >= count) 168 return "unknown"; 169 return table[value].name; 170 } 171 172 static ssize_t dr_mode_show(struct device *dev, 173 struct device_attribute *attr, 174 char *buf) 175 { 176 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); 177 178 return sprintf(buf, "%s\n", 179 value_to_name(&brcm_dr_mode_to_name[0], 180 ARRAY_SIZE(brcm_dr_mode_to_name), 181 priv->ini.mode)); 182 } 183 static DEVICE_ATTR_RO(dr_mode); 184 185 static ssize_t dual_select_store(struct device *dev, 186 struct device_attribute *attr, 187 const char *buf, size_t len) 188 { 189 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); 190 int value; 191 int res; 192 193 mutex_lock(&sysfs_lock); 194 res = name_to_value(&brcm_dual_mode_to_name[0], 195 ARRAY_SIZE(brcm_dual_mode_to_name), buf, &value); 196 if (!res) { 197 brcm_usb_init_set_dual_select(&priv->ini, value); 198 res = len; 199 } 200 mutex_unlock(&sysfs_lock); 201 return res; 202 } 203 204 static ssize_t dual_select_show(struct device *dev, 205 struct device_attribute *attr, 206 char *buf) 207 { 208 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); 209 int value; 210 211 mutex_lock(&sysfs_lock); 212 value = brcm_usb_init_get_dual_select(&priv->ini); 213 mutex_unlock(&sysfs_lock); 214 return sprintf(buf, "%s\n", 215 value_to_name(&brcm_dual_mode_to_name[0], 216 ARRAY_SIZE(brcm_dual_mode_to_name), 217 value)); 218 } 219 static DEVICE_ATTR_RW(dual_select); 220 221 static struct attribute *brcm_usb_phy_attrs[] = { 222 &dev_attr_dr_mode.attr, 223 &dev_attr_dual_select.attr, 224 NULL 225 }; 226 227 static const struct attribute_group brcm_usb_phy_group = { 228 .attrs = brcm_usb_phy_attrs, 229 }; 230 231 static int brcm_usb_phy_dvr_init(struct device *dev, 232 struct brcm_usb_phy_data *priv, 233 struct device_node *dn) 234 { 235 struct phy *gphy; 236 int err; 237 238 priv->usb_20_clk = of_clk_get_by_name(dn, "sw_usb"); 239 if (IS_ERR(priv->usb_20_clk)) { 240 dev_info(dev, "Clock not found in Device Tree\n"); 241 priv->usb_20_clk = NULL; 242 } 243 err = clk_prepare_enable(priv->usb_20_clk); 244 if (err) 245 return err; 246 247 if (priv->has_eohci) { 248 gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops); 249 if (IS_ERR(gphy)) { 250 dev_err(dev, "failed to create EHCI/OHCI PHY\n"); 251 return PTR_ERR(gphy); 252 } 253 priv->phys[BRCM_USB_PHY_2_0].phy = gphy; 254 priv->phys[BRCM_USB_PHY_2_0].id = BRCM_USB_PHY_2_0; 255 phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_2_0]); 256 } 257 258 if (priv->has_xhci) { 259 gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops); 260 if (IS_ERR(gphy)) { 261 dev_err(dev, "failed to create XHCI PHY\n"); 262 return PTR_ERR(gphy); 263 } 264 priv->phys[BRCM_USB_PHY_3_0].phy = gphy; 265 priv->phys[BRCM_USB_PHY_3_0].id = BRCM_USB_PHY_3_0; 266 phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_3_0]); 267 268 priv->usb_30_clk = of_clk_get_by_name(dn, "sw_usb3"); 269 if (IS_ERR(priv->usb_30_clk)) { 270 dev_info(dev, 271 "USB3.0 clock not found in Device Tree\n"); 272 priv->usb_30_clk = NULL; 273 } 274 err = clk_prepare_enable(priv->usb_30_clk); 275 if (err) 276 return err; 277 } 278 return 0; 279 } 280 281 static int brcm_usb_phy_probe(struct platform_device *pdev) 282 { 283 struct resource *res; 284 struct device *dev = &pdev->dev; 285 struct brcm_usb_phy_data *priv; 286 struct phy_provider *phy_provider; 287 struct device_node *dn = pdev->dev.of_node; 288 int err; 289 const char *mode; 290 291 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 292 if (!priv) 293 return -ENOMEM; 294 platform_set_drvdata(pdev, priv); 295 296 priv->ini.family_id = brcmstb_get_family_id(); 297 priv->ini.product_id = brcmstb_get_product_id(); 298 brcm_usb_set_family_map(&priv->ini); 299 dev_dbg(dev, "Best mapping table is for %s\n", 300 priv->ini.family_name); 301 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 302 if (!res) { 303 dev_err(dev, "can't get USB_CTRL base address\n"); 304 return -EINVAL; 305 } 306 priv->ini.ctrl_regs = devm_ioremap_resource(dev, res); 307 if (IS_ERR(priv->ini.ctrl_regs)) { 308 dev_err(dev, "can't map CTRL register space\n"); 309 return -EINVAL; 310 } 311 312 /* The XHCI EC registers are optional */ 313 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 314 if (res) { 315 priv->ini.xhci_ec_regs = 316 devm_ioremap_resource(dev, res); 317 if (IS_ERR(priv->ini.xhci_ec_regs)) { 318 dev_err(dev, "can't map XHCI EC register space\n"); 319 return -EINVAL; 320 } 321 } 322 323 of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp); 324 of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc); 325 326 priv->ini.mode = USB_CTLR_MODE_HOST; 327 err = of_property_read_string(dn, "dr_mode", &mode); 328 if (err == 0) { 329 name_to_value(&brcm_dr_mode_to_name[0], 330 ARRAY_SIZE(brcm_dr_mode_to_name), 331 mode, &priv->ini.mode); 332 } 333 if (of_property_read_bool(dn, "brcm,has-xhci")) 334 priv->has_xhci = true; 335 if (of_property_read_bool(dn, "brcm,has-eohci")) 336 priv->has_eohci = true; 337 338 err = brcm_usb_phy_dvr_init(dev, priv, dn); 339 if (err) 340 return err; 341 342 mutex_init(&priv->mutex); 343 344 /* make sure invert settings are correct */ 345 brcm_usb_init_ipp(&priv->ini); 346 347 /* 348 * Create sysfs entries for mode. 349 * Remove "dual_select" attribute if not in dual mode 350 */ 351 if (priv->ini.mode != USB_CTLR_MODE_DRD) 352 brcm_usb_phy_attrs[1] = NULL; 353 err = sysfs_create_group(&dev->kobj, &brcm_usb_phy_group); 354 if (err) 355 dev_warn(dev, "Error creating sysfs attributes\n"); 356 357 /* start with everything off */ 358 if (priv->has_xhci) 359 brcm_usb_uninit_xhci(&priv->ini); 360 if (priv->has_eohci) 361 brcm_usb_uninit_eohci(&priv->ini); 362 brcm_usb_uninit_common(&priv->ini); 363 clk_disable(priv->usb_20_clk); 364 clk_disable(priv->usb_30_clk); 365 366 phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate); 367 368 return PTR_ERR_OR_ZERO(phy_provider); 369 } 370 371 static int brcm_usb_phy_remove(struct platform_device *pdev) 372 { 373 sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group); 374 375 return 0; 376 } 377 378 #ifdef CONFIG_PM_SLEEP 379 static int brcm_usb_phy_suspend(struct device *dev) 380 { 381 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); 382 383 if (priv->init_count) { 384 clk_disable(priv->usb_20_clk); 385 clk_disable(priv->usb_30_clk); 386 } 387 return 0; 388 } 389 390 static int brcm_usb_phy_resume(struct device *dev) 391 { 392 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev); 393 394 clk_enable(priv->usb_20_clk); 395 clk_enable(priv->usb_30_clk); 396 brcm_usb_init_ipp(&priv->ini); 397 398 /* 399 * Initialize anything that was previously initialized. 400 * Uninitialize anything that wasn't previously initialized. 401 */ 402 if (priv->init_count) { 403 brcm_usb_init_common(&priv->ini); 404 if (priv->phys[BRCM_USB_PHY_2_0].inited) { 405 brcm_usb_init_eohci(&priv->ini); 406 } else if (priv->has_eohci) { 407 brcm_usb_uninit_eohci(&priv->ini); 408 clk_disable(priv->usb_20_clk); 409 } 410 if (priv->phys[BRCM_USB_PHY_3_0].inited) { 411 brcm_usb_init_xhci(&priv->ini); 412 } else if (priv->has_xhci) { 413 brcm_usb_uninit_xhci(&priv->ini); 414 clk_disable(priv->usb_30_clk); 415 } 416 } else { 417 if (priv->has_xhci) 418 brcm_usb_uninit_xhci(&priv->ini); 419 if (priv->has_eohci) 420 brcm_usb_uninit_eohci(&priv->ini); 421 brcm_usb_uninit_common(&priv->ini); 422 clk_disable(priv->usb_20_clk); 423 clk_disable(priv->usb_30_clk); 424 } 425 426 return 0; 427 } 428 #endif /* CONFIG_PM_SLEEP */ 429 430 static const struct dev_pm_ops brcm_usb_phy_pm_ops = { 431 SET_LATE_SYSTEM_SLEEP_PM_OPS(brcm_usb_phy_suspend, brcm_usb_phy_resume) 432 }; 433 434 static const struct of_device_id brcm_usb_dt_ids[] = { 435 { .compatible = "brcm,brcmstb-usb-phy" }, 436 { /* sentinel */ } 437 }; 438 439 MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids); 440 441 static struct platform_driver brcm_usb_driver = { 442 .probe = brcm_usb_phy_probe, 443 .remove = brcm_usb_phy_remove, 444 .driver = { 445 .name = "brcmstb-usb-phy", 446 .pm = &brcm_usb_phy_pm_ops, 447 .of_match_table = brcm_usb_dt_ids, 448 }, 449 }; 450 451 module_platform_driver(brcm_usb_driver); 452 453 MODULE_ALIAS("platform:brcmstb-usb-phy"); 454 MODULE_AUTHOR("Al Cooper <acooper@broadcom.com>"); 455 MODULE_DESCRIPTION("BRCM USB PHY driver"); 456 MODULE_LICENSE("GPL v2"); 457