Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Driver for onboard USB hubs
0004  *
0005  * Copyright (c) 2022, Google LLC
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/export.h>
0010 #include <linux/gpio/consumer.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/list.h>
0014 #include <linux/module.h>
0015 #include <linux/mutex.h>
0016 #include <linux/of.h>
0017 #include <linux/of_platform.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/regulator/consumer.h>
0020 #include <linux/slab.h>
0021 #include <linux/suspend.h>
0022 #include <linux/sysfs.h>
0023 #include <linux/usb.h>
0024 #include <linux/usb/hcd.h>
0025 #include <linux/usb/onboard_hub.h>
0026 #include <linux/workqueue.h>
0027 
0028 #include "onboard_usb_hub.h"
0029 
0030 static struct usb_device_driver onboard_hub_usbdev_driver;
0031 
0032 /************************** Platform driver **************************/
0033 
0034 struct usbdev_node {
0035     struct usb_device *udev;
0036     struct list_head list;
0037 };
0038 
0039 struct onboard_hub {
0040     struct regulator *vdd;
0041     struct device *dev;
0042     const struct onboard_hub_pdata *pdata;
0043     struct gpio_desc *reset_gpio;
0044     bool always_powered_in_suspend;
0045     bool is_powered_on;
0046     bool going_away;
0047     struct list_head udev_list;
0048     struct work_struct attach_usb_driver_work;
0049     struct mutex lock;
0050 };
0051 
0052 static int onboard_hub_power_on(struct onboard_hub *hub)
0053 {
0054     int err;
0055 
0056     err = regulator_enable(hub->vdd);
0057     if (err) {
0058         dev_err(hub->dev, "failed to enable regulator: %d\n", err);
0059         return err;
0060     }
0061 
0062     fsleep(hub->pdata->reset_us);
0063     gpiod_set_value_cansleep(hub->reset_gpio, 0);
0064 
0065     hub->is_powered_on = true;
0066 
0067     return 0;
0068 }
0069 
0070 static int onboard_hub_power_off(struct onboard_hub *hub)
0071 {
0072     int err;
0073 
0074     gpiod_set_value_cansleep(hub->reset_gpio, 1);
0075 
0076     err = regulator_disable(hub->vdd);
0077     if (err) {
0078         dev_err(hub->dev, "failed to disable regulator: %d\n", err);
0079         return err;
0080     }
0081 
0082     hub->is_powered_on = false;
0083 
0084     return 0;
0085 }
0086 
0087 static int __maybe_unused onboard_hub_suspend(struct device *dev)
0088 {
0089     struct onboard_hub *hub = dev_get_drvdata(dev);
0090     struct usbdev_node *node;
0091     bool power_off = true;
0092 
0093     if (hub->always_powered_in_suspend)
0094         return 0;
0095 
0096     mutex_lock(&hub->lock);
0097 
0098     list_for_each_entry(node, &hub->udev_list, list) {
0099         if (!device_may_wakeup(node->udev->bus->controller))
0100             continue;
0101 
0102         if (usb_wakeup_enabled_descendants(node->udev)) {
0103             power_off = false;
0104             break;
0105         }
0106     }
0107 
0108     mutex_unlock(&hub->lock);
0109 
0110     if (!power_off)
0111         return 0;
0112 
0113     return onboard_hub_power_off(hub);
0114 }
0115 
0116 static int __maybe_unused onboard_hub_resume(struct device *dev)
0117 {
0118     struct onboard_hub *hub = dev_get_drvdata(dev);
0119 
0120     if (hub->is_powered_on)
0121         return 0;
0122 
0123     return onboard_hub_power_on(hub);
0124 }
0125 
0126 static inline void get_udev_link_name(const struct usb_device *udev, char *buf, size_t size)
0127 {
0128     snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev));
0129 }
0130 
0131 static int onboard_hub_add_usbdev(struct onboard_hub *hub, struct usb_device *udev)
0132 {
0133     struct usbdev_node *node;
0134     char link_name[64];
0135     int err;
0136 
0137     mutex_lock(&hub->lock);
0138 
0139     if (hub->going_away) {
0140         err = -EINVAL;
0141         goto error;
0142     }
0143 
0144     node = kzalloc(sizeof(*node), GFP_KERNEL);
0145     if (!node) {
0146         err = -ENOMEM;
0147         goto error;
0148     }
0149 
0150     node->udev = udev;
0151 
0152     list_add(&node->list, &hub->udev_list);
0153 
0154     mutex_unlock(&hub->lock);
0155 
0156     get_udev_link_name(udev, link_name, sizeof(link_name));
0157     WARN_ON(sysfs_create_link(&hub->dev->kobj, &udev->dev.kobj, link_name));
0158 
0159     return 0;
0160 
0161 error:
0162     mutex_unlock(&hub->lock);
0163 
0164     return err;
0165 }
0166 
0167 static void onboard_hub_remove_usbdev(struct onboard_hub *hub, const struct usb_device *udev)
0168 {
0169     struct usbdev_node *node;
0170     char link_name[64];
0171 
0172     get_udev_link_name(udev, link_name, sizeof(link_name));
0173     sysfs_remove_link(&hub->dev->kobj, link_name);
0174 
0175     mutex_lock(&hub->lock);
0176 
0177     list_for_each_entry(node, &hub->udev_list, list) {
0178         if (node->udev == udev) {
0179             list_del(&node->list);
0180             kfree(node);
0181             break;
0182         }
0183     }
0184 
0185     mutex_unlock(&hub->lock);
0186 }
0187 
0188 static ssize_t always_powered_in_suspend_show(struct device *dev, struct device_attribute *attr,
0189                char *buf)
0190 {
0191     const struct onboard_hub *hub = dev_get_drvdata(dev);
0192 
0193     return sysfs_emit(buf, "%d\n", hub->always_powered_in_suspend);
0194 }
0195 
0196 static ssize_t always_powered_in_suspend_store(struct device *dev, struct device_attribute *attr,
0197                 const char *buf, size_t count)
0198 {
0199     struct onboard_hub *hub = dev_get_drvdata(dev);
0200     bool val;
0201     int ret;
0202 
0203     ret = kstrtobool(buf, &val);
0204     if (ret < 0)
0205         return ret;
0206 
0207     hub->always_powered_in_suspend = val;
0208 
0209     return count;
0210 }
0211 static DEVICE_ATTR_RW(always_powered_in_suspend);
0212 
0213 static struct attribute *onboard_hub_attrs[] = {
0214     &dev_attr_always_powered_in_suspend.attr,
0215     NULL,
0216 };
0217 ATTRIBUTE_GROUPS(onboard_hub);
0218 
0219 static void onboard_hub_attach_usb_driver(struct work_struct *work)
0220 {
0221     int err;
0222 
0223     err = driver_attach(&onboard_hub_usbdev_driver.drvwrap.driver);
0224     if (err)
0225         pr_err("Failed to attach USB driver: %d\n", err);
0226 }
0227 
0228 static int onboard_hub_probe(struct platform_device *pdev)
0229 {
0230     const struct of_device_id *of_id;
0231     struct device *dev = &pdev->dev;
0232     struct onboard_hub *hub;
0233     int err;
0234 
0235     hub = devm_kzalloc(dev, sizeof(*hub), GFP_KERNEL);
0236     if (!hub)
0237         return -ENOMEM;
0238 
0239     of_id = of_match_device(onboard_hub_match, &pdev->dev);
0240     if (!of_id)
0241         return -ENODEV;
0242 
0243     hub->pdata = of_id->data;
0244     if (!hub->pdata)
0245         return -EINVAL;
0246 
0247     hub->vdd = devm_regulator_get(dev, "vdd");
0248     if (IS_ERR(hub->vdd))
0249         return PTR_ERR(hub->vdd);
0250 
0251     hub->reset_gpio = devm_gpiod_get_optional(dev, "reset",
0252                           GPIOD_OUT_HIGH);
0253     if (IS_ERR(hub->reset_gpio))
0254         return dev_err_probe(dev, PTR_ERR(hub->reset_gpio), "failed to get reset GPIO\n");
0255 
0256     hub->dev = dev;
0257     mutex_init(&hub->lock);
0258     INIT_LIST_HEAD(&hub->udev_list);
0259 
0260     dev_set_drvdata(dev, hub);
0261 
0262     err = onboard_hub_power_on(hub);
0263     if (err)
0264         return err;
0265 
0266     /*
0267      * The USB driver might have been detached from the USB devices by
0268      * onboard_hub_remove() (e.g. through an 'unbind' by userspace),
0269      * make sure to re-attach it if needed.
0270      *
0271      * This needs to be done deferred to avoid self-deadlocks on systems
0272      * with nested onboard hubs.
0273      */
0274     INIT_WORK(&hub->attach_usb_driver_work, onboard_hub_attach_usb_driver);
0275     schedule_work(&hub->attach_usb_driver_work);
0276 
0277     return 0;
0278 }
0279 
0280 static int onboard_hub_remove(struct platform_device *pdev)
0281 {
0282     struct onboard_hub *hub = dev_get_drvdata(&pdev->dev);
0283     struct usbdev_node *node;
0284     struct usb_device *udev;
0285 
0286     hub->going_away = true;
0287 
0288     if (&hub->attach_usb_driver_work != current_work())
0289         cancel_work_sync(&hub->attach_usb_driver_work);
0290 
0291     mutex_lock(&hub->lock);
0292 
0293     /* unbind the USB devices to avoid dangling references to this device */
0294     while (!list_empty(&hub->udev_list)) {
0295         node = list_first_entry(&hub->udev_list, struct usbdev_node, list);
0296         udev = node->udev;
0297 
0298         /*
0299          * Unbinding the driver will call onboard_hub_remove_usbdev(),
0300          * which acquires hub->lock.  We must release the lock first.
0301          */
0302         get_device(&udev->dev);
0303         mutex_unlock(&hub->lock);
0304         device_release_driver(&udev->dev);
0305         put_device(&udev->dev);
0306         mutex_lock(&hub->lock);
0307     }
0308 
0309     mutex_unlock(&hub->lock);
0310 
0311     return onboard_hub_power_off(hub);
0312 }
0313 
0314 MODULE_DEVICE_TABLE(of, onboard_hub_match);
0315 
0316 static const struct dev_pm_ops __maybe_unused onboard_hub_pm_ops = {
0317     SET_LATE_SYSTEM_SLEEP_PM_OPS(onboard_hub_suspend, onboard_hub_resume)
0318 };
0319 
0320 static struct platform_driver onboard_hub_driver = {
0321     .probe = onboard_hub_probe,
0322     .remove = onboard_hub_remove,
0323 
0324     .driver = {
0325         .name = "onboard-usb-hub",
0326         .of_match_table = onboard_hub_match,
0327         .pm = pm_ptr(&onboard_hub_pm_ops),
0328         .dev_groups = onboard_hub_groups,
0329     },
0330 };
0331 
0332 /************************** USB driver **************************/
0333 
0334 #define VENDOR_ID_MICROCHIP 0x0424
0335 #define VENDOR_ID_REALTEK   0x0bda
0336 #define VENDOR_ID_TI        0x0451
0337 
0338 /*
0339  * Returns the onboard_hub platform device that is associated with the USB
0340  * device passed as parameter.
0341  */
0342 static struct onboard_hub *_find_onboard_hub(struct device *dev)
0343 {
0344     struct platform_device *pdev;
0345     struct device_node *np;
0346     struct onboard_hub *hub;
0347 
0348     pdev = of_find_device_by_node(dev->of_node);
0349     if (!pdev) {
0350         np = of_parse_phandle(dev->of_node, "peer-hub", 0);
0351         if (!np) {
0352             dev_err(dev, "failed to find device node for peer hub\n");
0353             return ERR_PTR(-EINVAL);
0354         }
0355 
0356         pdev = of_find_device_by_node(np);
0357         of_node_put(np);
0358 
0359         if (!pdev)
0360             return ERR_PTR(-ENODEV);
0361     }
0362 
0363     hub = dev_get_drvdata(&pdev->dev);
0364     put_device(&pdev->dev);
0365 
0366     /*
0367      * The presence of drvdata ('hub') indicates that the platform driver
0368      * finished probing. This handles the case where (conceivably) we could
0369      * be running at the exact same time as the platform driver's probe. If
0370      * we detect the race we request probe deferral and we'll come back and
0371      * try again.
0372      */
0373     if (!hub)
0374         return ERR_PTR(-EPROBE_DEFER);
0375 
0376     return hub;
0377 }
0378 
0379 static int onboard_hub_usbdev_probe(struct usb_device *udev)
0380 {
0381     struct device *dev = &udev->dev;
0382     struct onboard_hub *hub;
0383     int err;
0384 
0385     /* ignore supported hubs without device tree node */
0386     if (!dev->of_node)
0387         return -ENODEV;
0388 
0389     hub = _find_onboard_hub(dev);
0390     if (IS_ERR(hub))
0391         return PTR_ERR(hub);
0392 
0393     dev_set_drvdata(dev, hub);
0394 
0395     err = onboard_hub_add_usbdev(hub, udev);
0396     if (err)
0397         return err;
0398 
0399     return 0;
0400 }
0401 
0402 static void onboard_hub_usbdev_disconnect(struct usb_device *udev)
0403 {
0404     struct onboard_hub *hub = dev_get_drvdata(&udev->dev);
0405 
0406     onboard_hub_remove_usbdev(hub, udev);
0407 }
0408 
0409 static const struct usb_device_id onboard_hub_id_table[] = {
0410     { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
0411     { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
0412     { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */
0413     { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */
0414     { USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 */
0415     { USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 */
0416     { USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 */
0417     {}
0418 };
0419 MODULE_DEVICE_TABLE(usb, onboard_hub_id_table);
0420 
0421 static struct usb_device_driver onboard_hub_usbdev_driver = {
0422     .name = "onboard-usb-hub",
0423     .probe = onboard_hub_usbdev_probe,
0424     .disconnect = onboard_hub_usbdev_disconnect,
0425     .generic_subclass = 1,
0426     .supports_autosuspend = 1,
0427     .id_table = onboard_hub_id_table,
0428 };
0429 
0430 static int __init onboard_hub_init(void)
0431 {
0432     int ret;
0433 
0434     ret = platform_driver_register(&onboard_hub_driver);
0435     if (ret)
0436         return ret;
0437 
0438     ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE);
0439     if (ret)
0440         platform_driver_unregister(&onboard_hub_driver);
0441 
0442     return ret;
0443 }
0444 module_init(onboard_hub_init);
0445 
0446 static void __exit onboard_hub_exit(void)
0447 {
0448     usb_deregister_device_driver(&onboard_hub_usbdev_driver);
0449     platform_driver_unregister(&onboard_hub_driver);
0450 }
0451 module_exit(onboard_hub_exit);
0452 
0453 MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>");
0454 MODULE_DESCRIPTION("Driver for discrete onboard USB hubs");
0455 MODULE_LICENSE("GPL v2");