misc: tegra-baseband: enable DT EHCI load/unload
BH Hsieh [Tue, 15 Sep 2015 12:20:31 +0000 (20:20 +0800)]
Enable dynamic load/unload EHCI from device tree on T210.

Now EHCI load/unload is directly through of_* API through DT.

Bug 200027573

Change-Id: I6c9c0c3d4162bc7229d3f2fca975ada7c8105f61
Signed-off-by: BH Hsieh <bhsieh@nvidia.com>
Reviewed-on: http://git-master/r/453975
(cherry picked from commit b04a1451c98cba4acaaa18d2974a3917a6252027)
Reviewed-on: http://git-master/r/807763
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Frederic Bossy <fbossy@nvidia.com>
Tested-by: Frederic Bossy <fbossy@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Steve Rogers <srogers@nvidia.com>

arch/arm64/boot/dts/tegra210-platforms/tegra210-modem-common.dtsi
drivers/misc/tegra-baseband/tegra_usb_modem_power.c
include/linux/platform_data/tegra_usb_modem_power.h

index 163708b..7dee4f3 100644 (file)
@@ -28,6 +28,7 @@
                nvidia,reset-gpio = <&gpio TEGRA_GPIO(L, 0) GPIO_ACTIVE_LOW>;
                nvidia,mdm-en-gpio = <&gpio TEGRA_GPIO(K, 7) GPIO_ACTIVE_HIGH>;
                nvidia,num-temp-sensors = <3>;
+               nvidia,ehci-device = <&ehci2>;
 
                /* modem interface child nodes */
                nvidia,phy-ehci-hsic {
index f516975..80106ef 100644 (file)
@@ -36,9 +36,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/sysedp.h>
 #include <linux/platform_data/tegra_usb_modem_power.h>
-#include <linux/dma-mapping.h>
 #include <linux/delay.h>
-#include "../../../arch/arm/mach-tegra/iomap.h"
 #include <linux/fs.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/platform_data/sysedp_modem.h>
 #include <linux/system-wakeup.h>
 
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+#include <linux/of_platform.h>
+#else
+#include <linux/dma-mapping.h>
+#include "../../../arch/arm/mach-tegra/iomap.h"
+#endif
+
 #define BOOST_CPU_FREQ_MIN     1200000
 #define BOOST_CPU_FREQ_TIMEOUT 5000
 
@@ -85,6 +90,7 @@ static int hsic_power(bool on)
        return 0;
 }
 
+#ifndef CONFIG_ARCH_TEGRA_21x_SOC
 static u64 tegra_ehci_dmamask = DMA_BIT_MASK(64);
 
 static struct resource tegra_usb2_resources[] = {
@@ -124,6 +130,7 @@ static struct tegra_usb_platform_data tegra_ehci2_hsic_baseband_pdata = {
                .skip_resume = true,
        },
 };
+#endif
 
 struct tegra_usb_modem {
        struct tegra_usb_modem_power_platform_data *pdata;
@@ -527,6 +534,36 @@ static struct platform_device *tegra_usb_host_register(
        struct platform_device *pdev;
        int val;
 
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+       struct property *status_prop;
+
+       /* we're registering EHCI through DT here */
+
+       /* If ehci node is unavailable, we're unable to register it later.
+        * So make it available by setting status to "okay" */
+       if (!of_device_is_available(modem->pdata->ehci_node)) {
+               pr_info("%s(): enable ehci node\n", __func__);
+               status_prop = of_find_property(modem->pdata->ehci_node,
+                                               "status", NULL);
+               if (!status_prop) {
+                       pr_err("%s(): error getting status in ehci node\n",
+                               __func__);
+                       return NULL;
+               }
+               strcpy((char *)status_prop->value, "okay");
+       }
+
+       /* we have to hard-code EHCI device name here for now */
+       pdev = of_platform_device_create(modem->pdata->ehci_node,
+                                       "tegra-ehci.1", NULL);
+       if (!pdev) {
+               pr_info("%s: error registering EHCI\n", __func__);
+               return NULL;
+       }
+
+       return pdev;
+#endif
+
        pdev = platform_device_alloc(hc_device->name, hc_device->id);
        if (!pdev)
                return NULL;
@@ -557,9 +594,13 @@ error:
 }
 
 /* unload USB host controller */
-static void tegra_usb_host_unregister(struct platform_device *pdev)
+static void tegra_usb_host_unregister(const struct tegra_usb_modem *modem)
 {
-       platform_device_unregister(pdev);
+       struct platform_device *pdev = modem->hc;
+       if (unlikely(modem->pdata->tegra_ehci_device))
+               platform_device_unregister(pdev);
+       else
+               of_device_unregister(pdev);
 }
 
 static ssize_t show_usb_host(struct device *dev,
@@ -612,7 +653,7 @@ static ssize_t load_unload_usb_host(struct device *dev,
                if (host && !modem->hc) {
                        modem->hc = tegra_usb_host_register(modem);
                } else if (!host && modem->hc) {
-                       tegra_usb_host_unregister(modem->hc);
+                       tegra_usb_host_unregister(modem);
                        modem->hc = NULL;
                }
                break;
@@ -743,9 +784,11 @@ static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
        modem->pdata = pdata;
        modem->pdev = pdev;
 
+#ifndef CONFIG_ARCH_TEGRA_21x_SOC
        /* WAR to load statically defined ehci device/pdata */
        pdata->tegra_ehci_device = &tegra_ehci2_device;
        pdata->tegra_ehci_pdata = &tegra_ehci2_hsic_baseband_pdata;
+#endif
 
        pdata->autosuspend_delay = DEFAULT_AUTOSUSPEND;
 
@@ -885,6 +928,9 @@ static int tegra_usb_modem_parse_dt(struct tegra_usb_modem *modem,
        int gpio;
        int ret;
        const char *node_status;
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+       struct device_node *ehci_node = NULL;
+#endif
 
        if (!node) {
                dev_err(&pdev->dev, "Missing device tree node\n");
@@ -978,6 +1024,19 @@ static int tegra_usb_modem_parse_dt(struct tegra_usb_modem *modem,
                goto error;
        }
 
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+       /* get EHCI device/pdata handle */
+       if (modem->phy_type == EHCI_HSIC) {
+               ehci_node = of_parse_phandle(node, "nvidia,ehci-device", 0);
+               if (!ehci_node) {
+                       dev_err(&pdev->dev, "can't find nvidia,ehci-device\n");
+                       return -EINVAL;
+               }
+               /* set ehci device/pdata */
+               pdata.ehci_node = ehci_node;
+       }
+#endif
+
        prop = of_get_property(node, "nvidia,num-temp-sensors", NULL);
        if (prop)
                pdata.num_temp_sensors = be32_to_cpup(prop);
index 47720c4..04395a8 100644 (file)
@@ -50,6 +50,9 @@ struct tegra_usb_modem_power_platform_data {
        int autosuspend_delay;          /* autosuspend delay in milliseconds */
        const struct platform_device *tegra_ehci_device; /* USB host device */
        struct tegra_usb_platform_data *tegra_ehci_pdata;
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+       struct device_node *ehci_node;  /* EHCI device tree node */
+#endif
        int mdm_power_report_gpio;      /* modem power increase report gpio */
        unsigned long mdm_power_irq_flags; /* modem boot irq flags */
        unsigned int num_temp_sensors; /* num of temps modem reports */