linux/drivers/usb/host/ehci-ath79.c
<<
>>
Prefs
   1/*
   2 *  Bus Glue for Atheros AR7XXX/AR9XXX built-in EHCI controller.
   3 *
   4 *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
   5 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
   6 *
   7 *  Parts of this file are based on Atheros' 2.6.15 BSP
   8 *      Copyright (C) 2007 Atheros Communications, Inc.
   9 *
  10 *  This program is free software; you can redistribute it and/or modify it
  11 *  under the terms of the GNU General Public License version 2 as published
  12 *  by the Free Software Foundation.
  13 */
  14
  15#include <linux/platform_device.h>
  16
  17enum {
  18        EHCI_ATH79_IP_V1 = 0,
  19        EHCI_ATH79_IP_V2,
  20};
  21
  22static const struct platform_device_id ehci_ath79_id_table[] = {
  23        {
  24                .name           = "ar71xx-ehci",
  25                .driver_data    = EHCI_ATH79_IP_V1,
  26        },
  27        {
  28                .name           = "ar724x-ehci",
  29                .driver_data    = EHCI_ATH79_IP_V2,
  30        },
  31        {
  32                .name           = "ar913x-ehci",
  33                .driver_data    = EHCI_ATH79_IP_V2,
  34        },
  35        {
  36                .name           = "ar933x-ehci",
  37                .driver_data    = EHCI_ATH79_IP_V2,
  38        },
  39        {
  40                /* terminating entry */
  41        },
  42};
  43
  44MODULE_DEVICE_TABLE(platform, ehci_ath79_id_table);
  45
  46static int ehci_ath79_init(struct usb_hcd *hcd)
  47{
  48        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
  49        struct platform_device *pdev = to_platform_device(hcd->self.controller);
  50        const struct platform_device_id *id;
  51        int ret;
  52
  53        id = platform_get_device_id(pdev);
  54        if (!id) {
  55                dev_err(hcd->self.controller, "missing device id\n");
  56                return -EINVAL;
  57        }
  58
  59        switch (id->driver_data) {
  60        case EHCI_ATH79_IP_V1:
  61                ehci->has_synopsys_hc_bug = 1;
  62
  63                ehci->caps = hcd->regs;
  64                ehci->regs = hcd->regs +
  65                        HC_LENGTH(ehci,
  66                                  ehci_readl(ehci, &ehci->caps->hc_capbase));
  67                break;
  68
  69        case EHCI_ATH79_IP_V2:
  70                hcd->has_tt = 1;
  71
  72                ehci->caps = hcd->regs + 0x100;
  73                ehci->regs = hcd->regs + 0x100 +
  74                        HC_LENGTH(ehci,
  75                                  ehci_readl(ehci, &ehci->caps->hc_capbase));
  76                break;
  77
  78        default:
  79                BUG();
  80        }
  81
  82        dbg_hcs_params(ehci, "reset");
  83        dbg_hcc_params(ehci, "reset");
  84        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
  85        ehci->sbrn = 0x20;
  86
  87        ehci_reset(ehci);
  88
  89        ret = ehci_init(hcd);
  90        if (ret)
  91                return ret;
  92
  93        ehci_port_power(ehci, 0);
  94
  95        return 0;
  96}
  97
  98static const struct hc_driver ehci_ath79_hc_driver = {
  99        .description            = hcd_name,
 100        .product_desc           = "Atheros built-in EHCI controller",
 101        .hcd_priv_size          = sizeof(struct ehci_hcd),
 102        .irq                    = ehci_irq,
 103        .flags                  = HCD_MEMORY | HCD_USB2,
 104
 105        .reset                  = ehci_ath79_init,
 106        .start                  = ehci_run,
 107        .stop                   = ehci_stop,
 108        .shutdown               = ehci_shutdown,
 109
 110        .urb_enqueue            = ehci_urb_enqueue,
 111        .urb_dequeue            = ehci_urb_dequeue,
 112        .endpoint_disable       = ehci_endpoint_disable,
 113        .endpoint_reset         = ehci_endpoint_reset,
 114
 115        .get_frame_number       = ehci_get_frame,
 116
 117        .hub_status_data        = ehci_hub_status_data,
 118        .hub_control            = ehci_hub_control,
 119
 120        .relinquish_port        = ehci_relinquish_port,
 121        .port_handed_over       = ehci_port_handed_over,
 122
 123        .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 124};
 125
 126static int ehci_ath79_probe(struct platform_device *pdev)
 127{
 128        struct usb_hcd *hcd;
 129        struct resource *res;
 130        int irq;
 131        int ret;
 132
 133        if (usb_disabled())
 134                return -ENODEV;
 135
 136        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 137        if (!res) {
 138                dev_dbg(&pdev->dev, "no IRQ specified\n");
 139                return -ENODEV;
 140        }
 141        irq = res->start;
 142
 143        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 144        if (!res) {
 145                dev_dbg(&pdev->dev, "no base address specified\n");
 146                return -ENODEV;
 147        }
 148
 149        hcd = usb_create_hcd(&ehci_ath79_hc_driver, &pdev->dev,
 150                             dev_name(&pdev->dev));
 151        if (!hcd)
 152                return -ENOMEM;
 153
 154        hcd->rsrc_start = res->start;
 155        hcd->rsrc_len   = resource_size(res);
 156
 157        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 158                dev_dbg(&pdev->dev, "controller already in use\n");
 159                ret = -EBUSY;
 160                goto err_put_hcd;
 161        }
 162
 163        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 164        if (!hcd->regs) {
 165                dev_dbg(&pdev->dev, "error mapping memory\n");
 166                ret = -EFAULT;
 167                goto err_release_region;
 168        }
 169
 170        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 171        if (ret)
 172                goto err_iounmap;
 173
 174        return 0;
 175
 176err_iounmap:
 177        iounmap(hcd->regs);
 178
 179err_release_region:
 180        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 181err_put_hcd:
 182        usb_put_hcd(hcd);
 183        return ret;
 184}
 185
 186static int ehci_ath79_remove(struct platform_device *pdev)
 187{
 188        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 189
 190        usb_remove_hcd(hcd);
 191        iounmap(hcd->regs);
 192        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 193        usb_put_hcd(hcd);
 194
 195        return 0;
 196}
 197
 198static struct platform_driver ehci_ath79_driver = {
 199        .probe          = ehci_ath79_probe,
 200        .remove         = ehci_ath79_remove,
 201        .id_table       = ehci_ath79_id_table,
 202        .driver = {
 203                .owner  = THIS_MODULE,
 204                .name   = "ath79-ehci",
 205        }
 206};
 207
 208MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ehci");
 209
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.