USB: ehci-tegra: add probing through device tree
authorOlof Johansson <olof@lixom.net>
Fri, 4 Nov 2011 09:12:40 +0000 (09:12 +0000)
committerOlof Johansson <olof@lixom.net>
Thu, 8 Dec 2011 04:47:48 +0000 (20:47 -0800)
Rely on platform_data being passed through auxdata for now; more elaborate
bindings for phy config and tunings to be added.

v2: moved vbus-gpio check to the helper function, added check for !of_node,
    added usb2 clock to board-dt table.

Signed-off-by: Olof Johansson <olof@lixom.net>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
arch/arm/mach-tegra/board-dt.c
drivers/usb/host/ehci-tegra.c

index 74743ad3d2d356b90908529dfa57b15ccd168dd5..7f287a86941ef85ac04a23d79be1b07b2ac0fea7 100644 (file)
@@ -61,12 +61,21 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
        OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL),
        OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
+                      &tegra_ehci1_device.dev.platform_data),
+       OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
+                      &tegra_ehci2_device.dev.platform_data),
+       OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
+                      &tegra_ehci3_device.dev.platform_data),
        {}
 };
 
 static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
        /* name         parent          rate            enabled */
        { "uartd",      "pll_p",        216000000,      true },
+       { "usbd",       "clk_m",        12000000,       false },
+       { "usb2",       "clk_m",        12000000,       false },
+       { "usb3",       "clk_m",        12000000,       false },
        { NULL,         NULL,           0,              0},
 };
 
index db9d1b4bfbdc4eda2e4243cc43e31c4ed498adf5..dbc7fe8ca9e7d692dc750d58e49e3bbcc13b6140 100644 (file)
 #include <linux/platform_data/tegra_usb.h>
 #include <linux/irq.h>
 #include <linux/usb/otg.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
 #include <mach/usb_phy.h>
+#include <mach/iomap.h>
 
 #define TEGRA_USB_DMA_ALIGN 32
 
@@ -574,6 +579,35 @@ static const struct hc_driver tegra_ehci_hc_driver = {
        .port_handed_over       = ehci_port_handed_over,
 };
 
+static int setup_vbus_gpio(struct platform_device *pdev)
+{
+       int err = 0;
+       int gpio;
+
+       if (!pdev->dev.of_node)
+               return 0;
+
+       gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,vbus-gpio", 0);
+       if (!gpio_is_valid(gpio))
+               return 0;
+
+       err = gpio_request(gpio, "vbus_gpio");
+       if (err) {
+               dev_err(&pdev->dev, "can't request vbus gpio %d", gpio);
+               return err;
+       }
+       err = gpio_direction_output(gpio, 1);
+       if (err) {
+               dev_err(&pdev->dev, "can't enable vbus\n");
+               return err;
+       }
+       gpio_set_value(gpio, 1);
+
+       return err;
+}
+
+static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32);
+
 static int tegra_ehci_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -590,6 +624,15 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       /* Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &tegra_ehci_dma_mask;
+
+       setup_vbus_gpio(pdev);
+
        tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
        if (!tegra)
                return -ENOMEM;
@@ -640,6 +683,28 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                goto fail_io;
        }
 
+       /* This is pretty ugly and needs to be fixed when we do only
+        * device-tree probing. Old code relies on the platform_device
+        * numbering that we lack for device-tree-instantiated devices.
+        */
+       if (instance < 0) {
+               switch (res->start) {
+               case TEGRA_USB_BASE:
+                       instance = 0;
+                       break;
+               case TEGRA_USB2_BASE:
+                       instance = 1;
+                       break;
+               case TEGRA_USB3_BASE:
+                       instance = 2;
+                       break;
+               default:
+                       err = -ENODEV;
+                       dev_err(&pdev->dev, "unknown usb instance\n");
+                       goto fail_phy;
+               }
+       }
+
        tegra->phy = tegra_usb_phy_open(instance, hcd->regs, pdata->phy_config,
                                                TEGRA_USB_PHY_MODE_HOST);
        if (IS_ERR(tegra->phy)) {
@@ -773,6 +838,11 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev)
                hcd->driver->shutdown(hcd);
 }
 
+static struct of_device_id tegra_ehci_of_match[] __devinitdata = {
+       { .compatible = "nvidia,tegra20-ehci", },
+       { },
+};
+
 static struct platform_driver tegra_ehci_driver = {
        .probe          = tegra_ehci_probe,
        .remove         = tegra_ehci_remove,
@@ -783,5 +853,6 @@ static struct platform_driver tegra_ehci_driver = {
        .shutdown       = tegra_ehci_hcd_shutdown,
        .driver         = {
                .name   = "tegra-ehci",
+               .of_match_table = tegra_ehci_of_match,
        }
 };