linux/drivers/phy/broadcom/phy-brcm-usb.c
<<
>>
Prefs
   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/of_device.h>
  15#include <linux/phy/phy.h>
  16#include <linux/platform_device.h>
  17#include <linux/interrupt.h>
  18#include <linux/soc/brcmstb/brcmstb.h>
  19#include <dt-bindings/phy/phy.h>
  20#include <linux/mfd/syscon.h>
  21
  22#include "phy-brcm-usb-init.h"
  23
  24static DEFINE_MUTEX(sysfs_lock);
  25
  26enum brcm_usb_phy_id {
  27        BRCM_USB_PHY_2_0 = 0,
  28        BRCM_USB_PHY_3_0,
  29        BRCM_USB_PHY_ID_MAX
  30};
  31
  32struct value_to_name_map {
  33        int value;
  34        const char *name;
  35};
  36
  37struct match_chip_info {
  38        void (*init_func)(struct brcm_usb_init_params *params);
  39        u8 required_regs[BRCM_REGS_MAX + 1];
  40        u8 optional_reg;
  41};
  42
  43static const struct value_to_name_map brcm_dr_mode_to_name[] = {
  44        { USB_CTLR_MODE_HOST, "host" },
  45        { USB_CTLR_MODE_DEVICE, "peripheral" },
  46        { USB_CTLR_MODE_DRD, "drd" },
  47        { USB_CTLR_MODE_TYPEC_PD, "typec-pd" }
  48};
  49
  50static const struct value_to_name_map brcm_dual_mode_to_name[] = {
  51        { 0, "host" },
  52        { 1, "device" },
  53        { 2, "auto" },
  54};
  55
  56struct brcm_usb_phy {
  57        struct phy *phy;
  58        unsigned int id;
  59        bool inited;
  60};
  61
  62struct brcm_usb_phy_data {
  63        struct  brcm_usb_init_params ini;
  64        bool                    has_eohci;
  65        bool                    has_xhci;
  66        struct clk              *usb_20_clk;
  67        struct clk              *usb_30_clk;
  68        struct clk              *suspend_clk;
  69        struct mutex            mutex;  /* serialize phy init */
  70        int                     init_count;
  71        int                     wake_irq;
  72        struct brcm_usb_phy     phys[BRCM_USB_PHY_ID_MAX];
  73};
  74
  75static s8 *node_reg_names[BRCM_REGS_MAX] = {
  76        "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
  77};
  78
  79static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id)
  80{
  81        struct phy *gphy = dev_id;
  82
  83        pm_wakeup_event(&gphy->dev, 0);
  84
  85        return IRQ_HANDLED;
  86}
  87
  88static int brcm_usb_phy_init(struct phy *gphy)
  89{
  90        struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
  91        struct brcm_usb_phy_data *priv =
  92                container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
  93
  94        /*
  95         * Use a lock to make sure a second caller waits until
  96         * the base phy is inited before using it.
  97         */
  98        mutex_lock(&priv->mutex);
  99        if (priv->init_count++ == 0) {
 100                clk_prepare_enable(priv->usb_20_clk);
 101                clk_prepare_enable(priv->usb_30_clk);
 102                clk_prepare_enable(priv->suspend_clk);
 103                brcm_usb_init_common(&priv->ini);
 104        }
 105        mutex_unlock(&priv->mutex);
 106        if (phy->id == BRCM_USB_PHY_2_0)
 107                brcm_usb_init_eohci(&priv->ini);
 108        else if (phy->id == BRCM_USB_PHY_3_0)
 109                brcm_usb_init_xhci(&priv->ini);
 110        phy->inited = true;
 111        dev_dbg(&gphy->dev, "INIT, id: %d, total: %d\n", phy->id,
 112                priv->init_count);
 113
 114        return 0;
 115}
 116
 117static int brcm_usb_phy_exit(struct phy *gphy)
 118{
 119        struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
 120        struct brcm_usb_phy_data *priv =
 121                container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
 122
 123        dev_dbg(&gphy->dev, "EXIT\n");
 124        if (phy->id == BRCM_USB_PHY_2_0)
 125                brcm_usb_uninit_eohci(&priv->ini);
 126        if (phy->id == BRCM_USB_PHY_3_0)
 127                brcm_usb_uninit_xhci(&priv->ini);
 128
 129        /* If both xhci and eohci are gone, reset everything else */
 130        mutex_lock(&priv->mutex);
 131        if (--priv->init_count == 0) {
 132                brcm_usb_uninit_common(&priv->ini);
 133                clk_disable_unprepare(priv->usb_20_clk);
 134                clk_disable_unprepare(priv->usb_30_clk);
 135                clk_disable_unprepare(priv->suspend_clk);
 136        }
 137        mutex_unlock(&priv->mutex);
 138        phy->inited = false;
 139        return 0;
 140}
 141
 142static const struct phy_ops brcm_usb_phy_ops = {
 143        .init           = brcm_usb_phy_init,
 144        .exit           = brcm_usb_phy_exit,
 145        .owner          = THIS_MODULE,
 146};
 147
 148static struct phy *brcm_usb_phy_xlate(struct device *dev,
 149                                      struct of_phandle_args *args)
 150{
 151        struct brcm_usb_phy_data *data = dev_get_drvdata(dev);
 152
 153        /*
 154         * values 0 and 1 are for backward compatibility with
 155         * device tree nodes from older bootloaders.
 156         */
 157        switch (args->args[0]) {
 158        case 0:
 159        case PHY_TYPE_USB2:
 160                if (data->phys[BRCM_USB_PHY_2_0].phy)
 161                        return data->phys[BRCM_USB_PHY_2_0].phy;
 162                dev_warn(dev, "Error, 2.0 Phy not found\n");
 163                break;
 164        case 1:
 165        case PHY_TYPE_USB3:
 166                if (data->phys[BRCM_USB_PHY_3_0].phy)
 167                        return data->phys[BRCM_USB_PHY_3_0].phy;
 168                dev_warn(dev, "Error, 3.0 Phy not found\n");
 169                break;
 170        }
 171        return ERR_PTR(-ENODEV);
 172}
 173
 174static int name_to_value(const struct value_to_name_map *table, int count,
 175                         const char *name, int *value)
 176{
 177        int x;
 178
 179        *value = 0;
 180        for (x = 0; x < count; x++) {
 181                if (sysfs_streq(name, table[x].name)) {
 182                        *value = x;
 183                        return 0;
 184                }
 185        }
 186        return -EINVAL;
 187}
 188
 189static const char *value_to_name(const struct value_to_name_map *table, int count,
 190                                 int value)
 191{
 192        if (value >= count)
 193                return "unknown";
 194        return table[value].name;
 195}
 196
 197static ssize_t dr_mode_show(struct device *dev,
 198                            struct device_attribute *attr,
 199                            char *buf)
 200{
 201        struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
 202
 203        return sprintf(buf, "%s\n",
 204                value_to_name(&brcm_dr_mode_to_name[0],
 205                              ARRAY_SIZE(brcm_dr_mode_to_name),
 206                              priv->ini.mode));
 207}
 208static DEVICE_ATTR_RO(dr_mode);
 209
 210static ssize_t dual_select_store(struct device *dev,
 211                                 struct device_attribute *attr,
 212                                 const char *buf, size_t len)
 213{
 214        struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
 215        int value;
 216        int res;
 217
 218        mutex_lock(&sysfs_lock);
 219        res = name_to_value(&brcm_dual_mode_to_name[0],
 220                            ARRAY_SIZE(brcm_dual_mode_to_name), buf, &value);
 221        if (!res) {
 222                brcm_usb_set_dual_select(&priv->ini, value);
 223                res = len;
 224        }
 225        mutex_unlock(&sysfs_lock);
 226        return res;
 227}
 228
 229static ssize_t dual_select_show(struct device *dev,
 230                                struct device_attribute *attr,
 231                                char *buf)
 232{
 233        struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
 234        int value;
 235
 236        mutex_lock(&sysfs_lock);
 237        value = brcm_usb_get_dual_select(&priv->ini);
 238        mutex_unlock(&sysfs_lock);
 239        return sprintf(buf, "%s\n",
 240                value_to_name(&brcm_dual_mode_to_name[0],
 241                              ARRAY_SIZE(brcm_dual_mode_to_name),
 242                              value));
 243}
 244static DEVICE_ATTR_RW(dual_select);
 245
 246static struct attribute *brcm_usb_phy_attrs[] = {
 247        &dev_attr_dr_mode.attr,
 248        &dev_attr_dual_select.attr,
 249        NULL
 250};
 251
 252static const struct attribute_group brcm_usb_phy_group = {
 253        .attrs = brcm_usb_phy_attrs,
 254};
 255
 256static const struct match_chip_info chip_info_7216 = {
 257        .init_func = &brcm_usb_dvr_init_7216,
 258        .required_regs = {
 259                BRCM_REGS_CTRL,
 260                BRCM_REGS_XHCI_EC,
 261                BRCM_REGS_XHCI_GBL,
 262                -1,
 263        },
 264};
 265
 266static const struct match_chip_info chip_info_7211b0 = {
 267        .init_func = &brcm_usb_dvr_init_7211b0,
 268        .required_regs = {
 269                BRCM_REGS_CTRL,
 270                BRCM_REGS_XHCI_EC,
 271                BRCM_REGS_XHCI_GBL,
 272                BRCM_REGS_USB_PHY,
 273                BRCM_REGS_USB_MDIO,
 274                -1,
 275        },
 276        .optional_reg = BRCM_REGS_BDC_EC,
 277};
 278
 279static const struct match_chip_info chip_info_7445 = {
 280        .init_func = &brcm_usb_dvr_init_7445,
 281        .required_regs = {
 282                BRCM_REGS_CTRL,
 283                BRCM_REGS_XHCI_EC,
 284                -1,
 285        },
 286};
 287
 288static const struct of_device_id brcm_usb_dt_ids[] = {
 289        {
 290                .compatible = "brcm,bcm4908-usb-phy",
 291                .data = &chip_info_7445,
 292        },
 293        {
 294                .compatible = "brcm,bcm7216-usb-phy",
 295                .data = &chip_info_7216,
 296        },
 297        {
 298                .compatible = "brcm,bcm7211-usb-phy",
 299                .data = &chip_info_7211b0,
 300        },
 301        {
 302                .compatible = "brcm,brcmstb-usb-phy",
 303                .data = &chip_info_7445,
 304        },
 305        { /* sentinel */ }
 306};
 307
 308static int brcm_usb_get_regs(struct platform_device *pdev,
 309                             enum brcmusb_reg_sel regs,
 310                             struct  brcm_usb_init_params *ini,
 311                             bool optional)
 312{
 313        struct resource *res;
 314
 315        /* Older DT nodes have ctrl and optional xhci_ec by index only */
 316        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 317                                                node_reg_names[regs]);
 318        if (res == NULL) {
 319                if (regs == BRCM_REGS_CTRL) {
 320                        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 321                } else if (regs == BRCM_REGS_XHCI_EC) {
 322                        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 323                        /* XHCI_EC registers are optional */
 324                        if (res == NULL)
 325                                return 0;
 326                }
 327                if (res == NULL) {
 328                        if (optional) {
 329                                dev_dbg(&pdev->dev,
 330                                        "Optional reg %s not found\n",
 331                                        node_reg_names[regs]);
 332                                return 0;
 333                        }
 334                        dev_err(&pdev->dev, "can't get %s base addr\n",
 335                                node_reg_names[regs]);
 336                        return 1;
 337                }
 338        }
 339        ini->regs[regs] = devm_ioremap_resource(&pdev->dev, res);
 340        if (IS_ERR(ini->regs[regs])) {
 341                dev_err(&pdev->dev, "can't map %s register space\n",
 342                        node_reg_names[regs]);
 343                return 1;
 344        }
 345        return 0;
 346}
 347
 348static int brcm_usb_phy_dvr_init(struct platform_device *pdev,
 349                                 struct brcm_usb_phy_data *priv,
 350                                 struct device_node *dn)
 351{
 352        struct device *dev = &pdev->dev;
 353        struct phy *gphy = NULL;
 354        int err;
 355
 356        priv->usb_20_clk = of_clk_get_by_name(dn, "sw_usb");
 357        if (IS_ERR(priv->usb_20_clk)) {
 358                if (PTR_ERR(priv->usb_20_clk) == -EPROBE_DEFER)
 359                        return -EPROBE_DEFER;
 360                dev_info(dev, "Clock not found in Device Tree\n");
 361                priv->usb_20_clk = NULL;
 362        }
 363        err = clk_prepare_enable(priv->usb_20_clk);
 364        if (err)
 365                return err;
 366
 367        if (priv->has_eohci) {
 368                gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
 369                if (IS_ERR(gphy)) {
 370                        dev_err(dev, "failed to create EHCI/OHCI PHY\n");
 371                        return PTR_ERR(gphy);
 372                }
 373                priv->phys[BRCM_USB_PHY_2_0].phy = gphy;
 374                priv->phys[BRCM_USB_PHY_2_0].id = BRCM_USB_PHY_2_0;
 375                phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_2_0]);
 376        }
 377
 378        if (priv->has_xhci) {
 379                gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
 380                if (IS_ERR(gphy)) {
 381                        dev_err(dev, "failed to create XHCI PHY\n");
 382                        return PTR_ERR(gphy);
 383                }
 384                priv->phys[BRCM_USB_PHY_3_0].phy = gphy;
 385                priv->phys[BRCM_USB_PHY_3_0].id = BRCM_USB_PHY_3_0;
 386                phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_3_0]);
 387
 388                priv->usb_30_clk = of_clk_get_by_name(dn, "sw_usb3");
 389                if (IS_ERR(priv->usb_30_clk)) {
 390                        if (PTR_ERR(priv->usb_30_clk) == -EPROBE_DEFER)
 391                                return -EPROBE_DEFER;
 392                        dev_info(dev,
 393                                 "USB3.0 clock not found in Device Tree\n");
 394                        priv->usb_30_clk = NULL;
 395                }
 396                err = clk_prepare_enable(priv->usb_30_clk);
 397                if (err)
 398                        return err;
 399        }
 400
 401        priv->suspend_clk = clk_get(dev, "usb0_freerun");
 402        if (IS_ERR(priv->suspend_clk)) {
 403                if (PTR_ERR(priv->suspend_clk) == -EPROBE_DEFER)
 404                        return -EPROBE_DEFER;
 405                dev_err(dev, "Suspend Clock not found in Device Tree\n");
 406                priv->suspend_clk = NULL;
 407        }
 408
 409        priv->wake_irq = platform_get_irq_byname(pdev, "wake");
 410        if (priv->wake_irq < 0)
 411                priv->wake_irq = platform_get_irq_byname(pdev, "wakeup");
 412        if (priv->wake_irq >= 0) {
 413                err = devm_request_irq(dev, priv->wake_irq,
 414                                       brcm_usb_phy_wake_isr, 0,
 415                                       dev_name(dev), gphy);
 416                if (err < 0)
 417                        return err;
 418                device_set_wakeup_capable(dev, 1);
 419        } else {
 420                dev_info(dev,
 421                         "Wake interrupt missing, system wake not supported\n");
 422        }
 423
 424        return 0;
 425}
 426
 427static int brcm_usb_phy_probe(struct platform_device *pdev)
 428{
 429        struct device *dev = &pdev->dev;
 430        struct brcm_usb_phy_data *priv;
 431        struct phy_provider *phy_provider;
 432        struct device_node *dn = pdev->dev.of_node;
 433        int err;
 434        const char *mode;
 435        const struct match_chip_info *info;
 436        struct regmap *rmap;
 437        int x;
 438
 439        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 440        if (!priv)
 441                return -ENOMEM;
 442        platform_set_drvdata(pdev, priv);
 443
 444        priv->ini.family_id = brcmstb_get_family_id();
 445        priv->ini.product_id = brcmstb_get_product_id();
 446
 447        info = of_device_get_match_data(&pdev->dev);
 448        if (!info)
 449                return -ENOENT;
 450
 451        info->init_func(&priv->ini);
 452
 453        dev_dbg(dev, "Best mapping table is for %s\n",
 454                priv->ini.family_name);
 455
 456        of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp);
 457        of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc);
 458
 459        priv->ini.mode = USB_CTLR_MODE_HOST;
 460        err = of_property_read_string(dn, "dr_mode", &mode);
 461        if (err == 0) {
 462                name_to_value(&brcm_dr_mode_to_name[0],
 463                              ARRAY_SIZE(brcm_dr_mode_to_name),
 464                        mode, &priv->ini.mode);
 465        }
 466        if (of_property_read_bool(dn, "brcm,has-xhci"))
 467                priv->has_xhci = true;
 468        if (of_property_read_bool(dn, "brcm,has-eohci"))
 469                priv->has_eohci = true;
 470
 471        for (x = 0; x < BRCM_REGS_MAX; x++) {
 472                if (info->required_regs[x] >= BRCM_REGS_MAX)
 473                        break;
 474
 475                err = brcm_usb_get_regs(pdev, info->required_regs[x],
 476                                        &priv->ini, false);
 477                if (err)
 478                        return -EINVAL;
 479        }
 480        if (info->optional_reg) {
 481                err = brcm_usb_get_regs(pdev, info->optional_reg,
 482                                        &priv->ini, true);
 483                if (err)
 484                        return -EINVAL;
 485        }
 486
 487        err = brcm_usb_phy_dvr_init(pdev, priv, dn);
 488        if (err)
 489                return err;
 490
 491        mutex_init(&priv->mutex);
 492
 493        /* make sure invert settings are correct */
 494        brcm_usb_init_ipp(&priv->ini);
 495
 496        /*
 497         * Create sysfs entries for mode.
 498         * Remove "dual_select" attribute if not in dual mode
 499         */
 500        if (priv->ini.mode != USB_CTLR_MODE_DRD)
 501                brcm_usb_phy_attrs[1] = NULL;
 502        err = sysfs_create_group(&dev->kobj, &brcm_usb_phy_group);
 503        if (err)
 504                dev_warn(dev, "Error creating sysfs attributes\n");
 505
 506        /* Get piarbctl syscon if it exists */
 507        rmap = syscon_regmap_lookup_by_phandle(dev->of_node,
 508                                                 "syscon-piarbctl");
 509        if (IS_ERR(rmap))
 510                rmap = syscon_regmap_lookup_by_phandle(dev->of_node,
 511                                                       "brcm,syscon-piarbctl");
 512        if (!IS_ERR(rmap))
 513                priv->ini.syscon_piarbctl = rmap;
 514
 515        /* start with everything off */
 516        if (priv->has_xhci)
 517                brcm_usb_uninit_xhci(&priv->ini);
 518        if (priv->has_eohci)
 519                brcm_usb_uninit_eohci(&priv->ini);
 520        brcm_usb_uninit_common(&priv->ini);
 521        clk_disable_unprepare(priv->usb_20_clk);
 522        clk_disable_unprepare(priv->usb_30_clk);
 523
 524        phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate);
 525
 526        return PTR_ERR_OR_ZERO(phy_provider);
 527}
 528
 529static int brcm_usb_phy_remove(struct platform_device *pdev)
 530{
 531        sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
 532
 533        return 0;
 534}
 535
 536#ifdef CONFIG_PM_SLEEP
 537static int brcm_usb_phy_suspend(struct device *dev)
 538{
 539        struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
 540
 541        if (priv->init_count) {
 542                priv->ini.wake_enabled = device_may_wakeup(dev);
 543                if (priv->phys[BRCM_USB_PHY_3_0].inited)
 544                        brcm_usb_uninit_xhci(&priv->ini);
 545                if (priv->phys[BRCM_USB_PHY_2_0].inited)
 546                        brcm_usb_uninit_eohci(&priv->ini);
 547                brcm_usb_uninit_common(&priv->ini);
 548
 549                /*
 550                 * Handle the clocks unless needed for wake. This has
 551                 * to work for both older XHCI->3.0-clks, EOHCI->2.0-clks
 552                 * and newer XHCI->2.0-clks/3.0-clks.
 553                 */
 554
 555                if (!priv->ini.suspend_with_clocks) {
 556                        if (priv->phys[BRCM_USB_PHY_3_0].inited)
 557                                clk_disable_unprepare(priv->usb_30_clk);
 558                        if (priv->phys[BRCM_USB_PHY_2_0].inited ||
 559                            !priv->has_eohci)
 560                                clk_disable_unprepare(priv->usb_20_clk);
 561                }
 562                if (priv->wake_irq >= 0)
 563                        enable_irq_wake(priv->wake_irq);
 564        }
 565        return 0;
 566}
 567
 568static int brcm_usb_phy_resume(struct device *dev)
 569{
 570        struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
 571
 572        clk_prepare_enable(priv->usb_20_clk);
 573        clk_prepare_enable(priv->usb_30_clk);
 574        brcm_usb_init_ipp(&priv->ini);
 575
 576        /*
 577         * Initialize anything that was previously initialized.
 578         * Uninitialize anything that wasn't previously initialized.
 579         */
 580        if (priv->init_count) {
 581                if (priv->wake_irq >= 0)
 582                        disable_irq_wake(priv->wake_irq);
 583                brcm_usb_init_common(&priv->ini);
 584                if (priv->phys[BRCM_USB_PHY_2_0].inited) {
 585                        brcm_usb_init_eohci(&priv->ini);
 586                } else if (priv->has_eohci) {
 587                        brcm_usb_uninit_eohci(&priv->ini);
 588                        clk_disable_unprepare(priv->usb_20_clk);
 589                }
 590                if (priv->phys[BRCM_USB_PHY_3_0].inited) {
 591                        brcm_usb_init_xhci(&priv->ini);
 592                } else if (priv->has_xhci) {
 593                        brcm_usb_uninit_xhci(&priv->ini);
 594                        clk_disable_unprepare(priv->usb_30_clk);
 595                        if (!priv->has_eohci)
 596                                clk_disable_unprepare(priv->usb_20_clk);
 597                }
 598        } else {
 599                if (priv->has_xhci)
 600                        brcm_usb_uninit_xhci(&priv->ini);
 601                if (priv->has_eohci)
 602                        brcm_usb_uninit_eohci(&priv->ini);
 603                brcm_usb_uninit_common(&priv->ini);
 604                clk_disable_unprepare(priv->usb_20_clk);
 605                clk_disable_unprepare(priv->usb_30_clk);
 606        }
 607        priv->ini.wake_enabled = false;
 608        return 0;
 609}
 610#endif /* CONFIG_PM_SLEEP */
 611
 612static const struct dev_pm_ops brcm_usb_phy_pm_ops = {
 613        SET_LATE_SYSTEM_SLEEP_PM_OPS(brcm_usb_phy_suspend, brcm_usb_phy_resume)
 614};
 615
 616MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
 617
 618static struct platform_driver brcm_usb_driver = {
 619        .probe          = brcm_usb_phy_probe,
 620        .remove         = brcm_usb_phy_remove,
 621        .driver         = {
 622                .name   = "brcmstb-usb-phy",
 623                .pm = &brcm_usb_phy_pm_ops,
 624                .of_match_table = brcm_usb_dt_ids,
 625        },
 626};
 627
 628module_platform_driver(brcm_usb_driver);
 629
 630MODULE_ALIAS("platform:brcmstb-usb-phy");
 631MODULE_AUTHOR("Al Cooper <acooper@broadcom.com>");
 632MODULE_DESCRIPTION("BRCM USB PHY driver");
 633MODULE_LICENSE("GPL v2");
 634