Message ID | 20190329093334.3885-4-brgl@bgdev.pl (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | ARM: davinci: ohci-da8xx: model the vbus GPIO as a fixed regulator | expand |
pt., 29 mar 2019 o 10:33 Bartosz Golaszewski <brgl@bgdev.pl> napisaĆ(a): > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com> > > Historically the power supply management in this driver has been handled > in two separate places in parallel. Device-tree users simply defined an > appropriate regulator, while two boards with no DT support (da830-evm and > omapl138-hawk) passed functions defined in their respective board files > over platform data. These functions simply used legacy GPIO calls to > watch the oc GPIO for interrupts and disable the vbus GPIO when the irq > fires. > > Commit d193abf1c913 ("usb: ohci-da8xx: add vbus and overcurrent gpios") > updated these GPIO calls to the modern API and moved them inside the > driver. > > This however is not the optimal solution for the vbus GPIO which should > be modeled as a fixed regulator that can be controlled with a GPIO. > > In order to keep the overcurrent protection available once we move the > board files to using fixed regulators we need to disable the enable_reg > regulator when the overcurrent indicator interrupt fires. Since we > cannot call regulator_disable() from interrupt context, we need to > switch to using a oneshot threaded interrupt. > > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> > --- > drivers/usb/host/ohci-da8xx.c | 29 ++++++++++++++++++++++++----- > 1 file changed, 24 insertions(+), 5 deletions(-) > > diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c > index 9c6d1f03b871..35eb2cb96a8f 100644 > --- a/drivers/usb/host/ohci-da8xx.c > +++ b/drivers/usb/host/ohci-da8xx.c > @@ -206,8 +206,25 @@ static irqreturn_t ohci_da8xx_oc_handler(int irq, void *data) > { > struct da8xx_ohci_hcd *da8xx_ohci = data; > > - if (gpiod_get_value(da8xx_ohci->oc_gpio)) > - gpiod_set_value(da8xx_ohci->vbus_gpio, 0); > + if (gpiod_get_value(da8xx_ohci->oc_gpio)) { > + if (da8xx_ohci->vbus_gpio) > + gpiod_set_value(da8xx_ohci->vbus_gpio, 0); > + else if (da8xx_ohci->vbus_reg) > + return IRQ_WAKE_THREAD; > + } > + > + return IRQ_HANDLED; > +} > + > +static irqreturn_t ohci_da8xx_oc_thread(int irq, void *data) > +{ > + struct da8xx_ohci_hcd *da8xx_ohci = data; > + struct device *dev = da8xx_ohci->hcd->self.controller; > + int ret; > + > + ret = regulator_disable(da8xx_ohci->vbus_reg); > + if (ret) > + dev_err(dev, "Failed to disable regulator: %d\n", ret); > > return IRQ_HANDLED; > } > @@ -434,9 +451,11 @@ static int ohci_da8xx_probe(struct platform_device *pdev) > if (oc_irq < 0) > goto err; > > - error = devm_request_irq(dev, oc_irq, ohci_da8xx_oc_handler, > - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, > - "OHCI over-current indicator", da8xx_ohci); > + error = devm_request_threaded_irq(dev, oc_irq, > + ohci_da8xx_oc_handler, ohci_da8xx_oc_thread, > + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | > + IRQF_ONESHOT, "OHCI over-current indicator", > + da8xx_ohci); Ugh I noticed a problem with this patch if the module is built-in - after calling devm_request_threaded_irq() any subsequent msleep() will hang. This doesn't happen if the driver is built as a module. I'm not sure what the reason is yet. Bart > if (error) > goto err; > } > -- > 2.21.0 >
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 9c6d1f03b871..35eb2cb96a8f 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -206,8 +206,25 @@ static irqreturn_t ohci_da8xx_oc_handler(int irq, void *data) { struct da8xx_ohci_hcd *da8xx_ohci = data; - if (gpiod_get_value(da8xx_ohci->oc_gpio)) - gpiod_set_value(da8xx_ohci->vbus_gpio, 0); + if (gpiod_get_value(da8xx_ohci->oc_gpio)) { + if (da8xx_ohci->vbus_gpio) + gpiod_set_value(da8xx_ohci->vbus_gpio, 0); + else if (da8xx_ohci->vbus_reg) + return IRQ_WAKE_THREAD; + } + + return IRQ_HANDLED; +} + +static irqreturn_t ohci_da8xx_oc_thread(int irq, void *data) +{ + struct da8xx_ohci_hcd *da8xx_ohci = data; + struct device *dev = da8xx_ohci->hcd->self.controller; + int ret; + + ret = regulator_disable(da8xx_ohci->vbus_reg); + if (ret) + dev_err(dev, "Failed to disable regulator: %d\n", ret); return IRQ_HANDLED; } @@ -434,9 +451,11 @@ static int ohci_da8xx_probe(struct platform_device *pdev) if (oc_irq < 0) goto err; - error = devm_request_irq(dev, oc_irq, ohci_da8xx_oc_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "OHCI over-current indicator", da8xx_ohci); + error = devm_request_threaded_irq(dev, oc_irq, + ohci_da8xx_oc_handler, ohci_da8xx_oc_thread, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, "OHCI over-current indicator", + da8xx_ohci); if (error) goto err; }