diff options
Diffstat (limited to 'drivers/usb/host')
| -rw-r--r-- | drivers/usb/host/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 5 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-tegra.c | 20 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-tilegx.c | 214 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 5 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-omap.c | 7 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-tilegx.c | 203 |
7 files changed, 442 insertions, 14 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 18ba33da34ec..075d2eca8108 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
| @@ -308,7 +308,7 @@ config USB_OHCI_HCD | |||
| 308 | 308 | ||
| 309 | config USB_OHCI_HCD_OMAP1 | 309 | config USB_OHCI_HCD_OMAP1 |
| 310 | bool "OHCI support for OMAP1/2 chips" | 310 | bool "OHCI support for OMAP1/2 chips" |
| 311 | depends on USB_OHCI_HCD && (ARCH_OMAP1 || ARCH_OMAP2) | 311 | depends on USB_OHCI_HCD && ARCH_OMAP1 |
| 312 | default y | 312 | default y |
| 313 | ---help--- | 313 | ---help--- |
| 314 | Enables support for the OHCI controller on OMAP1/2 chips. | 314 | Enables support for the OHCI controller on OMAP1/2 chips. |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e44ca5453aa2..b05c6865b610 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
| @@ -1289,6 +1289,11 @@ MODULE_LICENSE ("GPL"); | |||
| 1289 | #define PLATFORM_DRIVER ehci_msm_driver | 1289 | #define PLATFORM_DRIVER ehci_msm_driver |
| 1290 | #endif | 1290 | #endif |
| 1291 | 1291 | ||
| 1292 | #ifdef CONFIG_TILE_USB | ||
| 1293 | #include "ehci-tilegx.c" | ||
| 1294 | #define PLATFORM_DRIVER ehci_hcd_tilegx_driver | ||
| 1295 | #endif | ||
| 1296 | |||
| 1292 | #ifdef CONFIG_USB_EHCI_HCD_PMC_MSP | 1297 | #ifdef CONFIG_USB_EHCI_HCD_PMC_MSP |
| 1293 | #include "ehci-pmcmsp.c" | 1298 | #include "ehci-pmcmsp.c" |
| 1294 | #define PLATFORM_DRIVER ehci_hcd_msp_driver | 1299 | #define PLATFORM_DRIVER ehci_hcd_msp_driver |
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 562c80e2bfe0..950e95efa381 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c | |||
| @@ -47,8 +47,8 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) | |||
| 47 | { | 47 | { |
| 48 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); | 48 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); |
| 49 | 49 | ||
| 50 | clk_enable(tegra->emc_clk); | 50 | clk_prepare_enable(tegra->emc_clk); |
| 51 | clk_enable(tegra->clk); | 51 | clk_prepare_enable(tegra->clk); |
| 52 | tegra_usb_phy_power_on(tegra->phy); | 52 | tegra_usb_phy_power_on(tegra->phy); |
| 53 | tegra->host_resumed = 1; | 53 | tegra->host_resumed = 1; |
| 54 | } | 54 | } |
| @@ -59,8 +59,8 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) | |||
| 59 | 59 | ||
| 60 | tegra->host_resumed = 0; | 60 | tegra->host_resumed = 0; |
| 61 | tegra_usb_phy_power_off(tegra->phy); | 61 | tegra_usb_phy_power_off(tegra->phy); |
| 62 | clk_disable(tegra->clk); | 62 | clk_disable_unprepare(tegra->clk); |
| 63 | clk_disable(tegra->emc_clk); | 63 | clk_disable_unprepare(tegra->emc_clk); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static int tegra_ehci_internal_port_reset( | 66 | static int tegra_ehci_internal_port_reset( |
| @@ -655,7 +655,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 655 | goto fail_clk; | 655 | goto fail_clk; |
| 656 | } | 656 | } |
| 657 | 657 | ||
| 658 | err = clk_enable(tegra->clk); | 658 | err = clk_prepare_enable(tegra->clk); |
| 659 | if (err) | 659 | if (err) |
| 660 | goto fail_clken; | 660 | goto fail_clken; |
| 661 | 661 | ||
| @@ -666,7 +666,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 666 | goto fail_emc_clk; | 666 | goto fail_emc_clk; |
| 667 | } | 667 | } |
| 668 | 668 | ||
| 669 | clk_enable(tegra->emc_clk); | 669 | clk_prepare_enable(tegra->emc_clk); |
| 670 | clk_set_rate(tegra->emc_clk, 400000000); | 670 | clk_set_rate(tegra->emc_clk, 400000000); |
| 671 | 671 | ||
| 672 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 672 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| @@ -766,10 +766,10 @@ fail: | |||
| 766 | fail_phy: | 766 | fail_phy: |
| 767 | iounmap(hcd->regs); | 767 | iounmap(hcd->regs); |
| 768 | fail_io: | 768 | fail_io: |
| 769 | clk_disable(tegra->emc_clk); | 769 | clk_disable_unprepare(tegra->emc_clk); |
| 770 | clk_put(tegra->emc_clk); | 770 | clk_put(tegra->emc_clk); |
| 771 | fail_emc_clk: | 771 | fail_emc_clk: |
| 772 | clk_disable(tegra->clk); | 772 | clk_disable_unprepare(tegra->clk); |
| 773 | fail_clken: | 773 | fail_clken: |
| 774 | clk_put(tegra->clk); | 774 | clk_put(tegra->clk); |
| 775 | fail_clk: | 775 | fail_clk: |
| @@ -804,10 +804,10 @@ static int tegra_ehci_remove(struct platform_device *pdev) | |||
| 804 | tegra_usb_phy_close(tegra->phy); | 804 | tegra_usb_phy_close(tegra->phy); |
| 805 | iounmap(hcd->regs); | 805 | iounmap(hcd->regs); |
| 806 | 806 | ||
| 807 | clk_disable(tegra->clk); | 807 | clk_disable_unprepare(tegra->clk); |
| 808 | clk_put(tegra->clk); | 808 | clk_put(tegra->clk); |
| 809 | 809 | ||
| 810 | clk_disable(tegra->emc_clk); | 810 | clk_disable_unprepare(tegra->emc_clk); |
| 811 | clk_put(tegra->emc_clk); | 811 | clk_put(tegra->emc_clk); |
| 812 | 812 | ||
| 813 | kfree(tegra); | 813 | kfree(tegra); |
diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c new file mode 100644 index 000000000000..1d215cdb9dea --- /dev/null +++ b/drivers/usb/host/ehci-tilegx.c | |||
| @@ -0,0 +1,214 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation, version 2. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, but | ||
| 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Tilera TILE-Gx USB EHCI host controller driver. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/irq.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/usb/tilegx.h> | ||
| 22 | #include <linux/usb.h> | ||
| 23 | |||
| 24 | #include <asm/homecache.h> | ||
| 25 | |||
| 26 | #include <gxio/iorpc_usb_host.h> | ||
| 27 | #include <gxio/usb_host.h> | ||
| 28 | |||
| 29 | static void tilegx_start_ehc(void) | ||
| 30 | { | ||
| 31 | } | ||
| 32 | |||
| 33 | static void tilegx_stop_ehc(void) | ||
| 34 | { | ||
| 35 | } | ||
| 36 | |||
| 37 | static int tilegx_ehci_setup(struct usb_hcd *hcd) | ||
| 38 | { | ||
| 39 | int ret = ehci_init(hcd); | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Some drivers do: | ||
| 43 | * | ||
| 44 | * struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
| 45 | * ehci->need_io_watchdog = 0; | ||
| 46 | * | ||
| 47 | * here, but since this is a new driver we're going to leave the | ||
| 48 | * watchdog enabled. Later we may try to turn it off and see | ||
| 49 | * whether we run into any problems. | ||
| 50 | */ | ||
| 51 | |||
| 52 | return ret; | ||
| 53 | } | ||
| 54 | |||
| 55 | static const struct hc_driver ehci_tilegx_hc_driver = { | ||
| 56 | .description = hcd_name, | ||
| 57 | .product_desc = "Tile-Gx EHCI", | ||
| 58 | .hcd_priv_size = sizeof(struct ehci_hcd), | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Generic hardware linkage. | ||
| 62 | */ | ||
| 63 | .irq = ehci_irq, | ||
| 64 | .flags = HCD_MEMORY | HCD_USB2, | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Basic lifecycle operations. | ||
| 68 | */ | ||
| 69 | .reset = tilegx_ehci_setup, | ||
| 70 | .start = ehci_run, | ||
| 71 | .stop = ehci_stop, | ||
| 72 | .shutdown = ehci_shutdown, | ||
| 73 | |||
| 74 | /* | ||
| 75 | * Managing I/O requests and associated device resources. | ||
| 76 | */ | ||
| 77 | .urb_enqueue = ehci_urb_enqueue, | ||
| 78 | .urb_dequeue = ehci_urb_dequeue, | ||
| 79 | .endpoint_disable = ehci_endpoint_disable, | ||
| 80 | .endpoint_reset = ehci_endpoint_reset, | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Scheduling support. | ||
| 84 | */ | ||
| 85 | .get_frame_number = ehci_get_frame, | ||
| 86 | |||
| 87 | /* | ||
| 88 | * Root hub support. | ||
| 89 | */ | ||
| 90 | .hub_status_data = ehci_hub_status_data, | ||
| 91 | .hub_control = ehci_hub_control, | ||
| 92 | .bus_suspend = ehci_bus_suspend, | ||
| 93 | .bus_resume = ehci_bus_resume, | ||
| 94 | .relinquish_port = ehci_relinquish_port, | ||
| 95 | .port_handed_over = ehci_port_handed_over, | ||
| 96 | |||
| 97 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) | ||
| 101 | { | ||
| 102 | struct usb_hcd *hcd; | ||
| 103 | struct ehci_hcd *ehci; | ||
| 104 | struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; | ||
| 105 | pte_t pte = { 0 }; | ||
| 106 | int my_cpu = smp_processor_id(); | ||
| 107 | int ret; | ||
| 108 | |||
| 109 | if (usb_disabled()) | ||
| 110 | return -ENODEV; | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Try to initialize our GXIO context; if we can't, the device | ||
| 114 | * doesn't exist. | ||
| 115 | */ | ||
| 116 | if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 1) != 0) | ||
| 117 | return -ENXIO; | ||
| 118 | |||
| 119 | hcd = usb_create_hcd(&ehci_tilegx_hc_driver, &pdev->dev, | ||
| 120 | dev_name(&pdev->dev)); | ||
| 121 | if (!hcd) | ||
| 122 | return -ENOMEM; | ||
| 123 | |||
| 124 | /* | ||
| 125 | * We don't use rsrc_start to map in our registers, but seems like | ||
| 126 | * we ought to set it to something, so we use the register VA. | ||
| 127 | */ | ||
| 128 | hcd->rsrc_start = | ||
| 129 | (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx); | ||
| 130 | hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx); | ||
| 131 | hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx); | ||
| 132 | |||
| 133 | tilegx_start_ehc(); | ||
| 134 | |||
| 135 | ehci = hcd_to_ehci(hcd); | ||
| 136 | ehci->caps = hcd->regs; | ||
| 137 | ehci->regs = | ||
| 138 | hcd->regs + HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); | ||
| 139 | /* cache this readonly data; minimize chip reads */ | ||
| 140 | ehci->hcs_params = readl(&ehci->caps->hcs_params); | ||
| 141 | |||
| 142 | /* Create our IRQs and register them. */ | ||
| 143 | pdata->irq = create_irq(); | ||
| 144 | if (pdata->irq < 0) { | ||
| 145 | ret = -ENXIO; | ||
| 146 | goto err_no_irq; | ||
| 147 | } | ||
| 148 | |||
| 149 | tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU); | ||
| 150 | |||
| 151 | /* Configure interrupts. */ | ||
| 152 | ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx, | ||
| 153 | cpu_x(my_cpu), cpu_y(my_cpu), | ||
| 154 | KERNEL_PL, pdata->irq); | ||
| 155 | if (ret) { | ||
| 156 | ret = -ENXIO; | ||
| 157 | goto err_have_irq; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* Register all of our memory. */ | ||
| 161 | pte = pte_set_home(pte, PAGE_HOME_HASH); | ||
| 162 | ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0); | ||
| 163 | if (ret) { | ||
| 164 | ret = -ENXIO; | ||
| 165 | goto err_have_irq; | ||
| 166 | } | ||
| 167 | |||
| 168 | ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); | ||
| 169 | if (ret == 0) { | ||
| 170 | platform_set_drvdata(pdev, hcd); | ||
| 171 | return ret; | ||
| 172 | } | ||
| 173 | |||
| 174 | err_have_irq: | ||
| 175 | destroy_irq(pdata->irq); | ||
| 176 | err_no_irq: | ||
| 177 | tilegx_stop_ehc(); | ||
| 178 | usb_put_hcd(hcd); | ||
| 179 | gxio_usb_host_destroy(&pdata->usb_ctx); | ||
| 180 | return ret; | ||
| 181 | } | ||
| 182 | |||
| 183 | static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) | ||
| 184 | { | ||
| 185 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
| 186 | struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; | ||
| 187 | |||
| 188 | usb_remove_hcd(hcd); | ||
| 189 | usb_put_hcd(hcd); | ||
| 190 | tilegx_stop_ehc(); | ||
| 191 | gxio_usb_host_destroy(&pdata->usb_ctx); | ||
| 192 | destroy_irq(pdata->irq); | ||
| 193 | platform_set_drvdata(pdev, NULL); | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | static void ehci_hcd_tilegx_drv_shutdown(struct platform_device *pdev) | ||
| 199 | { | ||
| 200 | usb_hcd_platform_shutdown(pdev); | ||
| 201 | ehci_hcd_tilegx_drv_remove(pdev); | ||
| 202 | } | ||
| 203 | |||
| 204 | static struct platform_driver ehci_hcd_tilegx_driver = { | ||
| 205 | .probe = ehci_hcd_tilegx_drv_probe, | ||
| 206 | .remove = ehci_hcd_tilegx_drv_remove, | ||
| 207 | .shutdown = ehci_hcd_tilegx_drv_shutdown, | ||
| 208 | .driver = { | ||
| 209 | .name = "tilegx-ehci", | ||
| 210 | .owner = THIS_MODULE, | ||
| 211 | } | ||
| 212 | }; | ||
| 213 | |||
| 214 | MODULE_ALIAS("platform:tilegx-ehci"); | ||
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index e0adf5c0cf55..2b1e8d84c873 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
| @@ -1100,6 +1100,11 @@ MODULE_LICENSE ("GPL"); | |||
| 1100 | #define PLATFORM_DRIVER ohci_octeon_driver | 1100 | #define PLATFORM_DRIVER ohci_octeon_driver |
| 1101 | #endif | 1101 | #endif |
| 1102 | 1102 | ||
| 1103 | #ifdef CONFIG_TILE_USB | ||
| 1104 | #include "ohci-tilegx.c" | ||
| 1105 | #define PLATFORM_DRIVER ohci_hcd_tilegx_driver | ||
| 1106 | #endif | ||
| 1107 | |||
| 1103 | #ifdef CONFIG_USB_CNS3XXX_OHCI | 1108 | #ifdef CONFIG_USB_CNS3XXX_OHCI |
| 1104 | #include "ohci-cns3xxx.c" | 1109 | #include "ohci-cns3xxx.c" |
| 1105 | #define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver | 1110 | #define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver |
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 076d2018e6df..e7d75d295988 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c | |||
| @@ -21,14 +21,15 @@ | |||
| 21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
| 22 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
| 23 | 23 | ||
| 24 | #include <mach/hardware.h> | ||
| 25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
| 26 | #include <asm/mach-types.h> | 25 | #include <asm/mach-types.h> |
| 27 | 26 | ||
| 28 | #include <plat/mux.h> | 27 | #include <plat/mux.h> |
| 29 | #include <mach/irqs.h> | ||
| 30 | #include <plat/fpga.h> | 28 | #include <plat/fpga.h> |
| 31 | #include <plat/usb.h> | 29 | |
| 30 | #include <mach/hardware.h> | ||
| 31 | #include <mach/irqs.h> | ||
| 32 | #include <mach/usb.h> | ||
| 32 | 33 | ||
| 33 | 34 | ||
| 34 | /* OMAP-1510 OHCI has its own MMU for DMA */ | 35 | /* OMAP-1510 OHCI has its own MMU for DMA */ |
diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c new file mode 100644 index 000000000000..1ae7b28a71c2 --- /dev/null +++ b/drivers/usb/host/ohci-tilegx.c | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation, version 2. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, but | ||
| 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Tilera TILE-Gx USB OHCI host controller driver. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/irq.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/usb/tilegx.h> | ||
| 22 | #include <linux/usb.h> | ||
| 23 | |||
| 24 | #include <asm/homecache.h> | ||
| 25 | |||
| 26 | #include <gxio/iorpc_usb_host.h> | ||
| 27 | #include <gxio/usb_host.h> | ||
| 28 | |||
| 29 | static void tilegx_start_ohc(void) | ||
| 30 | { | ||
| 31 | } | ||
| 32 | |||
| 33 | static void tilegx_stop_ohc(void) | ||
| 34 | { | ||
| 35 | } | ||
| 36 | |||
| 37 | static int tilegx_ohci_start(struct usb_hcd *hcd) | ||
| 38 | { | ||
| 39 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
| 40 | int ret; | ||
| 41 | |||
| 42 | ret = ohci_init(ohci); | ||
| 43 | if (ret < 0) | ||
| 44 | return ret; | ||
| 45 | |||
| 46 | ret = ohci_run(ohci); | ||
| 47 | if (ret < 0) { | ||
| 48 | dev_err(hcd->self.controller, "can't start %s\n", | ||
| 49 | hcd->self.bus_name); | ||
| 50 | ohci_stop(hcd); | ||
| 51 | return ret; | ||
| 52 | } | ||
| 53 | |||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | static const struct hc_driver ohci_tilegx_hc_driver = { | ||
| 58 | .description = hcd_name, | ||
| 59 | .product_desc = "Tile-Gx OHCI", | ||
| 60 | .hcd_priv_size = sizeof(struct ohci_hcd), | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Generic hardware linkage. | ||
| 64 | */ | ||
| 65 | .irq = ohci_irq, | ||
| 66 | .flags = HCD_MEMORY | HCD_LOCAL_MEM | HCD_USB11, | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Basic lifecycle operations. | ||
| 70 | */ | ||
| 71 | .start = tilegx_ohci_start, | ||
| 72 | .stop = ohci_stop, | ||
| 73 | .shutdown = ohci_shutdown, | ||
| 74 | |||
| 75 | /* | ||
| 76 | * Managing I/O requests and associated device resources. | ||
| 77 | */ | ||
| 78 | .urb_enqueue = ohci_urb_enqueue, | ||
| 79 | .urb_dequeue = ohci_urb_dequeue, | ||
| 80 | .endpoint_disable = ohci_endpoint_disable, | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Scheduling support. | ||
| 84 | */ | ||
| 85 | .get_frame_number = ohci_get_frame, | ||
| 86 | |||
| 87 | /* | ||
| 88 | * Root hub support. | ||
| 89 | */ | ||
| 90 | .hub_status_data = ohci_hub_status_data, | ||
| 91 | .hub_control = ohci_hub_control, | ||
| 92 | .start_port_reset = ohci_start_port_reset, | ||
| 93 | }; | ||
| 94 | |||
| 95 | static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) | ||
| 96 | { | ||
| 97 | struct usb_hcd *hcd; | ||
| 98 | struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; | ||
| 99 | pte_t pte = { 0 }; | ||
| 100 | int my_cpu = smp_processor_id(); | ||
| 101 | int ret; | ||
| 102 | |||
| 103 | if (usb_disabled()) | ||
| 104 | return -ENODEV; | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Try to initialize our GXIO context; if we can't, the device | ||
| 108 | * doesn't exist. | ||
| 109 | */ | ||
| 110 | if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 0) != 0) | ||
| 111 | return -ENXIO; | ||
| 112 | |||
| 113 | hcd = usb_create_hcd(&ohci_tilegx_hc_driver, &pdev->dev, | ||
| 114 | dev_name(&pdev->dev)); | ||
| 115 | if (!hcd) | ||
| 116 | return -ENOMEM; | ||
| 117 | |||
| 118 | /* | ||
| 119 | * We don't use rsrc_start to map in our registers, but seems like | ||
| 120 | * we ought to set it to something, so we use the register VA. | ||
| 121 | */ | ||
| 122 | hcd->rsrc_start = | ||
| 123 | (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx); | ||
| 124 | hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx); | ||
| 125 | hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx); | ||
| 126 | |||
| 127 | tilegx_start_ohc(); | ||
| 128 | |||
| 129 | /* Create our IRQs and register them. */ | ||
| 130 | pdata->irq = create_irq(); | ||
| 131 | if (pdata->irq < 0) { | ||
| 132 | ret = -ENXIO; | ||
| 133 | goto err_no_irq; | ||
| 134 | } | ||
| 135 | |||
| 136 | tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU); | ||
| 137 | |||
| 138 | /* Configure interrupts. */ | ||
| 139 | ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx, | ||
| 140 | cpu_x(my_cpu), cpu_y(my_cpu), | ||
| 141 | KERNEL_PL, pdata->irq); | ||
| 142 | if (ret) { | ||
| 143 | ret = -ENXIO; | ||
| 144 | goto err_have_irq; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* Register all of our memory. */ | ||
| 148 | pte = pte_set_home(pte, PAGE_HOME_HASH); | ||
| 149 | ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0); | ||
| 150 | if (ret) { | ||
| 151 | ret = -ENXIO; | ||
| 152 | goto err_have_irq; | ||
| 153 | } | ||
| 154 | |||
| 155 | ohci_hcd_init(hcd_to_ohci(hcd)); | ||
| 156 | |||
| 157 | ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); | ||
| 158 | if (ret == 0) { | ||
| 159 | platform_set_drvdata(pdev, hcd); | ||
| 160 | return ret; | ||
| 161 | } | ||
| 162 | |||
| 163 | err_have_irq: | ||
| 164 | destroy_irq(pdata->irq); | ||
| 165 | err_no_irq: | ||
| 166 | tilegx_stop_ohc(); | ||
| 167 | usb_put_hcd(hcd); | ||
| 168 | gxio_usb_host_destroy(&pdata->usb_ctx); | ||
| 169 | return ret; | ||
| 170 | } | ||
| 171 | |||
| 172 | static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev) | ||
| 173 | { | ||
| 174 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
| 175 | struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data; | ||
| 176 | |||
| 177 | usb_remove_hcd(hcd); | ||
| 178 | usb_put_hcd(hcd); | ||
| 179 | tilegx_stop_ohc(); | ||
| 180 | gxio_usb_host_destroy(&pdata->usb_ctx); | ||
| 181 | destroy_irq(pdata->irq); | ||
| 182 | platform_set_drvdata(pdev, NULL); | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void ohci_hcd_tilegx_drv_shutdown(struct platform_device *pdev) | ||
| 188 | { | ||
| 189 | usb_hcd_platform_shutdown(pdev); | ||
| 190 | ohci_hcd_tilegx_drv_remove(pdev); | ||
| 191 | } | ||
| 192 | |||
| 193 | static struct platform_driver ohci_hcd_tilegx_driver = { | ||
| 194 | .probe = ohci_hcd_tilegx_drv_probe, | ||
| 195 | .remove = ohci_hcd_tilegx_drv_remove, | ||
| 196 | .shutdown = ohci_hcd_tilegx_drv_shutdown, | ||
| 197 | .driver = { | ||
| 198 | .name = "tilegx-ohci", | ||
| 199 | .owner = THIS_MODULE, | ||
| 200 | } | ||
| 201 | }; | ||
| 202 | |||
| 203 | MODULE_ALIAS("platform:tilegx-ohci"); | ||
