linux/drivers/usb/host/ohci-tilegx.c
<<
>>
Prefs
   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
  29static void tilegx_start_ohc(void)
  30{
  31}
  32
  33static void tilegx_stop_ohc(void)
  34{
  35}
  36
  37static 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
  57static 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
  95static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev)
  96{
  97        struct usb_hcd *hcd;
  98        struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
  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                ret = -ENOMEM;
 117                goto err_hcd;
 118        }
 119
 120        /*
 121         * We don't use rsrc_start to map in our registers, but seems like
 122         * we ought to set it to something, so we use the register VA.
 123         */
 124        hcd->rsrc_start =
 125                (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx);
 126        hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx);
 127        hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx);
 128
 129        tilegx_start_ohc();
 130
 131        /* Create our IRQs and register them. */
 132        pdata->irq = irq_alloc_hwirq(-1);
 133        if (!pdata->irq) {
 134                ret = -ENXIO;
 135                goto err_no_irq;
 136        }
 137
 138        tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU);
 139
 140        /* Configure interrupts. */
 141        ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx,
 142                                          cpu_x(my_cpu), cpu_y(my_cpu),
 143                                          KERNEL_PL, pdata->irq);
 144        if (ret) {
 145                ret = -ENXIO;
 146                goto err_have_irq;
 147        }
 148
 149        /* Register all of our memory. */
 150        pte = pte_set_home(pte, PAGE_HOME_HASH);
 151        ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0);
 152        if (ret) {
 153                ret = -ENXIO;
 154                goto err_have_irq;
 155        }
 156
 157        ohci_hcd_init(hcd_to_ohci(hcd));
 158
 159        ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED);
 160        if (ret == 0) {
 161                platform_set_drvdata(pdev, hcd);
 162                device_wakeup_enable(hcd->self.controller);
 163                return ret;
 164        }
 165
 166err_have_irq:
 167        irq_free_hwirq(pdata->irq);
 168err_no_irq:
 169        tilegx_stop_ohc();
 170        usb_put_hcd(hcd);
 171err_hcd:
 172        gxio_usb_host_destroy(&pdata->usb_ctx);
 173        return ret;
 174}
 175
 176static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev)
 177{
 178        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 179        struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 180
 181        usb_remove_hcd(hcd);
 182        usb_put_hcd(hcd);
 183        tilegx_stop_ohc();
 184        gxio_usb_host_destroy(&pdata->usb_ctx);
 185        irq_free_hwirq(pdata->irq);
 186
 187        return 0;
 188}
 189
 190static void ohci_hcd_tilegx_drv_shutdown(struct platform_device *pdev)
 191{
 192        usb_hcd_platform_shutdown(pdev);
 193        ohci_hcd_tilegx_drv_remove(pdev);
 194}
 195
 196static struct platform_driver ohci_hcd_tilegx_driver = {
 197        .probe          = ohci_hcd_tilegx_drv_probe,
 198        .remove         = ohci_hcd_tilegx_drv_remove,
 199        .shutdown       = ohci_hcd_tilegx_drv_shutdown,
 200        .driver = {
 201                .name   = "tilegx-ohci",
 202                .owner  = THIS_MODULE,
 203        }
 204};
 205
 206MODULE_ALIAS("platform:tilegx-ohci");
 207