Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc3 / dwc3-pci.c
index d2c0c1a8d979bf007e730e8e1354d1ff740b6d80..5f40ea2b8aa9e8c8f6c2295795c8635b2a88d762 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/acpi.h>
-
-#include "platform_data.h"
+#include <linux/delay.h>
 
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3                0xabcd
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI    0xabce
@@ -35,6 +35,7 @@
 #define PCI_DEVICE_ID_INTEL_SPTLP              0x9d30
 #define PCI_DEVICE_ID_INTEL_SPTH               0xa130
 #define PCI_DEVICE_ID_INTEL_BXT                        0x0aaa
+#define PCI_DEVICE_ID_INTEL_BXT_M              0x1aaa
 #define PCI_DEVICE_ID_INTEL_APL                        0x5aaa
 #define PCI_DEVICE_ID_INTEL_KBP                        0xa2b0
 #define PCI_DEVICE_ID_INTEL_GLK                        0x31aa
@@ -48,67 +49,74 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
        { },
 };
 
-static int dwc3_pci_quirks(struct pci_dev *pdev)
+static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
 {
        if (pdev->vendor == PCI_VENDOR_ID_AMD &&
            pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
-               struct dwc3_platform_data pdata;
-
-               memset(&pdata, 0, sizeof(pdata));
-
-               pdata.has_lpm_erratum = true;
-               pdata.lpm_nyet_threshold = 0xf;
-
-               pdata.u2exit_lfps_quirk = true;
-               pdata.u2ss_inp3_quirk = true;
-               pdata.req_p1p2p3_quirk = true;
-               pdata.del_p1p2p3_quirk = true;
-               pdata.del_phy_power_chg_quirk = true;
-               pdata.lfps_filter_quirk = true;
-               pdata.rx_detect_poll_quirk = true;
-
-               pdata.tx_de_emphasis_quirk = true;
-               pdata.tx_de_emphasis = 1;
-
-               /*
-                * FIXME these quirks should be removed when AMD NL
-                * taps out
-                */
-               pdata.disable_scramble_quirk = true;
-               pdata.dis_u3_susphy_quirk = true;
-               pdata.dis_u2_susphy_quirk = true;
-
-               return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
-                                               sizeof(pdata));
+               struct property_entry properties[] = {
+                       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+                       PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
+                       PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
+                       PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
+                       /*
+                        * FIXME these quirks should be removed when AMD NL
+                        * tapes out
+                        */
+                       PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+                       { },
+               };
+
+               return platform_device_add_properties(dwc3, properties);
        }
 
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
-           pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
-               struct gpio_desc *gpio;
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+               int ret;
+
+               struct property_entry properties[] = {
+                       PROPERTY_ENTRY_STRING("dr-mode", "peripheral"),
+                       { }
+               };
 
-               acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
-                                         acpi_dwc3_byt_gpios);
+               ret = platform_device_add_properties(dwc3, properties);
+               if (ret < 0)
+                       return ret;
 
-               /*
-                * These GPIOs will turn on the USB2 PHY. Note that we have to
-                * put the gpio descriptors again here because the phy driver
-                * might want to grab them, too.
-                */
-               gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
-               if (IS_ERR(gpio))
-                       return PTR_ERR(gpio);
+               if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
+                       struct gpio_desc *gpio;
 
-               gpiod_set_value_cansleep(gpio, 1);
-               gpiod_put(gpio);
+                       acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
+                                       acpi_dwc3_byt_gpios);
 
-               gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
-               if (IS_ERR(gpio))
-                       return PTR_ERR(gpio);
+                       /*
+                        * These GPIOs will turn on the USB2 PHY. Note that we have to
+                        * put the gpio descriptors again here because the phy driver
+                        * might want to grab them, too.
+                        */
+                       gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
+                       if (IS_ERR(gpio))
+                               return PTR_ERR(gpio);
 
-               if (gpio) {
                        gpiod_set_value_cansleep(gpio, 1);
                        gpiod_put(gpio);
-                       usleep_range(10000, 11000);
+
+                       gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+                       if (IS_ERR(gpio))
+                               return PTR_ERR(gpio);
+
+                       if (gpio) {
+                               gpiod_set_value_cansleep(gpio, 1);
+                               gpiod_put(gpio);
+                               usleep_range(10000, 11000);
+                       }
                }
        }
 
@@ -116,16 +124,14 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
            (pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
             pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
             pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
-
-               struct dwc3_platform_data pdata;
-
-               memset(&pdata, 0, sizeof(pdata));
-               pdata.usb3_lpm_capable = true;
-               pdata.has_lpm_erratum = true;
-               pdata.dis_enblslpm_quirk = true;
-
-               return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
-                                               sizeof(pdata));
+               struct property_entry properties[] = {
+                       PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
+                       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+                       PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
+                       { },
+               };
+
+               return platform_device_add_properties(dwc3, properties);
        }
 
        return 0;
@@ -170,20 +176,24 @@ static int dwc3_pci_probe(struct pci_dev *pci,
                return ret;
        }
 
-       pci_set_drvdata(pci, dwc3);
-       ret = dwc3_pci_quirks(pci);
-       if (ret)
-               goto err;
-
        dwc3->dev.parent = dev;
        ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
 
+       ret = dwc3_pci_quirks(pci, dwc3);
+       if (ret)
+               goto err;
+
        ret = platform_device_add(dwc3);
        if (ret) {
                dev_err(dev, "failed to register dwc3 device\n");
                goto err;
        }
 
+       device_init_wakeup(dev, true);
+       device_set_run_wake(dev, true);
+       pci_set_drvdata(pci, dwc3);
+       pm_runtime_put(dev);
+
        return 0;
 err:
        platform_device_put(dwc3);
@@ -192,6 +202,8 @@ err:
 
 static void dwc3_pci_remove(struct pci_dev *pci)
 {
+       device_init_wakeup(&pci->dev, false);
+       pm_runtime_get(&pci->dev);
        acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev));
        platform_device_unregister(pci_get_drvdata(pci));
 }
@@ -215,6 +227,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
@@ -223,11 +236,43 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
+#ifdef CONFIG_PM
+static int dwc3_pci_runtime_suspend(struct device *dev)
+{
+       if (device_run_wake(dev))
+               return 0;
+
+       return -EBUSY;
+}
+
+static int dwc3_pci_pm_dummy(struct device *dev)
+{
+       /*
+        * There's nothing to do here. No, seriously. Everything is either taken
+        * care either by PCI subsystem or dwc3/core.c, so we have nothing
+        * missing here.
+        *
+        * So you'd think we didn't need this at all, but PCI subsystem will
+        * bail out if we don't have a valid callback :-s
+        */
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct dev_pm_ops dwc3_pci_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_pm_dummy, dwc3_pci_pm_dummy)
+       SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_pm_dummy,
+               NULL)
+};
+
 static struct pci_driver dwc3_pci_driver = {
        .name           = "dwc3-pci",
        .id_table       = dwc3_pci_id_table,
        .probe          = dwc3_pci_probe,
        .remove         = dwc3_pci_remove,
+       .driver         = {
+               .pm     = &dwc3_pci_dev_pm_ops,
+       }
 };
 
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");