~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/usb/host/ehci-pmcmsp.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno
  • Date: 2011-06-07 12:14:05 UTC
  • mfrom: (43.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20110607121405-i3h1rd7nrnd2b73h
Tags: 2.6.39-2
[ Ben Hutchings ]
* [x86] Enable BACKLIGHT_APPLE, replacing BACKLIGHT_MBP_NVIDIA
  (Closes: #627492)
* cgroups: Disable memory resource controller by default. Allow it
  to be enabled using kernel parameter 'cgroup_enable=memory'.
* rt2800usb: Enable support for more USB devices including
  Linksys WUSB600N (Closes: #596626) (this change was accidentally
  omitted from 2.6.39-1)
* [x86] Remove Celeron from list of processors supporting PAE. Most
  'Celeron M' models do not.
* Update debconf template translations:
  - Swedish (Martin Bagge) (Closes: #628932)
  - French (David Prévot) (Closes: #628191)
* aufs: Update for 2.6.39 (Closes: #627837)
* Add stable 2.6.39.1, including:
  - ext4: dont set PageUptodate in ext4_end_bio()
  - pata_cmd64x: fix boot crash on parisc (Closes: #622997, #622745)
  - ext3: Fix fs corruption when make_indexed_dir() fails
  - netfilter: nf_ct_sip: validate Content-Length in TCP SIP messages
  - sctp: fix race between sctp_bind_addr_free() and
    sctp_bind_addr_conflict()
  - sctp: fix memory leak of the ASCONF queue when free asoc
  - md/bitmap: fix saving of events_cleared and other state
  - cdc_acm: Fix oops when Droids MuIn LCD is connected
  - cx88: Fix conversion from BKL to fine-grained locks (Closes: #619827)
  - keys: Set cred->user_ns in key_replace_session_keyring (CVE-2011-2184)
  - tmpfs: fix race between truncate and writepage
  - nfs41: Correct offset for LAYOUTCOMMIT
  - xen/mmu: fix a race window causing leave_mm BUG()
  - ext4: fix possible use-after-free in ext4_remove_li_request()
  For the complete list of changes, see:
   http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.39.1
* Bump ABI to 2
* netfilter: Enable IP_SET, IP_SET_BITMAP_IP, IP_SET_BITMAP_IPMAC,
  IP_SET_BITMAP_PORT, IP_SET_HASH_IP, IP_SET_HASH_IPPORT,
  IP_SET_HASH_IPPORTIP, IP_SET_HASH_IPPORTNET, IP_SET_HASH_NET,
  IP_SET_HASH_NETPORT, IP_SET_LIST_SET, NETFILTER_XT_SET as modules
  (Closes: #629401)

[ Aurelien Jarno ]
* [mipsel/loongson-2f] Disable_SCSI_LPFC to workaround GCC ICE.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * PMC MSP EHCI (Host Controller Driver) for USB.
 
3
 *
 
4
 * (C) Copyright 2006-2010 PMC-Sierra Inc
 
5
 *
 
6
 * This file is subject to the terms and conditions of the GNU General Public
 
7
 * License.  See the file "COPYING" in the main directory of this archive
 
8
 * for more details.
 
9
 *
 
10
 */
 
11
 
 
12
/* includes */
 
13
#include <linux/platform_device.h>
 
14
#include <linux/gpio.h>
 
15
#include <linux/usb.h>
 
16
#include <msp_usb.h>
 
17
 
 
18
/* stream disable*/
 
19
#define USB_CTRL_MODE_STREAM_DISABLE    0x10
 
20
 
 
21
/* threshold */
 
22
#define USB_CTRL_FIFO_THRESH            0x00300000
 
23
 
 
24
/* register offset for usb_mode */
 
25
#define USB_EHCI_REG_USB_MODE           0x68
 
26
 
 
27
/* register offset for usb fifo */
 
28
#define USB_EHCI_REG_USB_FIFO           0x24
 
29
 
 
30
/* register offset for usb status */
 
31
#define USB_EHCI_REG_USB_STATUS         0x44
 
32
 
 
33
/* serial/parallel transceiver */
 
34
#define USB_EHCI_REG_BIT_STAT_STS       (1<<29)
 
35
 
 
36
/* TWI USB0 host device pin */
 
37
#define MSP_PIN_USB0_HOST_DEV           49
 
38
 
 
39
/* TWI USB1 host device pin */
 
40
#define MSP_PIN_USB1_HOST_DEV           50
 
41
 
 
42
 
 
43
static void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci)
 
44
{
 
45
        u8 *base;
 
46
        u8 *statreg;
 
47
        u8 *fiforeg;
 
48
        u32 val;
 
49
        struct ehci_regs *reg_base = ehci->regs;
 
50
 
 
51
        /* get register base */
 
52
        base = (u8 *)reg_base + USB_EHCI_REG_USB_MODE;
 
53
        statreg = (u8 *)reg_base + USB_EHCI_REG_USB_STATUS;
 
54
        fiforeg = (u8 *)reg_base + USB_EHCI_REG_USB_FIFO;
 
55
 
 
56
        /* Disable controller mode stream */
 
57
        val = ehci_readl(ehci, (u32 *)base);
 
58
        ehci_writel(ehci, (val | USB_CTRL_MODE_STREAM_DISABLE),
 
59
                        (u32 *)base);
 
60
 
 
61
        /* clear STS to select parallel transceiver interface */
 
62
        val = ehci_readl(ehci, (u32 *)statreg);
 
63
        val = val & ~USB_EHCI_REG_BIT_STAT_STS;
 
64
        ehci_writel(ehci, val, (u32 *)statreg);
 
65
 
 
66
        /* write to set the proper fifo threshold */
 
67
        ehci_writel(ehci, USB_CTRL_FIFO_THRESH, (u32 *)fiforeg);
 
68
 
 
69
        /* set TWI GPIO USB_HOST_DEV pin high */
 
70
        gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1);
 
71
#ifdef CONFIG_MSP_HAS_DUAL_USB
 
72
        gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1);
 
73
#endif
 
74
}
 
75
 
 
76
/* called during probe() after chip reset completes */
 
77
static int ehci_msp_setup(struct usb_hcd *hcd)
 
78
{
 
79
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
 
80
        int                     retval;
 
81
        ehci->big_endian_mmio = 1;
 
82
        ehci->big_endian_desc = 1;
 
83
 
 
84
        ehci->caps = hcd->regs;
 
85
        ehci->regs = hcd->regs +
 
86
                        HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
 
87
        dbg_hcs_params(ehci, "reset");
 
88
        dbg_hcc_params(ehci, "reset");
 
89
 
 
90
        /* cache this readonly data; minimize chip reads */
 
91
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
92
        hcd->has_tt = 1;
 
93
 
 
94
        retval = ehci_halt(ehci);
 
95
        if (retval)
 
96
                return retval;
 
97
 
 
98
        ehci_reset(ehci);
 
99
 
 
100
        /* data structure init */
 
101
        retval = ehci_init(hcd);
 
102
        if (retval)
 
103
                return retval;
 
104
 
 
105
        usb_hcd_tdi_set_mode(ehci);
 
106
        ehci_port_power(ehci, 0);
 
107
 
 
108
        return retval;
 
109
}
 
110
 
 
111
 
 
112
/* configure so an HC device and id are always provided
 
113
 * always called with process context; sleeping is OK
 
114
 */
 
115
 
 
116
static int usb_hcd_msp_map_regs(struct mspusb_device *dev)
 
117
{
 
118
        struct resource *res;
 
119
        struct platform_device *pdev = &dev->dev;
 
120
        u32 res_len;
 
121
        int retval;
 
122
 
 
123
        /* MAB register space */
 
124
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 
125
        if (res == NULL)
 
126
                return -ENOMEM;
 
127
        res_len = res->end - res->start + 1;
 
128
        if (!request_mem_region(res->start, res_len, "mab regs"))
 
129
                return -EBUSY;
 
130
 
 
131
        dev->mab_regs = ioremap_nocache(res->start, res_len);
 
132
        if (dev->mab_regs == NULL) {
 
133
                retval = -ENOMEM;
 
134
                goto err1;
 
135
        }
 
136
 
 
137
        /* MSP USB register space */
 
138
        res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 
139
        if (res == NULL) {
 
140
                retval = -ENOMEM;
 
141
                goto err2;
 
142
        }
 
143
        res_len = res->end - res->start + 1;
 
144
        if (!request_mem_region(res->start, res_len, "usbid regs")) {
 
145
                retval = -EBUSY;
 
146
                goto err2;
 
147
        }
 
148
        dev->usbid_regs = ioremap_nocache(res->start, res_len);
 
149
        if (dev->usbid_regs == NULL) {
 
150
                retval = -ENOMEM;
 
151
                goto err3;
 
152
        }
 
153
 
 
154
        return 0;
 
155
err3:
 
156
        res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 
157
        res_len = res->end - res->start + 1;
 
158
        release_mem_region(res->start, res_len);
 
159
err2:
 
160
        iounmap(dev->mab_regs);
 
161
err1:
 
162
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 
163
        res_len = res->end - res->start + 1;
 
164
        release_mem_region(res->start, res_len);
 
165
        dev_err(&pdev->dev, "Failed to map non-EHCI regs.\n");
 
166
        return retval;
 
167
}
 
168
 
 
169
/**
 
170
 * usb_hcd_msp_probe - initialize PMC MSP-based HCDs
 
171
 * Context: !in_interrupt()
 
172
 *
 
173
 * Allocates basic resources for this USB host controller, and
 
174
 * then invokes the start() method for the HCD associated with it
 
175
 * through the hotplug entry's driver_data.
 
176
 *
 
177
 */
 
178
int usb_hcd_msp_probe(const struct hc_driver *driver,
 
179
                          struct platform_device *dev)
 
180
{
 
181
        int retval;
 
182
        struct usb_hcd *hcd;
 
183
        struct resource *res;
 
184
        struct ehci_hcd         *ehci ;
 
185
 
 
186
        hcd = usb_create_hcd(driver, &dev->dev, "pmcmsp");
 
187
        if (!hcd)
 
188
                return -ENOMEM;
 
189
 
 
190
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 
191
        if (res == NULL) {
 
192
                pr_debug("No IOMEM resource info for %s.\n", dev->name);
 
193
                retval = -ENOMEM;
 
194
                goto err1;
 
195
        }
 
196
        hcd->rsrc_start = res->start;
 
197
        hcd->rsrc_len = res->end - res->start + 1;
 
198
        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, dev->name)) {
 
199
                retval = -EBUSY;
 
200
                goto err1;
 
201
        }
 
202
        hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
 
203
        if (!hcd->regs) {
 
204
                pr_debug("ioremap failed");
 
205
                retval = -ENOMEM;
 
206
                goto err2;
 
207
        }
 
208
 
 
209
        res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
 
210
        if (res == NULL) {
 
211
                dev_err(&dev->dev, "No IRQ resource info for %s.\n", dev->name);
 
212
                retval = -ENOMEM;
 
213
                goto err3;
 
214
        }
 
215
 
 
216
        /* Map non-EHCI register spaces */
 
217
        retval = usb_hcd_msp_map_regs(to_mspusb_device(dev));
 
218
        if (retval != 0)
 
219
                goto err3;
 
220
 
 
221
        ehci = hcd_to_ehci(hcd);
 
222
        ehci->big_endian_mmio = 1;
 
223
        ehci->big_endian_desc = 1;
 
224
 
 
225
 
 
226
        retval = usb_add_hcd(hcd, res->start, IRQF_SHARED);
 
227
        if (retval == 0)
 
228
                return 0;
 
229
 
 
230
        usb_remove_hcd(hcd);
 
231
err3:
 
232
        iounmap(hcd->regs);
 
233
err2:
 
234
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
235
err1:
 
236
        usb_put_hcd(hcd);
 
237
 
 
238
        return retval;
 
239
}
 
240
 
 
241
 
 
242
 
 
243
/**
 
244
 * usb_hcd_msp_remove - shutdown processing for PMC MSP-based HCDs
 
245
 * @dev: USB Host Controller being removed
 
246
 * Context: !in_interrupt()
 
247
 *
 
248
 * Reverses the effect of usb_hcd_msp_probe(), first invoking
 
249
 * the HCD's stop() method.  It is always called from a thread
 
250
 * context, normally "rmmod", "apmd", or something similar.
 
251
 *
 
252
 * may be called without controller electrically present
 
253
 * may be called with controller, bus, and devices active
 
254
 */
 
255
void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev)
 
256
{
 
257
        usb_remove_hcd(hcd);
 
258
        iounmap(hcd->regs);
 
259
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
260
        usb_put_hcd(hcd);
 
261
}
 
262
 
 
263
#ifdef CONFIG_MSP_HAS_DUAL_USB
 
264
/*
 
265
 * Wrapper around the main ehci_irq.  Since both USB host controllers are
 
266
 * sharing the same IRQ, need to first determine whether we're the intended
 
267
 * recipient of this interrupt.
 
268
 */
 
269
static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd)
 
270
{
 
271
        u32 int_src;
 
272
        struct device *dev = hcd->self.controller;
 
273
        struct platform_device *pdev;
 
274
        struct mspusb_device *mdev;
 
275
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
276
        /* need to reverse-map a couple of containers to get our device */
 
277
        pdev = to_platform_device(dev);
 
278
        mdev = to_mspusb_device(pdev);
 
279
 
 
280
        /* Check to see if this interrupt is for this host controller */
 
281
        int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat);
 
282
        if (int_src & (1 << pdev->id))
 
283
                return ehci_irq(hcd);
 
284
 
 
285
        /* Not for this device */
 
286
        return IRQ_NONE;
 
287
}
 
288
#endif /* DUAL_USB */
 
289
 
 
290
static const struct hc_driver ehci_msp_hc_driver = {
 
291
        .description =          hcd_name,
 
292
        .product_desc =         "PMC MSP EHCI",
 
293
        .hcd_priv_size =        sizeof(struct ehci_hcd),
 
294
 
 
295
        /*
 
296
         * generic hardware linkage
 
297
         */
 
298
#ifdef CONFIG_MSP_HAS_DUAL_USB
 
299
        .irq =                  ehci_msp_irq,
 
300
#else
 
301
        .irq =                  ehci_irq,
 
302
#endif
 
303
        .flags =                HCD_MEMORY | HCD_USB2,
 
304
 
 
305
        /*
 
306
         * basic lifecycle operations
 
307
         */
 
308
        .reset =                ehci_msp_setup,
 
309
        .start =                ehci_run,
 
310
        .shutdown               = ehci_shutdown,
 
311
        .start                  = ehci_run,
 
312
        .stop                   = ehci_stop,
 
313
 
 
314
        /*
 
315
         * managing i/o requests and associated device resources
 
316
         */
 
317
        .urb_enqueue            = ehci_urb_enqueue,
 
318
        .urb_dequeue            = ehci_urb_dequeue,
 
319
        .endpoint_disable       = ehci_endpoint_disable,
 
320
        .endpoint_reset         = ehci_endpoint_reset,
 
321
 
 
322
        /*
 
323
         * scheduling support
 
324
         */
 
325
        .get_frame_number       = ehci_get_frame,
 
326
 
 
327
        /*
 
328
         * root hub support
 
329
         */
 
330
        .hub_status_data        = ehci_hub_status_data,
 
331
        .hub_control            = ehci_hub_control,
 
332
        .bus_suspend            = ehci_bus_suspend,
 
333
        .bus_resume             = ehci_bus_resume,
 
334
        .relinquish_port        = ehci_relinquish_port,
 
335
        .port_handed_over       = ehci_port_handed_over,
 
336
 
 
337
        .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 
338
};
 
339
 
 
340
static int ehci_hcd_msp_drv_probe(struct platform_device *pdev)
 
341
{
 
342
        int ret;
 
343
 
 
344
        pr_debug("In ehci_hcd_msp_drv_probe");
 
345
 
 
346
        if (usb_disabled())
 
347
                return -ENODEV;
 
348
 
 
349
        gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO");
 
350
#ifdef CONFIG_MSP_HAS_DUAL_USB
 
351
        gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO");
 
352
#endif
 
353
 
 
354
        ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev);
 
355
 
 
356
        return ret;
 
357
}
 
358
 
 
359
static int ehci_hcd_msp_drv_remove(struct platform_device *pdev)
 
360
{
 
361
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
362
 
 
363
        usb_hcd_msp_remove(hcd, pdev);
 
364
 
 
365
        /* free TWI GPIO USB_HOST_DEV pin */
 
366
        gpio_free(MSP_PIN_USB0_HOST_DEV);
 
367
#ifdef CONFIG_MSP_HAS_DUAL_USB
 
368
        gpio_free(MSP_PIN_USB1_HOST_DEV);
 
369
#endif
 
370
 
 
371
        return 0;
 
372
}
 
373
 
 
374
MODULE_ALIAS("pmcmsp-ehci");
 
375
 
 
376
static struct platform_driver ehci_hcd_msp_driver = {
 
377
        .probe          = ehci_hcd_msp_drv_probe,
 
378
        .remove         = ehci_hcd_msp_drv_remove,
 
379
        .driver         = {
 
380
                .name   = "pmcmsp-ehci",
 
381
                .owner  = THIS_MODULE,
 
382
        },
 
383
};