0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk.h>
0009 #include <linux/delay.h>
0010 #include <linux/err.h>
0011 #include <linux/io.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_device.h>
0015 #include <linux/phy/phy.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/soc/brcmstb/brcmstb.h>
0019 #include <dt-bindings/phy/phy.h>
0020 #include <linux/mfd/syscon.h>
0021 #include <linux/suspend.h>
0022
0023 #include "phy-brcm-usb-init.h"
0024
0025 static DEFINE_MUTEX(sysfs_lock);
0026
0027 enum brcm_usb_phy_id {
0028 BRCM_USB_PHY_2_0 = 0,
0029 BRCM_USB_PHY_3_0,
0030 BRCM_USB_PHY_ID_MAX
0031 };
0032
0033 struct value_to_name_map {
0034 int value;
0035 const char *name;
0036 };
0037
0038 struct match_chip_info {
0039 void (*init_func)(struct brcm_usb_init_params *params);
0040 u8 required_regs[BRCM_REGS_MAX + 1];
0041 u8 optional_reg;
0042 };
0043
0044 static const struct value_to_name_map brcm_dr_mode_to_name[] = {
0045 { USB_CTLR_MODE_HOST, "host" },
0046 { USB_CTLR_MODE_DEVICE, "peripheral" },
0047 { USB_CTLR_MODE_DRD, "drd" },
0048 { USB_CTLR_MODE_TYPEC_PD, "typec-pd" }
0049 };
0050
0051 static const struct value_to_name_map brcm_dual_mode_to_name[] = {
0052 { 0, "host" },
0053 { 1, "device" },
0054 { 2, "auto" },
0055 };
0056
0057 struct brcm_usb_phy {
0058 struct phy *phy;
0059 unsigned int id;
0060 bool inited;
0061 };
0062
0063 struct brcm_usb_phy_data {
0064 struct brcm_usb_init_params ini;
0065 bool has_eohci;
0066 bool has_xhci;
0067 struct clk *usb_20_clk;
0068 struct clk *usb_30_clk;
0069 struct clk *suspend_clk;
0070 struct mutex mutex;
0071 int init_count;
0072 int wake_irq;
0073 struct brcm_usb_phy phys[BRCM_USB_PHY_ID_MAX];
0074 struct notifier_block pm_notifier;
0075 bool pm_active;
0076 };
0077
0078 static s8 *node_reg_names[BRCM_REGS_MAX] = {
0079 "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
0080 };
0081
0082 static int brcm_pm_notifier(struct notifier_block *notifier,
0083 unsigned long pm_event,
0084 void *unused)
0085 {
0086 struct brcm_usb_phy_data *priv =
0087 container_of(notifier, struct brcm_usb_phy_data, pm_notifier);
0088
0089 switch (pm_event) {
0090 case PM_HIBERNATION_PREPARE:
0091 case PM_SUSPEND_PREPARE:
0092 priv->pm_active = true;
0093 break;
0094 case PM_POST_RESTORE:
0095 case PM_POST_HIBERNATION:
0096 case PM_POST_SUSPEND:
0097 priv->pm_active = false;
0098 break;
0099 }
0100 return NOTIFY_DONE;
0101 }
0102
0103 static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id)
0104 {
0105 struct phy *gphy = dev_id;
0106
0107 pm_wakeup_event(&gphy->dev, 0);
0108
0109 return IRQ_HANDLED;
0110 }
0111
0112 static int brcm_usb_phy_init(struct phy *gphy)
0113 {
0114 struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
0115 struct brcm_usb_phy_data *priv =
0116 container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
0117
0118 if (priv->pm_active)
0119 return 0;
0120
0121
0122
0123
0124
0125 mutex_lock(&priv->mutex);
0126 if (priv->init_count++ == 0) {
0127 clk_prepare_enable(priv->usb_20_clk);
0128 clk_prepare_enable(priv->usb_30_clk);
0129 clk_prepare_enable(priv->suspend_clk);
0130 brcm_usb_init_common(&priv->ini);
0131 }
0132 mutex_unlock(&priv->mutex);
0133 if (phy->id == BRCM_USB_PHY_2_0)
0134 brcm_usb_init_eohci(&priv->ini);
0135 else if (phy->id == BRCM_USB_PHY_3_0)
0136 brcm_usb_init_xhci(&priv->ini);
0137 phy->inited = true;
0138 dev_dbg(&gphy->dev, "INIT, id: %d, total: %d\n", phy->id,
0139 priv->init_count);
0140
0141 return 0;
0142 }
0143
0144 static int brcm_usb_phy_exit(struct phy *gphy)
0145 {
0146 struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
0147 struct brcm_usb_phy_data *priv =
0148 container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
0149
0150 if (priv->pm_active)
0151 return 0;
0152
0153 dev_dbg(&gphy->dev, "EXIT\n");
0154 if (phy->id == BRCM_USB_PHY_2_0)
0155 brcm_usb_uninit_eohci(&priv->ini);
0156 if (phy->id == BRCM_USB_PHY_3_0)
0157 brcm_usb_uninit_xhci(&priv->ini);
0158
0159
0160 mutex_lock(&priv->mutex);
0161 if (--priv->init_count == 0) {
0162 brcm_usb_uninit_common(&priv->ini);
0163 clk_disable_unprepare(priv->usb_20_clk);
0164 clk_disable_unprepare(priv->usb_30_clk);
0165 clk_disable_unprepare(priv->suspend_clk);
0166 }
0167 mutex_unlock(&priv->mutex);
0168 phy->inited = false;
0169 return 0;
0170 }
0171
0172 static const struct phy_ops brcm_usb_phy_ops = {
0173 .init = brcm_usb_phy_init,
0174 .exit = brcm_usb_phy_exit,
0175 .owner = THIS_MODULE,
0176 };
0177
0178 static struct phy *brcm_usb_phy_xlate(struct device *dev,
0179 struct of_phandle_args *args)
0180 {
0181 struct brcm_usb_phy_data *data = dev_get_drvdata(dev);
0182
0183
0184
0185
0186
0187 switch (args->args[0]) {
0188 case 0:
0189 case PHY_TYPE_USB2:
0190 if (data->phys[BRCM_USB_PHY_2_0].phy)
0191 return data->phys[BRCM_USB_PHY_2_0].phy;
0192 dev_warn(dev, "Error, 2.0 Phy not found\n");
0193 break;
0194 case 1:
0195 case PHY_TYPE_USB3:
0196 if (data->phys[BRCM_USB_PHY_3_0].phy)
0197 return data->phys[BRCM_USB_PHY_3_0].phy;
0198 dev_warn(dev, "Error, 3.0 Phy not found\n");
0199 break;
0200 }
0201 return ERR_PTR(-ENODEV);
0202 }
0203
0204 static int name_to_value(const struct value_to_name_map *table, int count,
0205 const char *name, int *value)
0206 {
0207 int x;
0208
0209 *value = 0;
0210 for (x = 0; x < count; x++) {
0211 if (sysfs_streq(name, table[x].name)) {
0212 *value = x;
0213 return 0;
0214 }
0215 }
0216 return -EINVAL;
0217 }
0218
0219 static const char *value_to_name(const struct value_to_name_map *table, int count,
0220 int value)
0221 {
0222 if (value >= count)
0223 return "unknown";
0224 return table[value].name;
0225 }
0226
0227 static ssize_t dr_mode_show(struct device *dev,
0228 struct device_attribute *attr,
0229 char *buf)
0230 {
0231 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
0232
0233 return sprintf(buf, "%s\n",
0234 value_to_name(&brcm_dr_mode_to_name[0],
0235 ARRAY_SIZE(brcm_dr_mode_to_name),
0236 priv->ini.mode));
0237 }
0238 static DEVICE_ATTR_RO(dr_mode);
0239
0240 static ssize_t dual_select_store(struct device *dev,
0241 struct device_attribute *attr,
0242 const char *buf, size_t len)
0243 {
0244 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
0245 int value;
0246 int res;
0247
0248 mutex_lock(&sysfs_lock);
0249 res = name_to_value(&brcm_dual_mode_to_name[0],
0250 ARRAY_SIZE(brcm_dual_mode_to_name), buf, &value);
0251 if (!res) {
0252 brcm_usb_set_dual_select(&priv->ini, value);
0253 res = len;
0254 }
0255 mutex_unlock(&sysfs_lock);
0256 return res;
0257 }
0258
0259 static ssize_t dual_select_show(struct device *dev,
0260 struct device_attribute *attr,
0261 char *buf)
0262 {
0263 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
0264 int value;
0265
0266 mutex_lock(&sysfs_lock);
0267 value = brcm_usb_get_dual_select(&priv->ini);
0268 mutex_unlock(&sysfs_lock);
0269 return sprintf(buf, "%s\n",
0270 value_to_name(&brcm_dual_mode_to_name[0],
0271 ARRAY_SIZE(brcm_dual_mode_to_name),
0272 value));
0273 }
0274 static DEVICE_ATTR_RW(dual_select);
0275
0276 static struct attribute *brcm_usb_phy_attrs[] = {
0277 &dev_attr_dr_mode.attr,
0278 &dev_attr_dual_select.attr,
0279 NULL
0280 };
0281
0282 static const struct attribute_group brcm_usb_phy_group = {
0283 .attrs = brcm_usb_phy_attrs,
0284 };
0285
0286 static const struct match_chip_info chip_info_4908 = {
0287 .init_func = &brcm_usb_dvr_init_4908,
0288 .required_regs = {
0289 BRCM_REGS_CTRL,
0290 BRCM_REGS_XHCI_EC,
0291 -1,
0292 },
0293 };
0294
0295 static const struct match_chip_info chip_info_7216 = {
0296 .init_func = &brcm_usb_dvr_init_7216,
0297 .required_regs = {
0298 BRCM_REGS_CTRL,
0299 BRCM_REGS_XHCI_EC,
0300 BRCM_REGS_XHCI_GBL,
0301 -1,
0302 },
0303 };
0304
0305 static const struct match_chip_info chip_info_7211b0 = {
0306 .init_func = &brcm_usb_dvr_init_7211b0,
0307 .required_regs = {
0308 BRCM_REGS_CTRL,
0309 BRCM_REGS_XHCI_EC,
0310 BRCM_REGS_XHCI_GBL,
0311 BRCM_REGS_USB_PHY,
0312 BRCM_REGS_USB_MDIO,
0313 -1,
0314 },
0315 .optional_reg = BRCM_REGS_BDC_EC,
0316 };
0317
0318 static const struct match_chip_info chip_info_7445 = {
0319 .init_func = &brcm_usb_dvr_init_7445,
0320 .required_regs = {
0321 BRCM_REGS_CTRL,
0322 BRCM_REGS_XHCI_EC,
0323 -1,
0324 },
0325 };
0326
0327 static const struct of_device_id brcm_usb_dt_ids[] = {
0328 {
0329 .compatible = "brcm,bcm4908-usb-phy",
0330 .data = &chip_info_4908,
0331 },
0332 {
0333 .compatible = "brcm,bcm7216-usb-phy",
0334 .data = &chip_info_7216,
0335 },
0336 {
0337 .compatible = "brcm,bcm7211-usb-phy",
0338 .data = &chip_info_7211b0,
0339 },
0340 {
0341 .compatible = "brcm,brcmstb-usb-phy",
0342 .data = &chip_info_7445,
0343 },
0344 { }
0345 };
0346
0347 static int brcm_usb_get_regs(struct platform_device *pdev,
0348 enum brcmusb_reg_sel regs,
0349 struct brcm_usb_init_params *ini,
0350 bool optional)
0351 {
0352 struct resource *res;
0353
0354
0355 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
0356 node_reg_names[regs]);
0357 if (res == NULL) {
0358 if (regs == BRCM_REGS_CTRL) {
0359 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0360 } else if (regs == BRCM_REGS_XHCI_EC) {
0361 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0362
0363 if (res == NULL)
0364 return 0;
0365 }
0366 if (res == NULL) {
0367 if (optional) {
0368 dev_dbg(&pdev->dev,
0369 "Optional reg %s not found\n",
0370 node_reg_names[regs]);
0371 return 0;
0372 }
0373 dev_err(&pdev->dev, "can't get %s base addr\n",
0374 node_reg_names[regs]);
0375 return 1;
0376 }
0377 }
0378 ini->regs[regs] = devm_ioremap_resource(&pdev->dev, res);
0379 if (IS_ERR(ini->regs[regs])) {
0380 dev_err(&pdev->dev, "can't map %s register space\n",
0381 node_reg_names[regs]);
0382 return 1;
0383 }
0384 return 0;
0385 }
0386
0387 static int brcm_usb_phy_dvr_init(struct platform_device *pdev,
0388 struct brcm_usb_phy_data *priv,
0389 struct device_node *dn)
0390 {
0391 struct device *dev = &pdev->dev;
0392 struct phy *gphy = NULL;
0393 int err;
0394
0395 priv->usb_20_clk = of_clk_get_by_name(dn, "sw_usb");
0396 if (IS_ERR(priv->usb_20_clk)) {
0397 if (PTR_ERR(priv->usb_20_clk) == -EPROBE_DEFER)
0398 return -EPROBE_DEFER;
0399 dev_info(dev, "Clock not found in Device Tree\n");
0400 priv->usb_20_clk = NULL;
0401 }
0402 err = clk_prepare_enable(priv->usb_20_clk);
0403 if (err)
0404 return err;
0405
0406 if (priv->has_eohci) {
0407 gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
0408 if (IS_ERR(gphy)) {
0409 dev_err(dev, "failed to create EHCI/OHCI PHY\n");
0410 return PTR_ERR(gphy);
0411 }
0412 priv->phys[BRCM_USB_PHY_2_0].phy = gphy;
0413 priv->phys[BRCM_USB_PHY_2_0].id = BRCM_USB_PHY_2_0;
0414 phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_2_0]);
0415 }
0416
0417 if (priv->has_xhci) {
0418 gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
0419 if (IS_ERR(gphy)) {
0420 dev_err(dev, "failed to create XHCI PHY\n");
0421 return PTR_ERR(gphy);
0422 }
0423 priv->phys[BRCM_USB_PHY_3_0].phy = gphy;
0424 priv->phys[BRCM_USB_PHY_3_0].id = BRCM_USB_PHY_3_0;
0425 phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_3_0]);
0426
0427 priv->usb_30_clk = of_clk_get_by_name(dn, "sw_usb3");
0428 if (IS_ERR(priv->usb_30_clk)) {
0429 if (PTR_ERR(priv->usb_30_clk) == -EPROBE_DEFER)
0430 return -EPROBE_DEFER;
0431 dev_info(dev,
0432 "USB3.0 clock not found in Device Tree\n");
0433 priv->usb_30_clk = NULL;
0434 }
0435 err = clk_prepare_enable(priv->usb_30_clk);
0436 if (err)
0437 return err;
0438 }
0439
0440 priv->suspend_clk = clk_get(dev, "usb0_freerun");
0441 if (IS_ERR(priv->suspend_clk)) {
0442 if (PTR_ERR(priv->suspend_clk) == -EPROBE_DEFER)
0443 return -EPROBE_DEFER;
0444 dev_err(dev, "Suspend Clock not found in Device Tree\n");
0445 priv->suspend_clk = NULL;
0446 }
0447
0448 priv->wake_irq = platform_get_irq_byname(pdev, "wake");
0449 if (priv->wake_irq < 0)
0450 priv->wake_irq = platform_get_irq_byname(pdev, "wakeup");
0451 if (priv->wake_irq >= 0) {
0452 err = devm_request_irq(dev, priv->wake_irq,
0453 brcm_usb_phy_wake_isr, 0,
0454 dev_name(dev), gphy);
0455 if (err < 0)
0456 return err;
0457 device_set_wakeup_capable(dev, 1);
0458 } else {
0459 dev_info(dev,
0460 "Wake interrupt missing, system wake not supported\n");
0461 }
0462
0463 return 0;
0464 }
0465
0466 static int brcm_usb_phy_probe(struct platform_device *pdev)
0467 {
0468 struct device *dev = &pdev->dev;
0469 struct brcm_usb_phy_data *priv;
0470 struct phy_provider *phy_provider;
0471 struct device_node *dn = pdev->dev.of_node;
0472 int err;
0473 const char *mode;
0474 const struct match_chip_info *info;
0475 struct regmap *rmap;
0476 int x;
0477
0478 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0479 if (!priv)
0480 return -ENOMEM;
0481 platform_set_drvdata(pdev, priv);
0482
0483 priv->ini.family_id = brcmstb_get_family_id();
0484 priv->ini.product_id = brcmstb_get_product_id();
0485
0486 info = of_device_get_match_data(&pdev->dev);
0487 if (!info)
0488 return -ENOENT;
0489
0490 info->init_func(&priv->ini);
0491
0492 dev_dbg(dev, "Best mapping table is for %s\n",
0493 priv->ini.family_name);
0494
0495 of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp);
0496 of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc);
0497
0498 priv->ini.mode = USB_CTLR_MODE_HOST;
0499 err = of_property_read_string(dn, "dr_mode", &mode);
0500 if (err == 0) {
0501 name_to_value(&brcm_dr_mode_to_name[0],
0502 ARRAY_SIZE(brcm_dr_mode_to_name),
0503 mode, &priv->ini.mode);
0504 }
0505 if (of_property_read_bool(dn, "brcm,has-xhci"))
0506 priv->has_xhci = true;
0507 if (of_property_read_bool(dn, "brcm,has-eohci"))
0508 priv->has_eohci = true;
0509
0510 for (x = 0; x < BRCM_REGS_MAX; x++) {
0511 if (info->required_regs[x] >= BRCM_REGS_MAX)
0512 break;
0513
0514 err = brcm_usb_get_regs(pdev, info->required_regs[x],
0515 &priv->ini, false);
0516 if (err)
0517 return -EINVAL;
0518 }
0519 if (info->optional_reg) {
0520 err = brcm_usb_get_regs(pdev, info->optional_reg,
0521 &priv->ini, true);
0522 if (err)
0523 return -EINVAL;
0524 }
0525
0526 err = brcm_usb_phy_dvr_init(pdev, priv, dn);
0527 if (err)
0528 return err;
0529
0530 priv->pm_notifier.notifier_call = brcm_pm_notifier;
0531 register_pm_notifier(&priv->pm_notifier);
0532
0533 mutex_init(&priv->mutex);
0534
0535
0536 brcm_usb_init_ipp(&priv->ini);
0537
0538
0539
0540
0541
0542 if (priv->ini.mode != USB_CTLR_MODE_DRD)
0543 brcm_usb_phy_attrs[1] = NULL;
0544 err = sysfs_create_group(&dev->kobj, &brcm_usb_phy_group);
0545 if (err)
0546 dev_warn(dev, "Error creating sysfs attributes\n");
0547
0548
0549 rmap = syscon_regmap_lookup_by_phandle(dev->of_node,
0550 "syscon-piarbctl");
0551 if (IS_ERR(rmap))
0552 rmap = syscon_regmap_lookup_by_phandle(dev->of_node,
0553 "brcm,syscon-piarbctl");
0554 if (!IS_ERR(rmap))
0555 priv->ini.syscon_piarbctl = rmap;
0556
0557
0558 if (priv->has_xhci)
0559 brcm_usb_uninit_xhci(&priv->ini);
0560 if (priv->has_eohci)
0561 brcm_usb_uninit_eohci(&priv->ini);
0562 brcm_usb_uninit_common(&priv->ini);
0563 clk_disable_unprepare(priv->usb_20_clk);
0564 clk_disable_unprepare(priv->usb_30_clk);
0565
0566 phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate);
0567
0568 return PTR_ERR_OR_ZERO(phy_provider);
0569 }
0570
0571 static int brcm_usb_phy_remove(struct platform_device *pdev)
0572 {
0573 struct brcm_usb_phy_data *priv = dev_get_drvdata(&pdev->dev);
0574
0575 sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
0576 unregister_pm_notifier(&priv->pm_notifier);
0577
0578 return 0;
0579 }
0580
0581 #ifdef CONFIG_PM_SLEEP
0582 static int brcm_usb_phy_suspend(struct device *dev)
0583 {
0584 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
0585
0586 if (priv->init_count) {
0587 dev_dbg(dev, "SUSPEND\n");
0588 priv->ini.wake_enabled = device_may_wakeup(dev);
0589 if (priv->phys[BRCM_USB_PHY_3_0].inited)
0590 brcm_usb_uninit_xhci(&priv->ini);
0591 if (priv->phys[BRCM_USB_PHY_2_0].inited)
0592 brcm_usb_uninit_eohci(&priv->ini);
0593 brcm_usb_uninit_common(&priv->ini);
0594
0595
0596
0597
0598
0599
0600
0601 if (!priv->ini.suspend_with_clocks) {
0602 if (priv->phys[BRCM_USB_PHY_3_0].inited)
0603 clk_disable_unprepare(priv->usb_30_clk);
0604 if (priv->phys[BRCM_USB_PHY_2_0].inited ||
0605 !priv->has_eohci)
0606 clk_disable_unprepare(priv->usb_20_clk);
0607 }
0608 if (priv->wake_irq >= 0)
0609 enable_irq_wake(priv->wake_irq);
0610 }
0611 return 0;
0612 }
0613
0614 static int brcm_usb_phy_resume(struct device *dev)
0615 {
0616 struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
0617
0618 clk_prepare_enable(priv->usb_20_clk);
0619 clk_prepare_enable(priv->usb_30_clk);
0620 brcm_usb_init_ipp(&priv->ini);
0621
0622
0623
0624
0625
0626 if (priv->init_count) {
0627 dev_dbg(dev, "RESUME\n");
0628 if (priv->wake_irq >= 0)
0629 disable_irq_wake(priv->wake_irq);
0630 brcm_usb_init_common(&priv->ini);
0631 if (priv->phys[BRCM_USB_PHY_2_0].inited) {
0632 brcm_usb_init_eohci(&priv->ini);
0633 } else if (priv->has_eohci) {
0634 brcm_usb_uninit_eohci(&priv->ini);
0635 clk_disable_unprepare(priv->usb_20_clk);
0636 }
0637 if (priv->phys[BRCM_USB_PHY_3_0].inited) {
0638 brcm_usb_init_xhci(&priv->ini);
0639 } else if (priv->has_xhci) {
0640 brcm_usb_uninit_xhci(&priv->ini);
0641 clk_disable_unprepare(priv->usb_30_clk);
0642 if (!priv->has_eohci)
0643 clk_disable_unprepare(priv->usb_20_clk);
0644 }
0645 } else {
0646 if (priv->has_xhci)
0647 brcm_usb_uninit_xhci(&priv->ini);
0648 if (priv->has_eohci)
0649 brcm_usb_uninit_eohci(&priv->ini);
0650 brcm_usb_uninit_common(&priv->ini);
0651 clk_disable_unprepare(priv->usb_20_clk);
0652 clk_disable_unprepare(priv->usb_30_clk);
0653 }
0654 priv->ini.wake_enabled = false;
0655 return 0;
0656 }
0657 #endif
0658
0659 static const struct dev_pm_ops brcm_usb_phy_pm_ops = {
0660 SET_LATE_SYSTEM_SLEEP_PM_OPS(brcm_usb_phy_suspend, brcm_usb_phy_resume)
0661 };
0662
0663 MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
0664
0665 static struct platform_driver brcm_usb_driver = {
0666 .probe = brcm_usb_phy_probe,
0667 .remove = brcm_usb_phy_remove,
0668 .driver = {
0669 .name = "brcmstb-usb-phy",
0670 .pm = &brcm_usb_phy_pm_ops,
0671 .of_match_table = brcm_usb_dt_ids,
0672 },
0673 };
0674
0675 module_platform_driver(brcm_usb_driver);
0676
0677 MODULE_ALIAS("platform:brcmstb-usb-phy");
0678 MODULE_AUTHOR("Al Cooper <acooper@broadcom.com>");
0679 MODULE_DESCRIPTION("BRCM USB PHY driver");
0680 MODULE_LICENSE("GPL v2");