root/drivers/phy/broadcom/phy-brcm-usb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. brcm_usb_phy_init
  2. brcm_usb_phy_exit
  3. brcm_usb_phy_xlate
  4. name_to_value
  5. value_to_name
  6. dr_mode_show
  7. dual_select_store
  8. dual_select_show
  9. brcm_usb_phy_dvr_init
  10. brcm_usb_phy_probe
  11. brcm_usb_phy_remove
  12. brcm_usb_phy_suspend
  13. brcm_usb_phy_resume

   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");

/* [<][>][^][v][top][bottom][index][help] */