]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
usb: ohci-da8xx: add vbus and overcurrent gpios
authorBartosz Golaszewski <bgolaszewski@baylibre.com>
Mon, 11 Feb 2019 10:36:59 +0000 (11:36 +0100)
committerSekhar Nori <nsekhar@ti.com>
Tue, 12 Feb 2019 08:18:51 +0000 (13:48 +0530)
There are two users upstream which register external callbacks for
switching the port power on/off and overcurrent protection. Both
users only use two GPIOs for that. Instead of having that functionality
in the board files, move the logic into the OHCI driver - including
the interrupt handler for overcurrent detection.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
drivers/usb/host/ohci-da8xx.c

index e8ede0b5e3f0144c1d8d9157307cdd92f457e310..ca8a94f15ac05b9eff29c3c04139cd6d8bc4d222 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/gpio/consumer.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
@@ -40,6 +41,8 @@ struct da8xx_ohci_hcd {
        struct regulator *vbus_reg;
        struct notifier_block nb;
        unsigned int reg_enabled;
+       struct gpio_desc *vbus_gpio;
+       struct gpio_desc *oc_gpio;
 };
 
 #define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
@@ -86,12 +89,13 @@ static void ohci_da8xx_disable(struct usb_hcd *hcd)
 static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
-       struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
+       struct device *dev = hcd->self.controller;
        int ret;
 
-       if (hub && hub->set_power)
-               return hub->set_power(1, on);
+       if (da8xx_ohci->vbus_gpio) {
+               gpiod_set_value_cansleep(da8xx_ohci->vbus_gpio, on);
+               return 0;
+       }
 
        if (!da8xx_ohci->vbus_reg)
                return 0;
@@ -119,11 +123,9 @@ static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on)
 static int ohci_da8xx_get_power(struct usb_hcd *hcd)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
-       struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
 
-       if (hub && hub->get_power)
-               return hub->get_power(1);
+       if (da8xx_ohci->vbus_gpio)
+               return gpiod_get_value_cansleep(da8xx_ohci->vbus_gpio);
 
        if (da8xx_ohci->vbus_reg)
                return regulator_is_enabled(da8xx_ohci->vbus_reg);
@@ -134,13 +136,11 @@ static int ohci_da8xx_get_power(struct usb_hcd *hcd)
 static int ohci_da8xx_get_oci(struct usb_hcd *hcd)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
-       struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
        unsigned int flags;
        int ret;
 
-       if (hub && hub->get_oci)
-               return hub->get_oci(1);
+       if (da8xx_ohci->oc_gpio)
+               return gpiod_get_value_cansleep(da8xx_ohci->oc_gpio);
 
        if (!da8xx_ohci->vbus_reg)
                return 0;
@@ -158,10 +158,8 @@ static int ohci_da8xx_get_oci(struct usb_hcd *hcd)
 static int ohci_da8xx_has_set_power(struct usb_hcd *hcd)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
-       struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
 
-       if (hub && hub->set_power)
+       if (da8xx_ohci->vbus_gpio)
                return 1;
 
        if (da8xx_ohci->vbus_reg)
@@ -173,10 +171,8 @@ static int ohci_da8xx_has_set_power(struct usb_hcd *hcd)
 static int ohci_da8xx_has_oci(struct usb_hcd *hcd)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
-       struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
 
-       if (hub && hub->get_oci)
+       if (da8xx_ohci->oc_gpio)
                return 1;
 
        if (da8xx_ohci->vbus_reg)
@@ -196,19 +192,6 @@ static int ohci_da8xx_has_potpgt(struct usb_hcd *hcd)
        return 0;
 }
 
-/*
- * Handle the port over-current indicator change.
- */
-static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
-                                   unsigned port)
-{
-       ocic_mask |= 1 << port;
-
-       /* Once over-current is detected, the port needs to be powered down */
-       if (hub->get_oci(port) > 0)
-               hub->set_power(port, 0);
-}
-
 static int ohci_da8xx_regulator_event(struct notifier_block *nb,
                                unsigned long event, void *data)
 {
@@ -223,16 +206,23 @@ static int ohci_da8xx_regulator_event(struct notifier_block *nb,
        return 0;
 }
 
+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);
+
+       return IRQ_HANDLED;
+}
+
 static int ohci_da8xx_register_notify(struct usb_hcd *hcd)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
        struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
        int ret = 0;
 
-       if (hub && hub->ocic_notify) {
-               ret = hub->ocic_notify(ohci_da8xx_ocic_handler);
-       } else if (da8xx_ohci->vbus_reg) {
+       if (!da8xx_ohci->oc_gpio && da8xx_ohci->vbus_reg) {
                da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event;
                ret = devm_regulator_register_notifier(da8xx_ohci->vbus_reg,
                                                &da8xx_ohci->nb);
@@ -244,15 +234,6 @@ static int ohci_da8xx_register_notify(struct usb_hcd *hcd)
        return ret;
 }
 
-static void ohci_da8xx_unregister_notify(struct usb_hcd *hcd)
-{
-       struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
-
-       if (hub && hub->ocic_notify)
-               hub->ocic_notify(NULL);
-}
-
 static int ohci_da8xx_reset(struct usb_hcd *hcd)
 {
        struct device *dev              = hcd->self.controller;
@@ -403,9 +384,9 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
 {
        struct da8xx_ohci_hcd *da8xx_ohci;
        struct device *dev = &pdev->dev;
+       int error, hcd_irq, oc_irq;
        struct usb_hcd  *hcd;
        struct resource *mem;
-       int error, irq;
 
        hcd = usb_create_hcd(&ohci_da8xx_hc_driver, dev, dev_name(dev));
        if (!hcd)
@@ -443,6 +424,27 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
                }
        }
 
+       da8xx_ohci->vbus_gpio = devm_gpiod_get_optional(dev, "vbus",
+                                                       GPIOD_OUT_HIGH);
+       if (IS_ERR(da8xx_ohci->vbus_gpio))
+               goto err;
+
+       da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN);
+       if (IS_ERR(da8xx_ohci->oc_gpio))
+               goto err;
+
+       if (da8xx_ohci->oc_gpio) {
+               oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio);
+               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);
+               if (error)
+                       goto err;
+       }
+
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        hcd->regs = devm_ioremap_resource(dev, mem);
        if (IS_ERR(hcd->regs)) {
@@ -452,13 +454,13 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
        hcd->rsrc_start = mem->start;
        hcd->rsrc_len = resource_size(mem);
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
+       hcd_irq = platform_get_irq(pdev, 0);
+       if (hcd_irq < 0) {
                error = -ENODEV;
                goto err;
        }
 
-       error = usb_add_hcd(hcd, irq, 0);
+       error = usb_add_hcd(hcd, hcd_irq, 0);
        if (error)
                goto err;
 
@@ -481,7 +483,6 @@ static int ohci_da8xx_remove(struct platform_device *pdev)
 {
        struct usb_hcd  *hcd = platform_get_drvdata(pdev);
 
-       ohci_da8xx_unregister_notify(hcd);
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);