~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise-security

« back to all changes in this revision

Viewing changes to drivers/usb/host/ohci-at91.c

  • Committer: Package Import Robot
  • Author(s): Paolo Pisati, Paolo Pisati
  • Date: 2011-12-06 15:56:07 UTC
  • Revision ID: package-import@ubuntu.com-20111206155607-pcf44kv5fmhk564f
Tags: 3.2.0-1401.1
[ Paolo Pisati ]

* Rebased on top of Ubuntu-3.2.0-3.8
* Tilt-tracking @ ef2487af4bb15bdd0689631774b5a5e3a59f74e2
* Delete debian.ti-omap4/control, it shoudln't be tracked
* Fix architecture spelling (s/armel/armhf/)
* [Config] Update configs following 3.2 import
* [Config] Fix compilation: disable CODA and ARCH_OMAP3
* [Config] Fix compilation: disable Ethernet Faraday
* Update series to precise

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
 
36
36
static void at91_start_clock(void)
37
37
{
38
 
        if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
39
 
                clk_enable(hclk);
 
38
        clk_enable(hclk);
40
39
        clk_enable(iclk);
41
40
        clk_enable(fclk);
42
41
        clocked = 1;
46
45
{
47
46
        clk_disable(fclk);
48
47
        clk_disable(iclk);
49
 
        if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
50
 
                clk_disable(hclk);
 
48
        clk_disable(hclk);
51
49
        clocked = 0;
52
50
}
53
51
 
142
140
 
143
141
        iclk = clk_get(&pdev->dev, "ohci_clk");
144
142
        fclk = clk_get(&pdev->dev, "uhpck");
145
 
        if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
146
 
                hclk = clk_get(&pdev->dev, "hck0");
 
143
        hclk = clk_get(&pdev->dev, "hclk");
147
144
 
148
145
        at91_start_hc(pdev);
149
146
        ohci_hcd_init(hcd_to_ohci(hcd));
155
152
        /* Error handling */
156
153
        at91_stop_hc(pdev);
157
154
 
158
 
        if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
159
 
                clk_put(hclk);
 
155
        clk_put(hclk);
160
156
        clk_put(fclk);
161
157
        clk_put(iclk);
162
158
 
192
188
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
193
189
        usb_put_hcd(hcd);
194
190
 
195
 
        if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
196
 
                clk_put(hclk);
 
191
        clk_put(hclk);
197
192
        clk_put(fclk);
198
193
        clk_put(iclk);
199
194
        fclk = iclk = hclk = NULL;
223
218
        return 0;
224
219
}
225
220
 
 
221
static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable)
 
222
{
 
223
        if (port < 0 || port >= 2)
 
224
                return;
 
225
 
 
226
        if (pdata->vbus_pin[port] <= 0)
 
227
                return;
 
228
 
 
229
        gpio_set_value(pdata->vbus_pin[port], !pdata->vbus_pin_inverted ^ enable);
 
230
}
 
231
 
 
232
static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
 
233
{
 
234
        if (port < 0 || port >= 2)
 
235
                return -EINVAL;
 
236
 
 
237
        if (pdata->vbus_pin[port] <= 0)
 
238
                return -EINVAL;
 
239
 
 
240
        return gpio_get_value(pdata->vbus_pin[port]) ^ !pdata->vbus_pin_inverted;
 
241
}
 
242
 
 
243
/*
 
244
 * Update the status data from the hub with the over-current indicator change.
 
245
 */
 
246
static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
 
247
{
 
248
        struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
 
249
        int length = ohci_hub_status_data(hcd, buf);
 
250
        int port;
 
251
 
 
252
        for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
 
253
                if (pdata->overcurrent_changed[port]) {
 
254
                        if (! length)
 
255
                                length = 1;
 
256
                        buf[0] |= 1 << (port + 1);
 
257
                }
 
258
        }
 
259
 
 
260
        return length;
 
261
}
 
262
 
 
263
/*
 
264
 * Look at the control requests to the root hub and see if we need to override.
 
265
 */
 
266
static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 
267
                                 u16 wIndex, char *buf, u16 wLength)
 
268
{
 
269
        struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
 
270
        struct usb_hub_descriptor *desc;
 
271
        int ret = -EINVAL;
 
272
        u32 *data = (u32 *)buf;
 
273
 
 
274
        dev_dbg(hcd->self.controller,
 
275
                "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n",
 
276
                hcd, typeReq, wValue, wIndex, buf, wLength);
 
277
 
 
278
        switch (typeReq) {
 
279
        case SetPortFeature:
 
280
                if (wValue == USB_PORT_FEAT_POWER) {
 
281
                        dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n");
 
282
                        ohci_at91_usb_set_power(pdata, wIndex - 1, 1);
 
283
                        goto out;
 
284
                }
 
285
                break;
 
286
 
 
287
        case ClearPortFeature:
 
288
                switch (wValue) {
 
289
                case USB_PORT_FEAT_C_OVER_CURRENT:
 
290
                        dev_dbg(hcd->self.controller,
 
291
                                "ClearPortFeature: C_OVER_CURRENT\n");
 
292
 
 
293
                        if (wIndex == 1 || wIndex == 2) {
 
294
                                pdata->overcurrent_changed[wIndex-1] = 0;
 
295
                                pdata->overcurrent_status[wIndex-1] = 0;
 
296
                        }
 
297
 
 
298
                        goto out;
 
299
 
 
300
                case USB_PORT_FEAT_OVER_CURRENT:
 
301
                        dev_dbg(hcd->self.controller,
 
302
                                "ClearPortFeature: OVER_CURRENT\n");
 
303
 
 
304
                        if (wIndex == 1 || wIndex == 2) {
 
305
                                pdata->overcurrent_status[wIndex-1] = 0;
 
306
                        }
 
307
 
 
308
                        goto out;
 
309
 
 
310
                case USB_PORT_FEAT_POWER:
 
311
                        dev_dbg(hcd->self.controller,
 
312
                                "ClearPortFeature: POWER\n");
 
313
 
 
314
                        if (wIndex == 1 || wIndex == 2) {
 
315
                                ohci_at91_usb_set_power(pdata, wIndex - 1, 0);
 
316
                                return 0;
 
317
                        }
 
318
                }
 
319
                break;
 
320
        }
 
321
 
 
322
        ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
 
323
        if (ret)
 
324
                goto out;
 
325
 
 
326
        switch (typeReq) {
 
327
        case GetHubDescriptor:
 
328
 
 
329
                /* update the hub's descriptor */
 
330
 
 
331
                desc = (struct usb_hub_descriptor *)buf;
 
332
 
 
333
                dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n",
 
334
                        desc->wHubCharacteristics);
 
335
 
 
336
                /* remove the old configurations for power-switching, and
 
337
                 * over-current protection, and insert our new configuration
 
338
                 */
 
339
 
 
340
                desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
 
341
                desc->wHubCharacteristics |= cpu_to_le16(0x0001);
 
342
 
 
343
                if (pdata->overcurrent_supported) {
 
344
                        desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
 
345
                        desc->wHubCharacteristics |=  cpu_to_le16(0x0008|0x0001);
 
346
                }
 
347
 
 
348
                dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
 
349
                        desc->wHubCharacteristics);
 
350
 
 
351
                return ret;
 
352
 
 
353
        case GetPortStatus:
 
354
                /* check port status */
 
355
 
 
356
                dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
 
357
 
 
358
                if (wIndex == 1 || wIndex == 2) {
 
359
                        if (! ohci_at91_usb_get_power(pdata, wIndex-1)) {
 
360
                                *data &= ~cpu_to_le32(RH_PS_PPS);
 
361
                        }
 
362
 
 
363
                        if (pdata->overcurrent_changed[wIndex-1]) {
 
364
                                *data |= cpu_to_le32(RH_PS_OCIC);
 
365
                        }
 
366
 
 
367
                        if (pdata->overcurrent_status[wIndex-1]) {
 
368
                                *data |= cpu_to_le32(RH_PS_POCI);
 
369
                        }
 
370
                }
 
371
        }
 
372
 
 
373
 out:
 
374
        return ret;
 
375
}
 
376
 
226
377
/*-------------------------------------------------------------------------*/
227
378
 
228
379
static const struct hc_driver ohci_at91_hc_driver = {
258
409
        /*
259
410
         * root hub support
260
411
         */
261
 
        .hub_status_data =      ohci_hub_status_data,
262
 
        .hub_control =          ohci_hub_control,
 
412
        .hub_status_data =      ohci_at91_hub_status_data,
 
413
        .hub_control =          ohci_at91_hub_control,
263
414
#ifdef CONFIG_PM
264
415
        .bus_suspend =          ohci_bus_suspend,
265
416
        .bus_resume =           ohci_bus_resume,
269
420
 
270
421
/*-------------------------------------------------------------------------*/
271
422
 
 
423
static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
 
424
{
 
425
        struct platform_device *pdev = data;
 
426
        struct at91_usbh_data *pdata = pdev->dev.platform_data;
 
427
        int val, gpio, port;
 
428
 
 
429
        /* From the GPIO notifying the over-current situation, find
 
430
         * out the corresponding port */
 
431
        gpio = irq_to_gpio(irq);
 
432
        for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
 
433
                if (pdata->overcurrent_pin[port] == gpio)
 
434
                        break;
 
435
        }
 
436
 
 
437
        if (port == ARRAY_SIZE(pdata->overcurrent_pin)) {
 
438
                dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n");
 
439
                return IRQ_HANDLED;
 
440
        }
 
441
 
 
442
        val = gpio_get_value(gpio);
 
443
 
 
444
        /* When notified of an over-current situation, disable power
 
445
           on the corresponding port, and mark this port in
 
446
           over-current. */
 
447
        if (! val) {
 
448
                ohci_at91_usb_set_power(pdata, port, 0);
 
449
                pdata->overcurrent_status[port]  = 1;
 
450
                pdata->overcurrent_changed[port] = 1;
 
451
        }
 
452
 
 
453
        dev_dbg(& pdev->dev, "overcurrent situation %s\n",
 
454
                val ? "exited" : "notified");
 
455
 
 
456
        return IRQ_HANDLED;
 
457
}
 
458
 
 
459
/*-------------------------------------------------------------------------*/
 
460
 
272
461
static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
273
462
{
274
463
        struct at91_usbh_data   *pdata = pdev->dev.platform_data;
275
464
        int                     i;
276
465
 
277
466
        if (pdata) {
278
 
                /* REVISIT make the driver support per-port power switching,
279
 
                 * and also overcurrent detection.  Here we assume the ports
280
 
                 * are always powered while this driver is active, and use
281
 
                 * active-low power switches.
282
 
                 */
283
467
                for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
284
468
                        if (pdata->vbus_pin[i] <= 0)
285
469
                                continue;
286
470
                        gpio_request(pdata->vbus_pin[i], "ohci_vbus");
287
 
                        gpio_direction_output(pdata->vbus_pin[i], 0);
 
471
                        ohci_at91_usb_set_power(pdata, i, 1);
 
472
                }
 
473
 
 
474
                for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
 
475
                        int ret;
 
476
 
 
477
                        if (pdata->overcurrent_pin[i] <= 0)
 
478
                                continue;
 
479
                        gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent");
 
480
 
 
481
                        ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]),
 
482
                                          ohci_hcd_at91_overcurrent_irq,
 
483
                                          IRQF_SHARED, "ohci_overcurrent", pdev);
 
484
                        if (ret) {
 
485
                                gpio_free(pdata->overcurrent_pin[i]);
 
486
                                dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n");
 
487
                        }
288
488
                }
289
489
        }
290
490
 
301
501
                for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
302
502
                        if (pdata->vbus_pin[i] <= 0)
303
503
                                continue;
304
 
                        gpio_direction_output(pdata->vbus_pin[i], 1);
 
504
                        ohci_at91_usb_set_power(pdata, i, 0);
305
505
                        gpio_free(pdata->vbus_pin[i]);
306
506
                }
 
507
 
 
508
                for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
 
509
                        if (pdata->overcurrent_pin[i] <= 0)
 
510
                                continue;
 
511
                        free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev);
 
512
                        gpio_free(pdata->overcurrent_pin[i]);
 
513
                }
307
514
        }
308
515
 
309
516
        device_init_wakeup(&pdev->dev, 0);