diff options
Diffstat (limited to 'drivers/usb/host/ehci-tegra.c')
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 69 |
1 files changed, 26 insertions, 43 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 87e271b9c157..4a44bf833611 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c | |||
@@ -147,18 +147,7 @@ static int tegra_ehci_hub_control( | |||
147 | 147 | ||
148 | spin_lock_irqsave(&ehci->lock, flags); | 148 | spin_lock_irqsave(&ehci->lock, flags); |
149 | 149 | ||
150 | /* | 150 | if (typeReq == GetPortStatus) { |
151 | * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits | ||
152 | * that are write on clear, by writing back the register read value, so | ||
153 | * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits | ||
154 | */ | ||
155 | if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) { | ||
156 | temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS; | ||
157 | ehci_writel(ehci, temp & ~PORT_PE, status_reg); | ||
158 | goto done; | ||
159 | } | ||
160 | |||
161 | else if (typeReq == GetPortStatus) { | ||
162 | temp = ehci_readl(ehci, status_reg); | 151 | temp = ehci_readl(ehci, status_reg); |
163 | if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { | 152 | if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { |
164 | /* Resume completed, re-enable disconnect detection */ | 153 | /* Resume completed, re-enable disconnect detection */ |
@@ -174,7 +163,7 @@ static int tegra_ehci_hub_control( | |||
174 | goto done; | 163 | goto done; |
175 | } | 164 | } |
176 | 165 | ||
177 | temp &= ~PORT_WKCONN_E; | 166 | temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E); |
178 | temp |= PORT_WKDISC_E | PORT_WKOC_E; | 167 | temp |= PORT_WKDISC_E | PORT_WKOC_E; |
179 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); | 168 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); |
180 | 169 | ||
@@ -319,26 +308,23 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) | |||
319 | return retval; | 308 | return retval; |
320 | } | 309 | } |
321 | 310 | ||
322 | struct temp_buffer { | 311 | struct dma_aligned_buffer { |
323 | void *kmalloc_ptr; | 312 | void *kmalloc_ptr; |
324 | void *old_xfer_buffer; | 313 | void *old_xfer_buffer; |
325 | u8 data[0]; | 314 | u8 data[0]; |
326 | }; | 315 | }; |
327 | 316 | ||
328 | static void free_temp_buffer(struct urb *urb) | 317 | static void free_dma_aligned_buffer(struct urb *urb) |
329 | { | 318 | { |
330 | enum dma_data_direction dir; | 319 | struct dma_aligned_buffer *temp; |
331 | struct temp_buffer *temp; | ||
332 | 320 | ||
333 | if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) | 321 | if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) |
334 | return; | 322 | return; |
335 | 323 | ||
336 | dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | 324 | temp = container_of(urb->transfer_buffer, |
337 | 325 | struct dma_aligned_buffer, data); | |
338 | temp = container_of(urb->transfer_buffer, struct temp_buffer, | ||
339 | data); | ||
340 | 326 | ||
341 | if (dir == DMA_FROM_DEVICE) | 327 | if (usb_urb_dir_in(urb)) |
342 | memcpy(temp->old_xfer_buffer, temp->data, | 328 | memcpy(temp->old_xfer_buffer, temp->data, |
343 | urb->transfer_buffer_length); | 329 | urb->transfer_buffer_length); |
344 | urb->transfer_buffer = temp->old_xfer_buffer; | 330 | urb->transfer_buffer = temp->old_xfer_buffer; |
@@ -347,10 +333,9 @@ static void free_temp_buffer(struct urb *urb) | |||
347 | urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; | 333 | urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; |
348 | } | 334 | } |
349 | 335 | ||
350 | static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) | 336 | static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) |
351 | { | 337 | { |
352 | enum dma_data_direction dir; | 338 | struct dma_aligned_buffer *temp, *kmalloc_ptr; |
353 | struct temp_buffer *temp, *kmalloc_ptr; | ||
354 | size_t kmalloc_size; | 339 | size_t kmalloc_size; |
355 | 340 | ||
356 | if (urb->num_sgs || urb->sg || | 341 | if (urb->num_sgs || urb->sg || |
@@ -358,22 +343,19 @@ static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) | |||
358 | !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1))) | 343 | !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1))) |
359 | return 0; | 344 | return 0; |
360 | 345 | ||
361 | dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | ||
362 | |||
363 | /* Allocate a buffer with enough padding for alignment */ | 346 | /* Allocate a buffer with enough padding for alignment */ |
364 | kmalloc_size = urb->transfer_buffer_length + | 347 | kmalloc_size = urb->transfer_buffer_length + |
365 | sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1; | 348 | sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1; |
366 | 349 | ||
367 | kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); | 350 | kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); |
368 | if (!kmalloc_ptr) | 351 | if (!kmalloc_ptr) |
369 | return -ENOMEM; | 352 | return -ENOMEM; |
370 | 353 | ||
371 | /* Position our struct temp_buffer such that data is aligned */ | 354 | /* Position our struct dma_aligned_buffer such that data is aligned */ |
372 | temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1; | 355 | temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1; |
373 | |||
374 | temp->kmalloc_ptr = kmalloc_ptr; | 356 | temp->kmalloc_ptr = kmalloc_ptr; |
375 | temp->old_xfer_buffer = urb->transfer_buffer; | 357 | temp->old_xfer_buffer = urb->transfer_buffer; |
376 | if (dir == DMA_TO_DEVICE) | 358 | if (usb_urb_dir_out(urb)) |
377 | memcpy(temp->data, urb->transfer_buffer, | 359 | memcpy(temp->data, urb->transfer_buffer, |
378 | urb->transfer_buffer_length); | 360 | urb->transfer_buffer_length); |
379 | urb->transfer_buffer = temp->data; | 361 | urb->transfer_buffer = temp->data; |
@@ -388,13 +370,13 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | |||
388 | { | 370 | { |
389 | int ret; | 371 | int ret; |
390 | 372 | ||
391 | ret = alloc_temp_buffer(urb, mem_flags); | 373 | ret = alloc_dma_aligned_buffer(urb, mem_flags); |
392 | if (ret) | 374 | if (ret) |
393 | return ret; | 375 | return ret; |
394 | 376 | ||
395 | ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); | 377 | ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); |
396 | if (ret) | 378 | if (ret) |
397 | free_temp_buffer(urb); | 379 | free_dma_aligned_buffer(urb); |
398 | 380 | ||
399 | return ret; | 381 | return ret; |
400 | } | 382 | } |
@@ -402,38 +384,39 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | |||
402 | static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) | 384 | static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) |
403 | { | 385 | { |
404 | usb_hcd_unmap_urb_for_dma(hcd, urb); | 386 | usb_hcd_unmap_urb_for_dma(hcd, urb); |
405 | free_temp_buffer(urb); | 387 | free_dma_aligned_buffer(urb); |
406 | } | 388 | } |
407 | 389 | ||
408 | static const struct hc_driver tegra_ehci_hc_driver = { | 390 | static const struct hc_driver tegra_ehci_hc_driver = { |
409 | .description = hcd_name, | 391 | .description = hcd_name, |
410 | .product_desc = "Tegra EHCI Host Controller", | 392 | .product_desc = "Tegra EHCI Host Controller", |
411 | .hcd_priv_size = sizeof(struct ehci_hcd), | 393 | .hcd_priv_size = sizeof(struct ehci_hcd), |
412 | |||
413 | .flags = HCD_USB2 | HCD_MEMORY, | 394 | .flags = HCD_USB2 | HCD_MEMORY, |
414 | 395 | ||
415 | .reset = tegra_ehci_setup, | 396 | /* standard ehci functions */ |
416 | .irq = ehci_irq, | 397 | .irq = ehci_irq, |
417 | |||
418 | .start = ehci_run, | 398 | .start = ehci_run, |
419 | .stop = ehci_stop, | 399 | .stop = ehci_stop, |
420 | .shutdown = tegra_ehci_shutdown, | ||
421 | .urb_enqueue = ehci_urb_enqueue, | 400 | .urb_enqueue = ehci_urb_enqueue, |
422 | .urb_dequeue = ehci_urb_dequeue, | 401 | .urb_dequeue = ehci_urb_dequeue, |
423 | .map_urb_for_dma = tegra_ehci_map_urb_for_dma, | ||
424 | .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, | ||
425 | .endpoint_disable = ehci_endpoint_disable, | 402 | .endpoint_disable = ehci_endpoint_disable, |
426 | .endpoint_reset = ehci_endpoint_reset, | 403 | .endpoint_reset = ehci_endpoint_reset, |
427 | .get_frame_number = ehci_get_frame, | 404 | .get_frame_number = ehci_get_frame, |
428 | .hub_status_data = ehci_hub_status_data, | 405 | .hub_status_data = ehci_hub_status_data, |
429 | .hub_control = tegra_ehci_hub_control, | ||
430 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | 406 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
407 | .relinquish_port = ehci_relinquish_port, | ||
408 | .port_handed_over = ehci_port_handed_over, | ||
409 | |||
410 | /* modified ehci functions for tegra */ | ||
411 | .reset = tegra_ehci_setup, | ||
412 | .shutdown = tegra_ehci_shutdown, | ||
413 | .map_urb_for_dma = tegra_ehci_map_urb_for_dma, | ||
414 | .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, | ||
415 | .hub_control = tegra_ehci_hub_control, | ||
431 | #ifdef CONFIG_PM | 416 | #ifdef CONFIG_PM |
432 | .bus_suspend = ehci_bus_suspend, | 417 | .bus_suspend = ehci_bus_suspend, |
433 | .bus_resume = ehci_bus_resume, | 418 | .bus_resume = ehci_bus_resume, |
434 | #endif | 419 | #endif |
435 | .relinquish_port = ehci_relinquish_port, | ||
436 | .port_handed_over = ehci_port_handed_over, | ||
437 | }; | 420 | }; |
438 | 421 | ||
439 | static int setup_vbus_gpio(struct platform_device *pdev, | 422 | static int setup_vbus_gpio(struct platform_device *pdev, |