usb: gadget: pch_udc: Provide a GPIO line used on Intel Minnowboard (v1)
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Tue, 23 Mar 2021 15:36:26 +0000 (17:36 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 Mar 2021 15:53:30 +0000 (16:53 +0100)
Intel Minnowboard (v1) uses SCH GPIO line SUS7 (i.e. 12)
for VBUS sense. Provide a DMI based quirk to have it's being used.

Fixes: e20849a8c883 ("usb: gadget: pch_udc: Convert to use GPIO descriptors")
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20210323153626.54908-7-andriy.shevchenko@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/pch_udc.c

index 07199fd..070f43f 100644 (file)
@@ -7,12 +7,14 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/dmi.h>
 #include <linux/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/gpio/consumer.h>
 #include <linux/irq.h>
 
 #define PCH_VBUS_PERIOD                3000    /* VBUS polling period (msec) */
@@ -1360,6 +1362,43 @@ static irqreturn_t pch_vbus_gpio_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static struct gpiod_lookup_table minnowboard_udc_gpios = {
+       .dev_id         = "0000:02:02.4",
+       .table          = {
+               GPIO_LOOKUP("sch_gpio.33158", 12, NULL, GPIO_ACTIVE_HIGH),
+               {}
+       },
+};
+
+static const struct dmi_system_id pch_udc_gpio_dmi_table[] = {
+       {
+               .ident = "MinnowBoard",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "MinnowBoard"),
+               },
+               .driver_data = &minnowboard_udc_gpios,
+       },
+       { }
+};
+
+static void pch_vbus_gpio_remove_table(void *table)
+{
+       gpiod_remove_lookup_table(table);
+}
+
+static int pch_vbus_gpio_add_table(struct pch_udc_dev *dev)
+{
+       struct device *d = &dev->pdev->dev;
+       const struct dmi_system_id *dmi;
+
+       dmi = dmi_first_match(pch_udc_gpio_dmi_table);
+       if (!dmi)
+               return 0;
+
+       gpiod_add_lookup_table(dmi->driver_data);
+       return devm_add_action_or_reset(d, pch_vbus_gpio_remove_table, dmi->driver_data);
+}
+
 /**
  * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
  * @dev:               Reference to the driver structure
@@ -1378,8 +1417,12 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev)
        dev->vbus_gpio.port = NULL;
        dev->vbus_gpio.intr = 0;
 
+       err = pch_vbus_gpio_add_table(dev);
+       if (err)
+               return err;
+
        /* Retrieve the GPIO line from the USB gadget device */
-       gpiod = devm_gpiod_get(d, NULL, GPIOD_IN);
+       gpiod = devm_gpiod_get_optional(d, NULL, GPIOD_IN);
        if (IS_ERR(gpiod))
                return PTR_ERR(gpiod);
        gpiod_set_consumer_name(gpiod, "pch_vbus");
@@ -2889,14 +2932,20 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
  * @dev:       Reference to the driver structure
  *
  * Return codes:
- *     0: Success
+ *     0:              Success
+ *     -%ERRNO:        All kind of errors when retrieving VBUS GPIO
  */
 static int pch_udc_pcd_init(struct pch_udc_dev *dev)
 {
+       int ret;
+
        pch_udc_init(dev);
        pch_udc_pcd_reinit(dev);
-       pch_vbus_gpio_init(dev);
-       return 0;
+
+       ret = pch_vbus_gpio_init(dev);
+       if (ret)
+               pch_udc_exit(dev);
+       return ret;
 }
 
 /**
@@ -3098,16 +3147,10 @@ static int pch_udc_probe(struct pci_dev *pdev,
 
        dev->base_addr = pcim_iomap_table(pdev)[bar];
 
-       /*
-        * FIXME: add a GPIO descriptor table to pdev.dev using
-        * gpiod_add_descriptor_table() from <linux/gpio/machine.h> based on
-        * the PCI subsystem ID. The system-dependent GPIO is necessary for
-        * VBUS operation.
-        */
-
        /* initialize the hardware */
-       if (pch_udc_pcd_init(dev))
-               return -ENODEV;
+       retval = pch_udc_pcd_init(dev);
+       if (retval)
+               return retval;
 
        pci_enable_msi(pdev);