linux/drivers/usb/phy/phy-gpio-vbus-usb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices
   4 *
   5 * Copyright (c) 2008 Philipp Zabel <philipp.zabel@gmail.com>
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/platform_device.h>
  10#include <linux/gpio.h>
  11#include <linux/module.h>
  12#include <linux/slab.h>
  13#include <linux/interrupt.h>
  14#include <linux/usb.h>
  15#include <linux/workqueue.h>
  16
  17#include <linux/regulator/consumer.h>
  18
  19#include <linux/usb/gadget.h>
  20#include <linux/usb/gpio_vbus.h>
  21#include <linux/usb/otg.h>
  22
  23
  24/*
  25 * A simple GPIO VBUS sensing driver for B peripheral only devices
  26 * with internal transceivers. It can control a D+ pullup GPIO and
  27 * a regulator to limit the current drawn from VBUS.
  28 *
  29 * Needs to be loaded before the UDC driver that will use it.
  30 */
  31struct gpio_vbus_data {
  32        struct usb_phy          phy;
  33        struct device          *dev;
  34        struct regulator       *vbus_draw;
  35        int                     vbus_draw_enabled;
  36        unsigned                mA;
  37        struct delayed_work     work;
  38        int                     vbus;
  39        int                     irq;
  40};
  41
  42
  43/*
  44 * This driver relies on "both edges" triggering.  VBUS has 100 msec to
  45 * stabilize, so the peripheral controller driver may need to cope with
  46 * some bouncing due to current surges (e.g. charging local capacitance)
  47 * and contact chatter.
  48 *
  49 * REVISIT in desperate straits, toggling between rising and falling
  50 * edges might be workable.
  51 */
  52#define VBUS_IRQ_FLAGS \
  53        (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
  54
  55
  56/* interface to regulator framework */
  57static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
  58{
  59        struct regulator *vbus_draw = gpio_vbus->vbus_draw;
  60        int enabled;
  61        int ret;
  62
  63        if (!vbus_draw)
  64                return;
  65
  66        enabled = gpio_vbus->vbus_draw_enabled;
  67        if (mA) {
  68                regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
  69                if (!enabled) {
  70                        ret = regulator_enable(vbus_draw);
  71                        if (ret < 0)
  72                                return;
  73                        gpio_vbus->vbus_draw_enabled = 1;
  74                }
  75        } else {
  76                if (enabled) {
  77                        ret = regulator_disable(vbus_draw);
  78                        if (ret < 0)
  79                                return;
  80                        gpio_vbus->vbus_draw_enabled = 0;
  81                }
  82        }
  83        gpio_vbus->mA = mA;
  84}
  85
  86static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
  87{
  88        int vbus;
  89
  90        vbus = gpio_get_value(pdata->gpio_vbus);
  91        if (pdata->gpio_vbus_inverted)
  92                vbus = !vbus;
  93
  94        return vbus;
  95}
  96
  97static void gpio_vbus_work(struct work_struct *work)
  98{
  99        struct gpio_vbus_data *gpio_vbus =
 100                container_of(work, struct gpio_vbus_data, work.work);
 101        struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev);
 102        int gpio, status, vbus;
 103
 104        if (!gpio_vbus->phy.otg->gadget)
 105                return;
 106
 107        vbus = is_vbus_powered(pdata);
 108        if ((vbus ^ gpio_vbus->vbus) == 0)
 109                return;
 110        gpio_vbus->vbus = vbus;
 111
 112        /* Peripheral controllers which manage the pullup themselves won't have
 113         * gpio_pullup configured here.  If it's configured here, we'll do what
 114         * isp1301_omap::b_peripheral() does and enable the pullup here... although
 115         * that may complicate usb_gadget_{,dis}connect() support.
 116         */
 117        gpio = pdata->gpio_pullup;
 118
 119        if (vbus) {
 120                status = USB_EVENT_VBUS;
 121                gpio_vbus->phy.otg->state = OTG_STATE_B_PERIPHERAL;
 122                gpio_vbus->phy.last_event = status;
 123                usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget);
 124
 125                /* drawing a "unit load" is *always* OK, except for OTG */
 126                set_vbus_draw(gpio_vbus, 100);
 127
 128                /* optionally enable D+ pullup */
 129                if (gpio_is_valid(gpio))
 130                        gpio_set_value(gpio, !pdata->gpio_pullup_inverted);
 131
 132                atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
 133                                           status, gpio_vbus->phy.otg->gadget);
 134                usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_ENUMERATED);
 135        } else {
 136                /* optionally disable D+ pullup */
 137                if (gpio_is_valid(gpio))
 138                        gpio_set_value(gpio, pdata->gpio_pullup_inverted);
 139
 140                set_vbus_draw(gpio_vbus, 0);
 141
 142                usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget);
 143                status = USB_EVENT_NONE;
 144                gpio_vbus->phy.otg->state = OTG_STATE_B_IDLE;
 145                gpio_vbus->phy.last_event = status;
 146
 147                atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
 148                                           status, gpio_vbus->phy.otg->gadget);
 149                usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_NONE);
 150        }
 151}
 152
 153/* VBUS change IRQ handler */
 154static irqreturn_t gpio_vbus_irq(int irq, void *data)
 155{
 156        struct platform_device *pdev = data;
 157        struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
 158        struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
 159        struct usb_otg *otg = gpio_vbus->phy.otg;
 160
 161        dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
 162                is_vbus_powered(pdata) ? "supplied" : "inactive",
 163                otg->gadget ? otg->gadget->name : "none");
 164
 165        if (otg->gadget)
 166                schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100));
 167
 168        return IRQ_HANDLED;
 169}
 170
 171/* OTG transceiver interface */
 172
 173/* bind/unbind the peripheral controller */
 174static int gpio_vbus_set_peripheral(struct usb_otg *otg,
 175                                        struct usb_gadget *gadget)
 176{
 177        struct gpio_vbus_data *gpio_vbus;
 178        struct gpio_vbus_mach_info *pdata;
 179        struct platform_device *pdev;
 180        int gpio;
 181
 182        gpio_vbus = container_of(otg->usb_phy, struct gpio_vbus_data, phy);
 183        pdev = to_platform_device(gpio_vbus->dev);
 184        pdata = dev_get_platdata(gpio_vbus->dev);
 185        gpio = pdata->gpio_pullup;
 186
 187        if (!gadget) {
 188                dev_dbg(&pdev->dev, "unregistering gadget '%s'\n",
 189                        otg->gadget->name);
 190
 191                /* optionally disable D+ pullup */
 192                if (gpio_is_valid(gpio))
 193                        gpio_set_value(gpio, pdata->gpio_pullup_inverted);
 194
 195                set_vbus_draw(gpio_vbus, 0);
 196
 197                usb_gadget_vbus_disconnect(otg->gadget);
 198                otg->state = OTG_STATE_UNDEFINED;
 199
 200                otg->gadget = NULL;
 201                return 0;
 202        }
 203
 204        otg->gadget = gadget;
 205        dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
 206
 207        /* initialize connection state */
 208        gpio_vbus->vbus = 0; /* start with disconnected */
 209        gpio_vbus_irq(gpio_vbus->irq, pdev);
 210        return 0;
 211}
 212
 213/* effective for B devices, ignored for A-peripheral */
 214static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA)
 215{
 216        struct gpio_vbus_data *gpio_vbus;
 217
 218        gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
 219
 220        if (phy->otg->state == OTG_STATE_B_PERIPHERAL)
 221                set_vbus_draw(gpio_vbus, mA);
 222        return 0;
 223}
 224
 225/* for non-OTG B devices: set/clear transceiver suspend mode */
 226static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
 227{
 228        struct gpio_vbus_data *gpio_vbus;
 229
 230        gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
 231
 232        /* draw max 0 mA from vbus in suspend mode; or the previously
 233         * recorded amount of current if not suspended
 234         *
 235         * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA
 236         * if they're wake-enabled ... we don't handle that yet.
 237         */
 238        return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA);
 239}
 240
 241/* platform driver interface */
 242
 243static int gpio_vbus_probe(struct platform_device *pdev)
 244{
 245        struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
 246        struct gpio_vbus_data *gpio_vbus;
 247        struct resource *res;
 248        int err, gpio, irq;
 249        unsigned long irqflags;
 250
 251        if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
 252                return -EINVAL;
 253        gpio = pdata->gpio_vbus;
 254
 255        gpio_vbus = devm_kzalloc(&pdev->dev, sizeof(struct gpio_vbus_data),
 256                                 GFP_KERNEL);
 257        if (!gpio_vbus)
 258                return -ENOMEM;
 259
 260        gpio_vbus->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
 261                                          GFP_KERNEL);
 262        if (!gpio_vbus->phy.otg)
 263                return -ENOMEM;
 264
 265        platform_set_drvdata(pdev, gpio_vbus);
 266        gpio_vbus->dev = &pdev->dev;
 267        gpio_vbus->phy.label = "gpio-vbus";
 268        gpio_vbus->phy.dev = gpio_vbus->dev;
 269        gpio_vbus->phy.set_power = gpio_vbus_set_power;
 270        gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
 271
 272        gpio_vbus->phy.otg->state = OTG_STATE_UNDEFINED;
 273        gpio_vbus->phy.otg->usb_phy = &gpio_vbus->phy;
 274        gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral;
 275
 276        err = devm_gpio_request(&pdev->dev, gpio, "vbus_detect");
 277        if (err) {
 278                dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n",
 279                        gpio, err);
 280                return err;
 281        }
 282        gpio_direction_input(gpio);
 283
 284        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 285        if (res) {
 286                irq = res->start;
 287                irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
 288        } else {
 289                irq = gpio_to_irq(gpio);
 290                irqflags = VBUS_IRQ_FLAGS;
 291        }
 292
 293        gpio_vbus->irq = irq;
 294
 295        /* if data line pullup is in use, initialize it to "not pulling up" */
 296        gpio = pdata->gpio_pullup;
 297        if (gpio_is_valid(gpio)) {
 298                err = devm_gpio_request(&pdev->dev, gpio, "udc_pullup");
 299                if (err) {
 300                        dev_err(&pdev->dev,
 301                                "can't request pullup gpio %d, err: %d\n",
 302                                gpio, err);
 303                        return err;
 304                }
 305                gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
 306        }
 307
 308        err = devm_request_irq(&pdev->dev, irq, gpio_vbus_irq, irqflags,
 309                               "vbus_detect", pdev);
 310        if (err) {
 311                dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
 312                        irq, err);
 313                return err;
 314        }
 315
 316        INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
 317
 318        gpio_vbus->vbus_draw = devm_regulator_get(&pdev->dev, "vbus_draw");
 319        if (IS_ERR(gpio_vbus->vbus_draw)) {
 320                dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
 321                        PTR_ERR(gpio_vbus->vbus_draw));
 322                gpio_vbus->vbus_draw = NULL;
 323        }
 324
 325        /* only active when a gadget is registered */
 326        err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2);
 327        if (err) {
 328                dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 329                        err);
 330                return err;
 331        }
 332
 333        device_init_wakeup(&pdev->dev, pdata->wakeup);
 334
 335        return 0;
 336}
 337
 338static int gpio_vbus_remove(struct platform_device *pdev)
 339{
 340        struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
 341
 342        device_init_wakeup(&pdev->dev, 0);
 343        cancel_delayed_work_sync(&gpio_vbus->work);
 344
 345        usb_remove_phy(&gpio_vbus->phy);
 346
 347        return 0;
 348}
 349
 350#ifdef CONFIG_PM
 351static int gpio_vbus_pm_suspend(struct device *dev)
 352{
 353        struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
 354
 355        if (device_may_wakeup(dev))
 356                enable_irq_wake(gpio_vbus->irq);
 357
 358        return 0;
 359}
 360
 361static int gpio_vbus_pm_resume(struct device *dev)
 362{
 363        struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
 364
 365        if (device_may_wakeup(dev))
 366                disable_irq_wake(gpio_vbus->irq);
 367
 368        return 0;
 369}
 370
 371static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
 372        .suspend        = gpio_vbus_pm_suspend,
 373        .resume         = gpio_vbus_pm_resume,
 374};
 375#endif
 376
 377MODULE_ALIAS("platform:gpio-vbus");
 378
 379static struct platform_driver gpio_vbus_driver = {
 380        .driver = {
 381                .name  = "gpio-vbus",
 382#ifdef CONFIG_PM
 383                .pm = &gpio_vbus_dev_pm_ops,
 384#endif
 385        },
 386        .probe          = gpio_vbus_probe,
 387        .remove         = gpio_vbus_remove,
 388};
 389
 390module_platform_driver(gpio_vbus_driver);
 391
 392MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");
 393MODULE_AUTHOR("Philipp Zabel");
 394MODULE_LICENSE("GPL");
 395