From 968b822c0023861ef6e4e15bb68582b36e89ad29 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 3 Nov 2011 12:03:38 -0400 Subject: USB: Remove the SAW_IRQ hcd flag The HCD_FLAG_SAW_IRQ flag was introduced in order to catch IRQ routing errors: If an URB was unlinked and the host controller hadn't gotten any IRQs, it seemed likely that the IRQs were directed to the wrong vector. This warning hasn't come up in many years, as far as I know; interrupt routing now seems to be well under control. Therefore there's no reason to keep the flag around any more. This patch (as1495) finally removes it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/hcd.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 03354d557b79..b2f62f3a32af 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -99,7 +99,6 @@ struct usb_hcd { */ unsigned long flags; #define HCD_FLAG_HW_ACCESSIBLE 0 /* at full power */ -#define HCD_FLAG_SAW_IRQ 1 #define HCD_FLAG_POLL_RH 2 /* poll for rh status? */ #define HCD_FLAG_POLL_PENDING 3 /* status has changed? */ #define HCD_FLAG_WAKEUP_PENDING 4 /* root hub is resuming? */ @@ -110,7 +109,6 @@ struct usb_hcd { * be slightly faster than test_bit(). */ #define HCD_HW_ACCESSIBLE(hcd) ((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE)) -#define HCD_SAW_IRQ(hcd) ((hcd)->flags & (1U << HCD_FLAG_SAW_IRQ)) #define HCD_POLL_RH(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_RH)) #define HCD_POLL_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING)) #define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING)) -- cgit v1.2.3 From 4556143cab73e013d0c3fa00f0f4f4373882399e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 6 Nov 2011 19:06:25 +0100 Subject: USB: serial: remove write_urb_busy field from usb_serial_port Remove no longer used write_urb_busy field from struct usb_serial_port. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/serial.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index b29f70b2ecae..8ccd405e9005 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -62,7 +62,6 @@ enum port_dev_state { * @bulk_out_size: the size of the bulk_out_buffer, in bytes. * @write_urb: pointer to the bulk out struct urb for this port. * @write_fifo: kfifo used to buffer outgoing data - * @write_urb_busy: port`s writing status * @bulk_out_buffers: pointers to the bulk out buffers for this port * @write_urbs: pointers to the bulk out urbs for this port * @write_urbs_free: status bitmap the for bulk out urbs @@ -103,7 +102,6 @@ struct usb_serial_port { int bulk_out_size; struct urb *write_urb; struct kfifo write_fifo; - int write_urb_busy; unsigned char *bulk_out_buffers[2]; struct urb *write_urbs[2]; -- cgit v1.2.3 From d83b405383c965498923f3561c3321e2b5df5727 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 6 Nov 2011 19:06:37 +0100 Subject: USB: serial: add support for multiple read urbs Add support for multiple read urbs to generic read implementation. Use a static array of two read urbs for now which is enough to get a 50% throughput increase in one test setup. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 83 ++++++++++++++++++++++++++++++----------- drivers/usb/serial/usb-serial.c | 50 +++++++++++++++---------- include/linux/usb/serial.h | 9 ++++- 3 files changed, 101 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index e4db5ad2bc55..f7403576f99f 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -1,7 +1,7 @@ /* * USB Serial Converter Generic functions * - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or @@ -132,7 +132,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port /* if we have a bulk endpoint, start reading from it */ if (port->bulk_in_size) - result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); + result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); return result; } @@ -157,8 +157,10 @@ static void generic_cleanup(struct usb_serial_port *port) kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); } - if (port->bulk_in_size) - usb_kill_urb(port->read_urb); + if (port->bulk_in_size) { + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) + usb_kill_urb(port->read_urbs[i]); + } } } @@ -308,19 +310,52 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) return chars; } -int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, +static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, + int index, gfp_t mem_flags) +{ + int res; + + if (!test_and_clear_bit(index, &port->read_urbs_free)) + return 0; + + dbg("%s - port %d, urb %d\n", __func__, port->number, index); + + res = usb_submit_urb(port->read_urbs[index], mem_flags); + if (res) { + if (res != -EPERM) { + dev_err(&port->dev, + "%s - usb_submit_urb failed: %d\n", + __func__, res); + } + set_bit(index, &port->read_urbs_free); + return res; + } + + return 0; +} + +int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, gfp_t mem_flags) { - int result; + int res; + int i; - result = usb_submit_urb(port->read_urb, mem_flags); - if (result && result != -EPERM) { - dev_err(&port->dev, "%s - error submitting urb: %d\n", - __func__, result); + dbg("%s - port %d", __func__, port->number); + + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { + res = usb_serial_generic_submit_read_urb(port, i, mem_flags); + if (res) + goto err; } - return result; + + return 0; +err: + for (; i >= 0; --i) + usb_kill_urb(port->read_urbs[i]); + + return res; } -EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); +EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs); void usb_serial_generic_process_read_urb(struct urb *urb) { @@ -356,14 +391,19 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; - int status = urb->status; unsigned long flags; + int i; - dbg("%s - port %d", __func__, port->number); + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { + if (urb == port->read_urbs[i]) + break; + } + set_bit(i, &port->read_urbs_free); - if (unlikely(status != 0)) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i, + urb->actual_length); + if (urb->status) { + dbg("%s - non-zero urb status: %d\n", __func__, urb->status); return; } @@ -376,7 +416,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) port->throttled = port->throttle_req; if (!port->throttled) { spin_unlock_irqrestore(&port->lock, flags); - usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); + usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); } else spin_unlock_irqrestore(&port->lock, flags); } @@ -443,7 +483,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) spin_unlock_irq(&port->lock); if (was_throttled) - usb_serial_generic_submit_read_urb(port, GFP_KERNEL); + usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); } EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); @@ -509,8 +549,9 @@ int usb_serial_generic_resume(struct usb_serial *serial) if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) continue; - if (port->read_urb) { - r = usb_submit_urb(port->read_urb, GFP_NOIO); + if (port->bulk_in_size) { + r = usb_serial_generic_submit_read_urbs(port, + GFP_NOIO); if (r < 0) c++; } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bfbe6e5431d3..8d5190f3d8eb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -562,7 +562,8 @@ static void kill_traffic(struct usb_serial_port *port) { int i; - usb_kill_urb(port->read_urb); + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) + usb_kill_urb(port->read_urbs[i]); for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) usb_kill_urb(port->write_urbs[i]); /* @@ -594,15 +595,17 @@ static void port_release(struct device *dev) kill_traffic(port); cancel_work_sync(&port->work); - usb_free_urb(port->read_urb); usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { + usb_free_urb(port->read_urbs[i]); + kfree(port->bulk_in_buffers[i]); + } for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { usb_free_urb(port->write_urbs[i]); kfree(port->bulk_out_buffers[i]); } kfifo_free(&port->write_fifo); - kfree(port->bulk_in_buffer); kfree(port->interrupt_in_buffer); kfree(port->interrupt_out_buffer); kfree(port); @@ -721,6 +724,7 @@ int usb_serial_probe(struct usb_interface *interface, unsigned int minor; int buffer_size; int i; + int j; int num_interrupt_in = 0; int num_interrupt_out = 0; int num_bulk_in = 0; @@ -903,31 +907,39 @@ int usb_serial_probe(struct usb_interface *interface, for (i = 0; i < num_bulk_in; ++i) { endpoint = bulk_in_endpoint[i]; port = serial->port[i]; - port->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->read_urb) { - dev_err(&interface->dev, "No free urbs available\n"); - goto probe_error; - } buffer_size = max_t(int, serial->type->bulk_in_size, usb_endpoint_maxp(endpoint)); port->bulk_in_size = buffer_size; port->bulk_in_endpointAddress = endpoint->bEndpointAddress; - port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_in_buffer) { - dev_err(&interface->dev, + + for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) { + set_bit(j, &port->read_urbs_free); + port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); + if (!port->read_urbs[j]) { + dev_err(&interface->dev, + "No free urbs available\n"); + goto probe_error; + } + port->bulk_in_buffers[j] = kmalloc(buffer_size, + GFP_KERNEL); + if (!port->bulk_in_buffers[j]) { + dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n"); - goto probe_error; - } - usb_fill_bulk_urb(port->read_urb, dev, - usb_rcvbulkpipe(dev, + goto probe_error; + } + usb_fill_bulk_urb(port->read_urbs[j], dev, + usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), - port->bulk_in_buffer, buffer_size, - serial->type->read_bulk_callback, port); + port->bulk_in_buffers[j], buffer_size, + serial->type->read_bulk_callback, + port); + } + + port->read_urb = port->read_urbs[0]; + port->bulk_in_buffer = port->bulk_in_buffers[0]; } for (i = 0; i < num_bulk_out; ++i) { - int j; - endpoint = bulk_out_endpoint[i]; port = serial->port[i]; if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 8ccd405e9005..4267a9c717ba 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -58,6 +58,9 @@ enum port_dev_state { * @read_urb: pointer to the bulk in struct urb for this port. * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this * port. + * @bulk_in_buffers: pointers to the bulk in buffers for this port + * @read_urbs: pointers to the bulk in urbs for this port + * @read_urbs_free: status bitmap the for bulk in urbs * @bulk_out_buffer: pointer to the bulk out buffer for this port. * @bulk_out_size: the size of the bulk_out_buffer, in bytes. * @write_urb: pointer to the bulk out struct urb for this port. @@ -98,6 +101,10 @@ struct usb_serial_port { struct urb *read_urb; __u8 bulk_in_endpointAddress; + unsigned char *bulk_in_buffers[2]; + struct urb *read_urbs[2]; + unsigned long read_urbs_free; + unsigned char *bulk_out_buffer; int bulk_out_size; struct urb *write_urb; @@ -338,7 +345,7 @@ extern void usb_serial_generic_disconnect(struct usb_serial *serial); extern void usb_serial_generic_release(struct usb_serial *serial); extern int usb_serial_generic_register(int debug); extern void usb_serial_generic_deregister(void); -extern int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, +extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, gfp_t mem_flags); extern void usb_serial_generic_process_read_urb(struct urb *urb); extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, -- cgit v1.2.3 From 2c4d6bf295ae10ffcd84f0df6cb642598eb66603 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 10 Nov 2011 14:58:26 +0100 Subject: USB: move usb_translate_errors to linux/usb.h Move usb_translate_errors from usb core to linux/usb.h as it is meant to be accessed from drivers. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.h | 14 -------------- include/linux/usb.h | 13 +++++++++++++ 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 3888778582c4..45e8479c377d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -132,20 +132,6 @@ static inline int is_usb_device_driver(struct device_driver *drv) for_devices; } -/* translate USB error codes to codes user space understands */ -static inline int usb_translate_errors(int error_code) -{ - switch (error_code) { - case 0: - case -ENOMEM: - case -ENODEV: - return error_code; - default: - return -EIO; - } -} - - /* for labeling diagnostics */ extern const char *usbcore_name; diff --git a/include/linux/usb.h b/include/linux/usb.h index d3d0c1374334..2f05a7fa1ecf 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1598,6 +1598,19 @@ usb_maxpacket(struct usb_device *udev, int pipe, int is_out) /* ----------------------------------------------------------------------- */ +/* translate USB error codes to codes user space understands */ +static inline int usb_translate_errors(int error_code) +{ + switch (error_code) { + case 0: + case -ENOMEM: + case -ENODEV: + return error_code; + default: + return -EIO; + } +} + /* Events from the usb core */ #define USB_DEVICE_ADD 0x0001 #define USB_DEVICE_REMOVE 0x0002 -- cgit v1.2.3 From 0720a06a7518c9d0c0125bd5d1f3b6264c55c3dd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Nov 2011 16:42:19 -0500 Subject: NLS: improve UTF8 -> UTF16 string conversion routine The utf8s_to_utf16s conversion routine needs to be improved. Unlike its utf16s_to_utf8s sibling, it doesn't accept arguments specifying the maximum length of the output buffer or the endianness of its 16-bit output. This patch (as1501) adds the two missing arguments, and adjusts the only two places in the kernel where the function is called. A follow-on patch will add a third caller that does utilize the new capabilities. The two conversion routines are still annoyingly inconsistent in the way they handle invalid byte combinations. But that's a subject for a different patch. Signed-off-by: Alan Stern CC: Clemens Ladisch Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_kvp.c | 10 ++++++---- fs/fat/namei_vfat.c | 3 ++- fs/nls/nls_base.c | 43 +++++++++++++++++++++++++++++++++---------- include/linux/nls.h | 5 +++-- 4 files changed, 44 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 89f52440fcf4..0e8343f585bb 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -212,11 +212,13 @@ kvp_respond_to_host(char *key, char *value, int error) * The windows host expects the key/value pair to be encoded * in utf16. */ - keylen = utf8s_to_utf16s(key_name, strlen(key_name), - (wchar_t *)kvp_data->data.key); + keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN, + (wchar_t *) kvp_data->data.key, + HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2); kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */ - valuelen = utf8s_to_utf16s(value, strlen(value), - (wchar_t *)kvp_data->data.value); + valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, + (wchar_t *) kvp_data->data.value, + HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2); kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */ kvp_data->data.value_type = REG_SZ; /* all our values are strings */ diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index a87a65663c25..c25cf151b84b 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -512,7 +512,8 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, int charlen; if (utf8) { - *outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname); + *outlen = utf8s_to_utf16s(name, len, UTF16_HOST_ENDIAN, + (wchar_t *) outname, FAT_LFN_LEN + 2); if (*outlen < 0) return *outlen; else if (*outlen > FAT_LFN_LEN) diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 44a88a9fa2c8..0eb059ec6f28 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -114,34 +114,57 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxlen) } EXPORT_SYMBOL(utf32_to_utf8); -int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs) +static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian) +{ + switch (endian) { + default: + *s = (wchar_t) c; + break; + case UTF16_LITTLE_ENDIAN: + *s = __cpu_to_le16(c); + break; + case UTF16_BIG_ENDIAN: + *s = __cpu_to_be16(c); + break; + } +} + +int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian, + wchar_t *pwcs, int maxlen) { u16 *op; int size; unicode_t u; op = pwcs; - while (*s && len > 0) { + while (len > 0 && maxlen > 0 && *s) { if (*s & 0x80) { size = utf8_to_utf32(s, len, &u); if (size < 0) return -EINVAL; + s += size; + len -= size; if (u >= PLANE_SIZE) { + if (maxlen < 2) + break; u -= PLANE_SIZE; - *op++ = (wchar_t) (SURROGATE_PAIR | - ((u >> 10) & SURROGATE_BITS)); - *op++ = (wchar_t) (SURROGATE_PAIR | + put_utf16(op++, SURROGATE_PAIR | + ((u >> 10) & SURROGATE_BITS), + endian); + put_utf16(op++, SURROGATE_PAIR | SURROGATE_LOW | - (u & SURROGATE_BITS)); + (u & SURROGATE_BITS), + endian); + maxlen -= 2; } else { - *op++ = (wchar_t) u; + put_utf16(op++, u, endian); + maxlen--; } - s += size; - len -= size; } else { - *op++ = *s++; + put_utf16(op++, *s++, endian); len--; + maxlen--; } } return op - pwcs; diff --git a/include/linux/nls.h b/include/linux/nls.h index d47beef08dfd..5dc635f8d79e 100644 --- a/include/linux/nls.h +++ b/include/linux/nls.h @@ -43,7 +43,7 @@ enum utf16_endian { UTF16_BIG_ENDIAN }; -/* nls.c */ +/* nls_base.c */ extern int register_nls(struct nls_table *); extern int unregister_nls(struct nls_table *); extern struct nls_table *load_nls(char *); @@ -52,7 +52,8 @@ extern struct nls_table *load_nls_default(void); extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu); extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen); -extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs); +extern int utf8s_to_utf16s(const u8 *s, int len, + enum utf16_endian endian, wchar_t *pwcs, int maxlen); extern int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian, u8 *s, int maxlen); -- cgit v1.2.3 From c8421147926fcacf53081a36438a0bed394da9f5 Mon Sep 17 00:00:00 2001 From: Aman Deep Date: Tue, 22 Nov 2011 19:33:36 +0530 Subject: xHCI: Adding #define values used for hub descriptor xhci-hub used some numerical values for initialisation of root hub descriptors. #define values are addded in usb 2.0 hub specification file and these values are used for root hub characteristics initialisation. Also use some #defines in places where magic numbers are being used. Signed-off-by: Aman Deep Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 18 ++++++++---------- include/linux/usb/ch11.h | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 430e88fd3f6c..35e257f79c7b 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -57,17 +57,15 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, desc->bHubContrCurrent = 0; desc->bNbrPorts = ports; - /* Ugh, these should be #defines, FIXME */ - /* Using table 11-13 in USB 2.0 spec. */ temp = 0; - /* Bits 1:0 - support port power switching, or power always on */ + /* Bits 1:0 - support per-port power switching, or power always on */ if (HCC_PPC(xhci->hcc_params)) - temp |= 0x0001; + temp |= HUB_CHAR_INDV_PORT_LPSM; else - temp |= 0x0002; + temp |= HUB_CHAR_NO_LPSM; /* Bit 2 - root hubs are not part of a compound device */ /* Bits 4:3 - individual port over current protection */ - temp |= 0x0008; + temp |= HUB_CHAR_INDV_PORT_OCPM; /* Bits 6:5 - no TTs in root ports */ /* Bit 7 - no port indicators */ desc->wHubCharacteristics = cpu_to_le16(temp); @@ -86,9 +84,9 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, ports = xhci->num_usb2_ports; xhci_common_hub_descriptor(xhci, desc, ports); - desc->bDescriptorType = 0x29; + desc->bDescriptorType = USB_DT_HUB; temp = 1 + (ports / 8); - desc->bDescLength = 7 + 2 * temp; + desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp; /* The Device Removable bits are reported on a byte granularity. * If the port doesn't exist within that byte, the bit is set to 0. @@ -137,8 +135,8 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, ports = xhci->num_usb3_ports; xhci_common_hub_descriptor(xhci, desc, ports); - desc->bDescriptorType = 0x2a; - desc->bDescLength = 12; + desc->bDescriptorType = USB_DT_SS_HUB; + desc->bDescLength = USB_DT_SS_HUB_SIZE; /* header decode latency should be zero for roothubs, * see section 4.23.5.2. diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h index 4ebaf0824179..55e7325926c1 100644 --- a/include/linux/usb/ch11.h +++ b/include/linux/usb/ch11.h @@ -165,11 +165,20 @@ struct usb_port_status { * wHubCharacteristics (masks) * See USB 2.0 spec Table 11-13, offset 3 */ -#define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */ -#define HUB_CHAR_COMPOUND 0x0004 /* D2 */ -#define HUB_CHAR_OCPM 0x0018 /* D4 .. D3 */ -#define HUB_CHAR_TTTT 0x0060 /* D6 .. D5 */ -#define HUB_CHAR_PORTIND 0x0080 /* D7 */ +#define HUB_CHAR_LPSM 0x0003 /* Logical Power Switching Mode mask */ +#define HUB_CHAR_COMMON_LPSM 0x0000 /* All ports power control at once */ +#define HUB_CHAR_INDV_PORT_LPSM 0x0001 /* per-port power control */ +#define HUB_CHAR_NO_LPSM 0x0002 /* no power switching */ + +#define HUB_CHAR_COMPOUND 0x0004 /* hub is part of a compound device */ + +#define HUB_CHAR_OCPM 0x0018 /* Over-Current Protection Mode mask */ +#define HUB_CHAR_COMMON_OCPM 0x0000 /* All ports Over-Current reporting */ +#define HUB_CHAR_INDV_PORT_OCPM 0x0008 /* per-port Over-current reporting */ +#define HUB_CHAR_NO_OCPM 0x0010 /* No Over-current Protection support */ + +#define HUB_CHAR_TTTT 0x0060 /* TT Think Time mask */ +#define HUB_CHAR_PORTIND 0x0080 /* per-port indicators (LEDs) */ struct usb_hub_status { __le16 wHubStatus; -- cgit v1.2.3 From bc677d5b64644c399cd3db6a905453e611f402ab Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sat, 3 Dec 2011 23:41:31 +0100 Subject: usb: fix number of mapped SG DMA entries Add a new field num_mapped_sgs to struct urb so that we have a place to store the number of mapped entries and can also retain the original value of entries in num_sgs. Previously, usb_hcd_map_urb_for_dma() would overwrite this with the number of mapped entries, which would break dma_unmap_sg() because it requires the original number of entries. This fixes warnings like the following when using USB storage devices: ------------[ cut here ]------------ WARNING: at lib/dma-debug.c:902 check_unmap+0x4e4/0x695() ehci_hcd 0000:00:12.2: DMA-API: device driver frees DMA sg list with different entry count [map count=4] [unmap count=1] Modules linked in: ohci_hcd ehci_hcd Pid: 0, comm: kworker/0:1 Not tainted 3.2.0-rc2+ #319 Call Trace: [] warn_slowpath_common+0x80/0x98 [] warn_slowpath_fmt+0x41/0x43 [] check_unmap+0x4e4/0x695 [] ? trace_hardirqs_off+0xd/0xf [] ? _raw_spin_unlock_irqrestore+0x33/0x50 [] debug_dma_unmap_sg+0xeb/0x117 [] usb_hcd_unmap_urb_for_dma+0x71/0x188 [] unmap_urb_for_dma+0x20/0x22 [] usb_hcd_giveback_urb+0x5d/0xc0 [] ehci_urb_done+0xf7/0x10c [ehci_hcd] [] qh_completions+0x429/0x4bd [ehci_hcd] [] ehci_work+0x95/0x9c0 [ehci_hcd] ... ---[ end trace f29ac88a5a48c580 ]--- Mapped at: [] debug_dma_map_sg+0x45/0x139 [] usb_hcd_map_urb_for_dma+0x22e/0x478 [] usb_hcd_submit_urb+0x63f/0x6fa [] usb_submit_urb+0x2c7/0x2de [] usb_sg_wait+0x55/0x161 Signed-off-by: Clemens Ladisch Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 ++--- drivers/usb/host/ehci-q.c | 2 +- drivers/usb/host/uhci-q.c | 2 +- drivers/usb/host/whci/qset.c | 4 ++-- drivers/usb/host/xhci-ring.c | 4 ++-- include/linux/usb.h | 1 + 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 43a89e4ba928..2cec49d1773d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1398,11 +1398,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_SG; - if (n != urb->num_sgs) { - urb->num_sgs = n; + urb->num_mapped_sgs = n; + if (n != urb->num_sgs) urb->transfer_flags |= URB_DMA_SG_COMBINED; - } } else if (urb->sg) { struct scatterlist *sg = urb->sg; urb->transfer_dma = dma_map_page( diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index f136f7f1c4f4..36ca5077cdf7 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -658,7 +658,7 @@ qh_urb_transaction ( /* * data transfer stage: buffer setup */ - i = urb->num_sgs; + i = urb->num_mapped_sgs; if (len > 0 && i > 0) { sg = urb->sg; buf = sg_dma_address(sg); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index f6ca80ee4cec..d2c6f5ac4626 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -943,7 +943,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, if (usb_pipein(urb->pipe)) status |= TD_CTRL_SPD; - i = urb->num_sgs; + i = urb->num_mapped_sgs; if (len > 0 && i > 0) { sg = urb->sg; data = sg_dma_address(sg); diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index d6e175428618..a91712c8bff5 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -443,7 +443,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u remaining = urb->transfer_buffer_length; - for_each_sg(urb->sg, sg, urb->num_sgs, i) { + for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) { dma_addr_t dma_addr; size_t dma_remaining; dma_addr_t sp, ep; @@ -561,7 +561,7 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset, remaining = urb->transfer_buffer_length; - for_each_sg(urb->sg, sg, urb->num_sgs, i) { + for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) { size_t len; size_t sg_remaining; void *orig; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 133ce302c860..d030f0b2bfa2 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2551,7 +2551,7 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) struct scatterlist *sg; sg = NULL; - num_sgs = urb->num_sgs; + num_sgs = urb->num_mapped_sgs; temp = urb->transfer_buffer_length; xhci_dbg(xhci, "count sg list trbs: \n"); @@ -2735,7 +2735,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return -EINVAL; num_trbs = count_sg_trbs_needed(xhci, urb); - num_sgs = urb->num_sgs; + num_sgs = urb->num_mapped_sgs; total_packet_count = roundup(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); diff --git a/include/linux/usb.h b/include/linux/usb.h index 2f05a7fa1ecf..4269c3f88148 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1221,6 +1221,7 @@ struct urb { void *transfer_buffer; /* (in) associated data buffer */ dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ struct scatterlist *sg; /* (in) scatter gather buffer list */ + int num_mapped_sgs; /* (internal) mapped sg entries */ int num_sgs; /* (in) number of entries in the sg list */ u32 transfer_buffer_length; /* (in) data buffer length */ u32 actual_length; /* (return) actual transfer length */ -- cgit v1.2.3 From 7bf01185c5e9ec19f739f7208646dc2e2cf1904b Mon Sep 17 00:00:00 2001 From: Aman Deep Date: Thu, 8 Dec 2011 12:05:22 +0530 Subject: USB: Adding #define in hub_configure() and hcd.c file This patch is in succession of previous patch commit c8421147926fcacf53081a36438a0bed394da9f5 xHCI: Adding #define values used for hub descriptor Hub descriptors characteristics #defines values are added in hub_configure() in place of magic numbers as asked by Alan Stern. And the indentation for switch and case is changed to be same. Some #defines values are added in ch11.h for defining hub class protocols and used in hub.c and hcd.c in which magic values were used for hub class protocols. Signed-off-by: Aman Deep Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hub.c | 88 ++++++++++++++++++++++++------------------------ include/linux/usb/ch11.h | 11 ++++++ 3 files changed, 56 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2cec49d1773d..eb19cba34ac9 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -658,7 +658,7 @@ error: len > offsetof(struct usb_device_descriptor, bDeviceProtocol)) ((struct usb_device_descriptor *) ubuf)-> - bDeviceProtocol = 1; + bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT; } /* any errors get returned through the urb completion */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 29d0669227ec..79d339e2e700 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -84,7 +84,7 @@ struct usb_hub { static inline int hub_is_superspeed(struct usb_device *hdev) { - return (hdev->descriptor.bDeviceProtocol == 3); + return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); } /* Protect struct usb_device->state and ->children members @@ -1041,58 +1041,58 @@ static int hub_configure(struct usb_hub *hub, dev_dbg(hub_dev, "standalone hub\n"); switch (wHubCharacteristics & HUB_CHAR_LPSM) { - case 0x00: - dev_dbg(hub_dev, "ganged power switching\n"); - break; - case 0x01: - dev_dbg(hub_dev, "individual port power switching\n"); - break; - case 0x02: - case 0x03: - dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); - break; + case HUB_CHAR_COMMON_LPSM: + dev_dbg(hub_dev, "ganged power switching\n"); + break; + case HUB_CHAR_INDV_PORT_LPSM: + dev_dbg(hub_dev, "individual port power switching\n"); + break; + case HUB_CHAR_NO_LPSM: + case HUB_CHAR_LPSM: + dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); + break; } switch (wHubCharacteristics & HUB_CHAR_OCPM) { - case 0x00: - dev_dbg(hub_dev, "global over-current protection\n"); - break; - case 0x08: - dev_dbg(hub_dev, "individual port over-current protection\n"); - break; - case 0x10: - case 0x18: - dev_dbg(hub_dev, "no over-current protection\n"); - break; + case HUB_CHAR_COMMON_OCPM: + dev_dbg(hub_dev, "global over-current protection\n"); + break; + case HUB_CHAR_INDV_PORT_OCPM: + dev_dbg(hub_dev, "individual port over-current protection\n"); + break; + case HUB_CHAR_NO_OCPM: + case HUB_CHAR_OCPM: + dev_dbg(hub_dev, "no over-current protection\n"); + break; } spin_lock_init (&hub->tt.lock); INIT_LIST_HEAD (&hub->tt.clear_list); INIT_WORK(&hub->tt.clear_work, hub_tt_work); switch (hdev->descriptor.bDeviceProtocol) { - case 0: - break; - case 1: - dev_dbg(hub_dev, "Single TT\n"); - hub->tt.hub = hdev; - break; - case 2: - ret = usb_set_interface(hdev, 0, 1); - if (ret == 0) { - dev_dbg(hub_dev, "TT per port\n"); - hub->tt.multi = 1; - } else - dev_err(hub_dev, "Using single TT (err %d)\n", - ret); - hub->tt.hub = hdev; - break; - case 3: - /* USB 3.0 hubs don't have a TT */ - break; - default: - dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", - hdev->descriptor.bDeviceProtocol); - break; + case USB_HUB_PR_FS: + break; + case USB_HUB_PR_HS_SINGLE_TT: + dev_dbg(hub_dev, "Single TT\n"); + hub->tt.hub = hdev; + break; + case USB_HUB_PR_HS_MULTI_TT: + ret = usb_set_interface(hdev, 0, 1); + if (ret == 0) { + dev_dbg(hub_dev, "TT per port\n"); + hub->tt.multi = 1; + } else + dev_err(hub_dev, "Using single TT (err %d)\n", + ret); + hub->tt.hub = hdev; + break; + case USB_HUB_PR_SS: + /* USB 3.0 hubs don't have a TT */ + break; + default: + dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", + hdev->descriptor.bDeviceProtocol); + break; } /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h index 55e7325926c1..0832eb841a30 100644 --- a/include/linux/usb/ch11.h +++ b/include/linux/usb/ch11.h @@ -207,6 +207,17 @@ struct usb_hub_status { #define USB_DT_HUB_NONVAR_SIZE 7 #define USB_DT_SS_HUB_SIZE 12 +/* + * Hub Device descriptor + * USB Hub class device protocols + */ + +#define USB_HUB_PR_FS 0 /* Full speed hub */ +#define USB_HUB_PR_HS_NO_TT 0 /* Hi-speed hub without TT */ +#define USB_HUB_PR_HS_SINGLE_TT 1 /* Hi-speed hub with single TT */ +#define USB_HUB_PR_HS_MULTI_TT 2 /* Hi-speed hub with multiple TT */ +#define USB_HUB_PR_SS 3 /* Super speed hub */ + struct usb_hub_descriptor { __u8 bDescLength; __u8 bDescriptorType; -- cgit v1.2.3 From a49a88f108516fd5ae24e26df5a63beb847807df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:57:02 -0700 Subject: usb: gadget: renesas_usbhs: tidyup the unit of detection_delay detection_delay was assumed as msec Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 3 ++- include/linux/usb/renesas_usbhs.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 1ce32d92e720..b4cf555ce58e 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -388,7 +388,8 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) * To make sure safety context, * use workqueue for usbhs_notify_hotplug */ - schedule_delayed_work(&priv->notify_hotplug_work, delay); + schedule_delayed_work(&priv->notify_hotplug_work, + msecs_to_jiffies(delay)); return 0; } diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index e5a40c318548..c9fceb9f7690 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -118,7 +118,7 @@ struct renesas_usbhs_driver_param { * * delay time from notify_hotplug callback */ - int detection_delay; + int detection_delay; /* msec */ /* * option: -- cgit v1.2.3 From f1ee56a0004c4a5974e7a69665330b6ff818bf92 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:57:10 -0700 Subject: usb: gadget: renesas_usbhs: add platform power control function Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 7 +++++++ include/linux/usb/renesas_usbhs.h | 8 ++++++++ 2 files changed, 15 insertions(+) (limited to 'include') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index b4cf555ce58e..17bf1f74377a 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -291,18 +291,25 @@ static u32 usbhsc_default_pipe_type[] = { */ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) { + struct platform_device *pdev = usbhs_priv_to_pdev(priv); struct device *dev = usbhs_priv_to_dev(priv); if (enable) { /* enable PM */ pm_runtime_get_sync(dev); + /* enable platform power */ + usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); + /* USB on */ usbhs_sys_clock_ctrl(priv, enable); } else { /* USB off */ usbhs_sys_clock_ctrl(priv, enable); + /* disable platform power */ + usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); + /* disable PM */ pm_runtime_put_sync(dev); } diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index c9fceb9f7690..0d3f98879256 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -64,6 +64,14 @@ struct renesas_usbhs_platform_callback { */ void (*hardware_exit)(struct platform_device *pdev); + /* + * option: + * + * for board specific clock control + */ + void (*power_ctrl)(struct platform_device *pdev, + void __iomem *base, int enable); + /* * option: * -- cgit v1.2.3 From d327ab5b6d660d6fe22b073b743fde1668e593bb Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sat, 19 Nov 2011 18:27:37 +0100 Subject: usb: gadget: replace usb_gadget::is_dualspeed with max_speed This commit replaces usb_gadget's is_dualspeed field with a max_speed field. [ balbi@ti.com : Fixed DWC3 driver ] Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- Documentation/feature-removal-schedule.txt | 14 ++++++++++++++ drivers/usb/dwc3/gadget.c | 2 +- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/atmel_usba_udc.c | 2 +- drivers/usb/gadget/ci13xxx_udc.c | 7 +++++-- drivers/usb/gadget/dummy_hcd.c | 2 +- drivers/usb/gadget/epautoconf.c | 6 +++--- drivers/usb/gadget/fsl_udc_core.c | 2 +- drivers/usb/gadget/fusb300_udc.c | 2 +- drivers/usb/gadget/goku_udc.c | 1 + drivers/usb/gadget/langwell_udc.c | 2 +- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/mv_udc_core.c | 2 +- drivers/usb/gadget/net2272.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 1 + drivers/usb/gadget/pch_udc.c | 2 +- drivers/usb/gadget/printer.c | 4 ++-- drivers/usb/gadget/r8a66597-udc.c | 2 +- drivers/usb/gadget/s3c-hsotg.c | 2 +- drivers/usb/gadget/s3c-hsudc.c | 2 +- drivers/usb/gadget/udc-core.c | 26 ++++++++++++++++++++------ drivers/usb/musb/musb_gadget.c | 2 +- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- include/linux/usb/gadget.h | 10 +++++----- 25 files changed, 68 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 3d849122b5b1..a7e4ac1202d6 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -535,6 +535,20 @@ Why: In 3.0, we can now autodetect internal 3G device and already have information log when acer-wmi initial. Who: Lee, Chun-Yi +--------------------------- + +What: /sys/devices/platform/_UDC_/udc/_UDC_/is_dualspeed file and + is_dualspeed line in /sys/devices/platform/ci13xxx_*/udc/device file. +When: 3.8 +Why: The is_dualspeed file is superseded by maximum_speed in the same + directory and is_dualspeed line in device file is superseded by + max_speed line in the same file. + + The maximum_speed/max_speed specifies maximum speed supported by UDC. + To check if dualspeeed is supported, check if the value is >= 3. + Various possible speeds are defined in . +Who: Michal Nazarewicz + ---------------------------- What: The XFS nodelaylog mount option diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 25dbd8614e72..580272042a33 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1986,7 +1986,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) dev_set_name(&dwc->gadget.dev, "gadget"); dwc->gadget.ops = &dwc3_gadget_ops; - dwc->gadget.is_dualspeed = true; + dwc->gadget.max_speed = USB_SPEED_SUPER; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.dev.parent = dwc->dev; diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 45f422ac103f..e69cdbca8017 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3349,7 +3349,7 @@ static int udc_probe(struct udc *dev) dev_set_name(&dev->gadget.dev, "gadget"); dev->gadget.dev.release = gadget_release; dev->gadget.name = name; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; /* init registers, interrupts, ... */ startup_registers(dev); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 271a9d873608..e2fb6d583bd9 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1038,7 +1038,7 @@ static struct usba_udc the_udc = { .gadget = { .ops = &usba_udc_ops, .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), - .is_dualspeed = 1, + .max_speed = USB_SPEED_HIGH, .name = "atmel_usba_udc", .dev = { .init_name = "gadget", diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 8956a2448b33..9767d9170fbd 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -766,8 +766,11 @@ static ssize_t show_device(struct device *dev, struct device_attribute *attr, n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", gadget->speed); + n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", + gadget->max_speed); + /* TODO: Scheduled for removal in 3.8. */ n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", - gadget->is_dualspeed); + gadget_is_dualspeed(gadget)); n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", gadget->is_otg); n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", @@ -2880,7 +2883,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, udc->gadget.ops = &usb_gadget_ops; udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.is_dualspeed = 1; + udc->gadget.max_speed = USB_SPEED_HIGH; udc->gadget.is_otg = 0; udc->gadget.name = driver->name; diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index ab8f1b488d54..cf235d84d8b7 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -977,7 +977,7 @@ static int dummy_udc_probe (struct platform_device *pdev) dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; - dum->gadget.is_dualspeed = 1; + dum->gadget.max_speed = USB_SPEED_SUPER; dev_set_name(&dum->gadget.dev, "gadget"); dum->gadget.dev.parent = &pdev->dev; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 596a0b464e61..38bcbfb91f62 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -152,7 +152,7 @@ ep_matches ( switch (type) { case USB_ENDPOINT_XFER_INT: /* INT: limit 64 bytes full speed, 1024 high/super speed */ - if (!gadget->is_dualspeed && max > 64) + if (!gadget_is_dualspeed(gadget) && max > 64) return 0; /* FALLTHROUGH */ @@ -160,12 +160,12 @@ ep_matches ( /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ if (ep->maxpacket < max) return 0; - if (!gadget->is_dualspeed && max > 1023) + if (!gadget_is_dualspeed(gadget) && max > 1023) return 0; /* BOTH: "high bandwidth" works only at high speed */ if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) return 0; /* configure your hardware with enough buffering!! */ } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index dd28ef3def71..6de8ec753818 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2525,7 +2525,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) /* Setup gadget structure */ udc_controller->gadget.ops = &fsl_gadget_ops; - udc_controller->gadget.is_dualspeed = 1; + udc_controller->gadget.max_speed = USB_SPEED_HIGH; udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; INIT_LIST_HEAD(&udc_controller->gadget.ep_list); udc_controller->gadget.speed = USB_SPEED_UNKNOWN; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 74da206c8406..6e32a60ab3b7 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1463,7 +1463,7 @@ static int __init fusb300_probe(struct platform_device *pdev) dev_set_name(&fusb300->gadget.dev, "gadget"); - fusb300->gadget.is_dualspeed = 1; + fusb300->gadget.max_speed = USB_SPEED_HIGH; fusb300->gadget.dev.parent = &pdev->dev; fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask; fusb300->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 7f87805cddc4..ab9c924eee76 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1796,6 +1796,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&dev->lock); dev->pdev = pdev; dev->gadget.ops = &goku_ops; + dev->gadget.max_speed = USB_SPEED_FULL; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&dev->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index c9fa3bf5b377..fa0fcc11263f 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -3267,7 +3267,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */ INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */ dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - dev->gadget.is_dualspeed = 1; /* support dual speed */ + dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ #ifdef OTG_TRANSCEIVER dev->gadget.is_otg = 1; /* support otg mode */ #endif diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 9aa1cbbee45b..a7692c208ea7 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1653,7 +1653,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->gadget.ops = &m66592_gadget_ops; device_initialize(&m66592->gadget.dev); dev_set_name(&m66592->gadget.dev, "gadget"); - m66592->gadget.is_dualspeed = 1; + m66592->gadget.max_speed = USB_SPEED_HIGH; m66592->gadget.dev.parent = &pdev->dev; m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; m66592->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 892412103dd8..9376a7483c9b 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2312,7 +2312,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev) udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */ INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */ udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - udc->gadget.is_dualspeed = 1; /* support dual speed */ + udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&udc->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index d1b76368472f..d5050f4e8449 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -2235,7 +2235,7 @@ net2272_probe_init(struct device *dev, unsigned int irq) ret->irq = irq; ret->dev = dev; ret->gadget.ops = &net2272_ops; - ret->gadget.is_dualspeed = 1; + ret->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&ret->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index da2b9d0be3ca..9ee36fd5adae 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2698,7 +2698,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&dev->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 788989a10223..ed01a0f5f119 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2676,6 +2676,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) INIT_LIST_HEAD(&udc->gadget.ep_list); INIT_LIST_HEAD(&udc->iso); udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.max_speed = USB_SPEED_FULL; udc->gadget.name = driver_name; device_initialize(&udc->gadget.dev); diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 5048a0c07640..7f97b4adba3e 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2941,7 +2941,7 @@ static int pch_udc_probe(struct pci_dev *pdev, dev->gadget.dev.dma_mask = pdev->dev.dma_mask; dev->gadget.dev.release = gadget_release; dev->gadget.name = KBUILD_MODNAME; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; retval = device_register(&dev->gadget.dev); if (retval) diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 65a8834f274b..b74f49ac95e5 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1141,7 +1141,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; #ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* * assumes ep0 uses the same value for both @@ -1155,7 +1155,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* FALLTHROUGH */ #endif /* CONFIG_USB_GADGET_DUALSPEED */ diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index fc719a3f8557..3666d7c54e24 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1911,7 +1911,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->gadget.ops = &r8a66597_gadget_ops; dev_set_name(&r8a66597->gadget.dev, "gadget"); - r8a66597->gadget.is_dualspeed = 1; + r8a66597->gadget.max_speed = USB_SPEED_HIGH; r8a66597->gadget.dev.parent = &pdev->dev; r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask; r8a66597->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index b31448229f0b..6bc7ad87c306 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -3362,7 +3362,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) dev_set_name(&hsotg->gadget.dev, "gadget"); - hsotg->gadget.is_dualspeed = 1; + hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.ops = &s3c_hsotg_gadget_ops; hsotg->gadget.name = dev_name(dev); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 20a553b46aed..09ea96558b91 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1310,7 +1310,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) device_initialize(&hsudc->gadget.dev); dev_set_name(&hsudc->gadget.dev, "gadget"); - hsudc->gadget.is_dualspeed = 1; + hsudc->gadget.max_speed = USB_SPEED_HIGH; hsudc->gadget.ops = &s3c_hsudc_gadget_ops; hsudc->gadget.name = dev_name(dev); hsudc->gadget.dev.parent = dev; diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 6939e17f4580..0b0d12ccc487 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -371,14 +371,28 @@ static ssize_t usb_udc_softconn_store(struct device *dev, } static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); -static ssize_t usb_udc_speed_show(struct device *dev, +#define USB_UDC_SPEED_ATTR(name, param) \ +ssize_t usb_udc_##param##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ + return snprintf(buf, PAGE_SIZE, "%s\n", \ + usb_speed_string(udc->gadget->param)); \ +} \ +static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) + +static USB_UDC_SPEED_ATTR(current_speed, speed); +static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); + +/* TODO: Scheduled for removal in 3.8. */ +static ssize_t usb_udc_is_dualspeed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - return snprintf(buf, PAGE_SIZE, "%s\n", - usb_speed_string(udc->gadget->speed)); + return snprintf(buf, PAGE_SIZE, "%d\n", + gadget_is_dualspeed(udc->gadget)); } -static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL); +static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL); #define USB_UDC_ATTR(name) \ ssize_t usb_udc_##name##_show(struct device *dev, \ @@ -391,7 +405,6 @@ ssize_t usb_udc_##name##_show(struct device *dev, \ } \ static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL) -static USB_UDC_ATTR(is_dualspeed); static USB_UDC_ATTR(is_otg); static USB_UDC_ATTR(is_a_peripheral); static USB_UDC_ATTR(b_hnp_enable); @@ -401,7 +414,8 @@ static USB_UDC_ATTR(a_alt_hnp_support); static struct attribute *usb_udc_attrs[] = { &dev_attr_srp.attr, &dev_attr_soft_connect.attr, - &dev_attr_speed.attr, + &dev_attr_current_speed.attr, + &dev_attr_maximum_speed.attr, &dev_attr_is_dualspeed.attr, &dev_attr_is_otg.attr, diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 922148ff8d29..47a3d1e5b28b 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1844,7 +1844,7 @@ int __init musb_gadget_setup(struct musb *musb) */ musb->g.ops = &musb_gadget_operations; - musb->g.is_dualspeed = 1; + musb->g.max_speed = USB_SPEED_HIGH; musb->g.speed = USB_SPEED_UNKNOWN; /* this "gadget" abstracts/virtualizes the controller */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 8fb9056ff48d..43c67e5cde26 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -862,7 +862,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) gpriv->gadget.dev.parent = dev; gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; - gpriv->gadget.is_dualspeed = 1; + gpriv->gadget.max_speed = USB_SPEED_HIGH; ret = device_register(&gpriv->gadget.dev); if (ret < 0) goto err_add_udc; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 1d3a67523ffc..98dc306898b5 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -477,8 +477,8 @@ struct usb_gadget_ops { * driver setup() requests * @ep_list: List of other endpoints supported by the device. * @speed: Speed of current connection to USB host. - * @is_dualspeed: True if the controller supports both high and full speed - * operation. If it does, the gadget driver must also support both. + * @max_speed: Maximal speed the UDC can handle. UDC must support this + * and all slower speeds. * @is_otg: True if the USB device port uses a Mini-AB jack, so that the * gadget driver must provide a USB OTG descriptor. * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable @@ -518,7 +518,7 @@ struct usb_gadget { struct usb_ep *ep0; struct list_head ep_list; /* of usb_ep */ enum usb_device_speed speed; - unsigned is_dualspeed:1; + enum usb_device_speed max_speed; unsigned is_otg:1; unsigned is_a_peripheral:1; unsigned b_hnp_enable:1; @@ -549,7 +549,7 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) static inline int gadget_is_dualspeed(struct usb_gadget *g) { #ifdef CONFIG_USB_GADGET_DUALSPEED - /* runtime test would check "g->is_dualspeed" ... that might be + /* runtime test would check "g->max_speed" ... that might be * useful to work around hardware bugs, but is mostly pointless */ return 1; @@ -567,7 +567,7 @@ static inline int gadget_is_superspeed(struct usb_gadget *g) { #ifdef CONFIG_USB_GADGET_SUPERSPEED /* - * runtime test would check "g->is_superspeed" ... that might be + * runtime test would check "g->max_speed" ... that might be * useful to work around hardware bugs, but is mostly pointless */ return 1; -- cgit v1.2.3 From 7177aed44f515d949f587170e0e177ce17e74793 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sat, 19 Nov 2011 18:27:38 +0100 Subject: usb: gadget: rename usb_gadget_driver::speed to max_speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit renames the “speed” field of the usb_gadget_driver structure to “max_speed”. This is so that to make it more apparent that the field represents the maximum speed gadget driver can support. This also make the field look more like fields with the same name in usb_gadget and usb_composite_driver structures. All of those represent the *maximal* speed given entity supports. After this commit, there are the following fields in various structures: * usb_gadget::speed - the current connection speed, * usb_gadget::max_speed - maximal speed UDC supports, * usb_gadget_driver::max_speed - maximal speed gadget driver supports, and * usb_composite_driver::max_speed - maximal speed composite gadget supports. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/ci13xxx_udc.c | 2 +- drivers/usb/gadget/composite.c | 8 ++++---- drivers/usb/gadget/dbgp.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 13 ++++++------- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/fsl_qe_udc.c | 4 ++-- drivers/usb/gadget/fsl_udc_core.c | 2 +- drivers/usb/gadget/fusb300_udc.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/imx_udc.c | 2 +- drivers/usb/gadget/inode.c | 6 +++--- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/net2272.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pch_udc.c | 2 +- drivers/usb/gadget/printer.c | 2 +- drivers/usb/gadget/pxa25x_udc.c | 2 +- drivers/usb/gadget/pxa27x_udc.c | 2 +- drivers/usb/gadget/r8a66597-udc.c | 2 +- drivers/usb/gadget/s3c-hsotg.c | 2 +- drivers/usb/gadget/s3c-hsudc.c | 2 +- drivers/usb/gadget/s3c2410_udc.c | 4 ++-- drivers/usb/musb/musb_gadget.c | 2 +- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- include/linux/usb/gadget.h | 4 ++-- 28 files changed, 41 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index e69cdbca8017..e9a2c5c44454 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver, u32 tmp; if (!driver || !bind || !driver->setup - || driver->speed < USB_SPEED_HIGH) + || driver->max_speed < USB_SPEED_HIGH) return -EINVAL; if (!dev) return -ENODEV; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 8efe0fa9228d..ac41f71bf9ca 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1633,7 +1633,7 @@ static int at91_start(struct usb_gadget_driver *driver, unsigned long flags; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) { DBG("bad parameter.\n"); diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 9767d9170fbd..27e313718422 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -813,7 +813,7 @@ static ssize_t show_driver(struct device *dev, struct device_attribute *attr, n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", (driver->function ? driver->function : "")); n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", - driver->speed); + driver->max_speed); return n; } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f71b0787983f..a95de6a4a134 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1535,9 +1535,9 @@ composite_resume(struct usb_gadget *gadget) static struct usb_gadget_driver composite_driver = { #ifdef CONFIG_USB_GADGET_SUPERSPEED - .speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_SUPER, #else - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, #endif .unbind = composite_unbind, @@ -1584,8 +1584,8 @@ int usb_composite_probe(struct usb_composite_driver *driver, driver->iProduct = driver->name; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; - composite_driver.speed = min((u8)composite_driver.speed, - (u8)driver->max_speed); + composite_driver.max_speed = + min_t(u8, composite_driver.max_speed, driver->max_speed); composite = driver; composite_gadget_bind = bind; diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 6256420089f3..19d7bb0df75a 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -404,7 +404,7 @@ fail: static struct usb_gadget_driver dbgp_driver = { .function = "dbgp", - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, .unbind = dbgp_unbind, .setup = dbgp_setup, .disconnect = dbgp_disconnect, diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index cf235d84d8b7..db815c2da7ed 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -823,19 +823,18 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) if (value && dum->driver) { if (mod_data.is_super_speed) - dum->gadget.speed = dum->driver->speed; + dum->gadget.speed = dum->driver->max_speed; else if (mod_data.is_high_speed) dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, - dum->driver->speed); + dum->driver->max_speed); else dum->gadget.speed = USB_SPEED_FULL; dummy_udc_udpate_ep0(dum); - if (dum->gadget.speed < dum->driver->speed) + if (dum->gadget.speed < dum->driver->max_speed) dev_dbg(udc_dev(dum), "This device can perform faster" - " if you connect it to a %s port...\n", - (dum->driver->speed == USB_SPEED_SUPER ? - "SuperSpeed" : "HighSpeed")); + " if you connect it to a %s port...\n", + usb_speed_string(dum->driver->max_speed)); } dum_hcd = gadget_to_dummy_hcd(_gadget); @@ -898,7 +897,7 @@ static int dummy_udc_start(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - if (driver->speed == USB_SPEED_UNKNOWN) + if (driver->max_speed == USB_SPEED_UNKNOWN) return -EINVAL; /* diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index e8ff2f1c06cc..e0f30fc70e45 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3604,7 +3604,7 @@ static void fsg_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { - .speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_SUPER, .function = (char *) fsg_string_product, .unbind = fsg_unbind, .disconnect = fsg_disconnect, diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index e00cf92409ce..b7a1efef938d 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2336,7 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || driver->speed < USB_SPEED_FULL + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -2350,7 +2350,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, /* hook up the driver */ udc_controller->driver = driver; udc_controller->gadget.dev.driver = &driver->driver; - udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed); + udc_controller->gadget.speed = driver->max_speed; spin_unlock_irqrestore(&udc_controller->lock, flags); retval = bind(&udc_controller->gadget); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 6de8ec753818..d7ea6c076ce9 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1934,7 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || driver->speed < USB_SPEED_FULL + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 6e32a60ab3b7..5831cb4a0b35 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1317,7 +1317,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index ab9c924eee76..5af70fcce139 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1357,7 +1357,7 @@ static int goku_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 2d978c0e7ced..8d1c75abd73d 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1336,7 +1336,7 @@ static int imx_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 6ccae2707e59..93612519b53a 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1766,9 +1766,9 @@ gadgetfs_suspend (struct usb_gadget *gadget) static struct usb_gadget_driver gadgetfs_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, #else - .speed = USB_SPEED_FULL, + .max_speed = USB_SPEED_FULL, #endif .function = (char *) driver_desc, .unbind = gadgetfs_unbind, @@ -1792,7 +1792,7 @@ static int gadgetfs_probe (struct usb_gadget *gadget) } static struct usb_gadget_driver probe_driver = { - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index a7692c208ea7..3608b3bd5732 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_HIGH + || driver->max_speed < USB_SPEED_HIGH || !bind || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index d5050f4e8449..4c81d540bc26 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -1459,7 +1459,7 @@ static int net2272_start(struct usb_gadget *_gadget, unsigned i; if (!driver || !driver->unbind || !driver->setup || - driver->speed != USB_SPEED_HIGH) + driver->max_speed != USB_SPEED_HIGH) return -EINVAL; dev = container_of(_gadget, struct net2272, gadget); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 9ee36fd5adae..cf1f36454d08 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1881,7 +1881,7 @@ static int net2280_start(struct usb_gadget *_gadget, * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) * "must not be used in normal operation" */ - if (!driver || driver->speed < USB_SPEED_HIGH + if (!driver || driver->max_speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index ed01a0f5f119..7db5bbe6251b 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2110,7 +2110,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver, return -ENODEV; if (!driver // FIXME if otg, check: driver->is_otg - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 7f97b4adba3e..dd2313cce1d3 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2693,7 +2693,7 @@ static int pch_udc_start(struct usb_gadget_driver *driver, struct pch_udc_dev *dev = pch_udc; int retval; - if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind || + if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind || !driver->setup || !driver->unbind || !driver->disconnect) { dev_err(&dev->pdev->dev, "%s: invalid driver parameter\n", __func__); diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index b74f49ac95e5..d83134b0f78a 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1535,7 +1535,7 @@ fail: /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver printer_driver = { - .speed = DEVSPEED, + .max_speed = DEVSPEED, .function = (char *) driver_desc, .unbind = printer_unbind, diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index c090a7e3ecf8..dd470635f4f7 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1264,7 +1264,7 @@ static int pxa25x_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 18b6b091f2a6..f4c44eb806c3 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1807,7 +1807,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver, struct pxa_udc *udc = the_controller; int retval; - if (!driver || driver->speed < USB_SPEED_FULL || !bind + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; if (!udc) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 3666d7c54e24..f5b8d215e1d5 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1746,7 +1746,7 @@ static int r8a66597_start(struct usb_gadget *gadget, struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); if (!driver - || driver->speed < USB_SPEED_HIGH + || driver->max_speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; if (!r8a66597) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 6bc7ad87c306..d098c36cb587 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2586,7 +2586,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, return -EINVAL; } - if (driver->speed < USB_SPEED_FULL) + if (driver->max_speed < USB_SPEED_FULL) dev_err(hsotg->dev, "%s: bad speed\n", __func__); if (!bind || !driver->setup) { diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 09ea96558b91..f398b8590f9c 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1142,7 +1142,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, int ret; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index b8643771fa80..4d860e9460a4 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1683,9 +1683,9 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver, if (udc->driver) return -EBUSY; - if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) { + if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) { printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", - bind, driver->setup, driver->speed); + bind, driver->setup, driver->max_speed); return -EINVAL; } #if defined(MODULE) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 47a3d1e5b28b..3148461287b1 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1903,7 +1903,7 @@ static int musb_gadget_start(struct usb_gadget *g, unsigned long flags; int retval = -EINVAL; - if (driver->speed < USB_SPEED_HIGH) + if (driver->max_speed < USB_SPEED_HIGH) goto err0; pm_runtime_get_sync(musb->controller); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 43c67e5cde26..c307c8f5bd3a 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -751,7 +751,7 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, if (!driver || !driver->setup || - driver->speed < USB_SPEED_FULL) + driver->max_speed < USB_SPEED_FULL) return -EINVAL; /* first hook up the driver ... */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 98dc306898b5..317d8925387c 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -760,7 +760,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) /** * struct usb_gadget_driver - driver for usb 'slave' devices * @function: String describing the gadget's function - * @speed: Highest speed the driver handles. + * @max_speed: Highest speed the driver handles. * @setup: Invoked for ep0 control requests that aren't handled by * the hardware level driver. Most calls must be handled by * the gadget driver, including descriptor and configuration @@ -824,7 +824,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) */ struct usb_gadget_driver { char *function; - enum usb_device_speed speed; + enum usb_device_speed max_speed; void (*unbind)(struct usb_gadget *); int (*setup)(struct usb_gadget *, const struct usb_ctrlrequest *); -- cgit v1.2.3 From c91043adaf50ef13609003120f3471783460fb71 Mon Sep 17 00:00:00 2001 From: Qinglin Ye Date: Sun, 11 Dec 2011 16:40:22 +0800 Subject: USB: Remove the duplicate definition of HUB_SET_DEPTH The macro HUB_SET_DEPTH is defined twice in ch11.h (introduced by commit 0eadcc0 "usb: USB3.0 ch11 definitions" and dbe79bb "USB 3.0 Hub Changes"), so remove the duplicate one in the USB 2.0 part. Signed-off-by: Qinglin Ye Cc: John Youn Cc: Sergei Shtylyov Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/ch11.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h index 0832eb841a30..31fdb4c6ee3d 100644 --- a/include/linux/usb/ch11.h +++ b/include/linux/usb/ch11.h @@ -26,7 +26,6 @@ #define HUB_RESET_TT 9 #define HUB_GET_TT_STATE 10 #define HUB_STOP_TT 11 -#define HUB_SET_DEPTH 12 /* * Hub class additional requests defined by USB 3.0 spec -- cgit v1.2.3 From a7250db36308424ae040f1b2eeb5bfd0cbee0b0d Mon Sep 17 00:00:00 2001 From: Yu Xu Date: Mon, 19 Dec 2011 17:33:03 +0800 Subject: usb: gadget: enlarge maxburst bit width. For super speed bulk transfer, the max burst size is 16, so that 4 bits of maxburst cannot store it. Signed-off-by: Yu Xu Signed-off-by: Felipe Balbi --- include/linux/usb/gadget.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 317d8925387c..4d99805bcbb7 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -164,7 +164,7 @@ struct usb_ep { unsigned maxpacket:16; unsigned max_streams:16; unsigned mult:2; - unsigned maxburst:4; + unsigned maxburst:5; u8 address; const struct usb_endpoint_descriptor *desc; const struct usb_ss_ep_comp_descriptor *comp_desc; -- cgit v1.2.3 From 5e6c86b017691230b6b47f19b7d5449997e8a0b8 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Tue, 20 Dec 2011 13:20:21 +0800 Subject: usb: gadget: mv_udc: drop ARCH dependency This patch do the following things: 1. Change the Kconfig information. 2. Rename the driver name. 3. Don't do any type cast to io memory. 4. Add dummy stub for clk framework. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 10 +++++----- drivers/usb/gadget/Makefile | 2 +- drivers/usb/gadget/mv_udc.h | 2 +- drivers/usb/gadget/mv_udc_core.c | 17 ++++++++--------- include/linux/platform_data/mv_usb.h | 12 ++++++++++-- 5 files changed, 25 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 953b00cd59ff..f1a5409e99f7 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -309,13 +309,13 @@ config USB_S3C_HSUDC This driver has been tested on S3C2416 and S3C2450 processors. -config USB_PXA_U2O - tristate "PXA9xx Processor USB2.0 controller" - depends on ARCH_MMP +config USB_MV_UDC + tristate "Marvell USB2.0 Device Controller" select USB_GADGET_DUALSPEED help - PXA9xx Processor series include a high speed USB2.0 device - controller, which support high speed and full speed USB peripheral. + Marvell Socs (including PXA and MMP series) include a high speed + USB2.0 OTG controller, which can be configured as high speed or + full speed USB peripheral. config USB_GADGET_DWC3 tristate "DesignWare USB3.0 (DRD) Controller" diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index b54ac6190890..b7f6eefc3927 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o -obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o +obj-$(CONFIG_USB_MV_UDC) += mv_udc.o mv_udc-y := mv_udc_core.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index 3d8404484613..34aadfae723d 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -180,7 +180,7 @@ struct mv_udc { struct mv_cap_regs __iomem *cap_regs; struct mv_op_regs __iomem *op_regs; - unsigned int phy_regs; + void __iomem *phy_regs; unsigned int max_eps; struct mv_dqh *ep_dqh; size_t ep_dqh_size; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index a3a7664add19..f0596ac533e0 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2128,11 +2128,9 @@ static int __devexit mv_udc_remove(struct platform_device *dev) if (udc->cap_regs) iounmap(udc->cap_regs); - udc->cap_regs = NULL; if (udc->phy_regs) - iounmap((void *)udc->phy_regs); - udc->phy_regs = 0; + iounmap(udc->phy_regs); if (udc->status_req) { kfree(udc->status_req->req.buf); @@ -2217,8 +2215,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev) goto err_iounmap_capreg; } - udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r)); - if (udc->phy_regs == 0) { + udc->phy_regs = ioremap(r->start, resource_size(r)); + if (udc->phy_regs == NULL) { dev_err(&dev->dev, "failed to map phy I/O memory\n"); retval = -EBUSY; goto err_iounmap_capreg; @@ -2229,7 +2227,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev) if (retval) goto err_iounmap_phyreg; - udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs + udc->op_regs = + (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs + (readl(&udc->cap_regs->caplength_hciversion) & CAPLENGTH_MASK)); udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK; @@ -2389,7 +2388,7 @@ err_free_dma: err_disable_clock: mv_udc_disable_internal(udc); err_iounmap_phyreg: - iounmap((void *)udc->phy_regs); + iounmap(udc->phy_regs); err_iounmap_capreg: iounmap(udc->cap_regs); err_put_clk: @@ -2480,13 +2479,13 @@ static struct platform_driver udc_driver = { .shutdown = mv_udc_shutdown, .driver = { .owner = THIS_MODULE, - .name = "pxa-u2o", + .name = "mv-udc", #ifdef CONFIG_PM .pm = &mv_udc_pm_ops, #endif }, }; -MODULE_ALIAS("platform:pxa-u2o"); +MODULE_ALIAS("platform:mv-udc"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Chao Xie "); diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h index e9d9149ddf38..a642cf20ad6e 100644 --- a/include/linux/platform_data/mv_usb.h +++ b/include/linux/platform_data/mv_usb.h @@ -42,9 +42,17 @@ struct mv_usb_platform_data { /* only valid for HCD. OTG or Host only*/ unsigned int mode; - int (*phy_init)(unsigned int regbase); - void (*phy_deinit)(unsigned int regbase); + int (*phy_init)(void __iomem *regbase); + void (*phy_deinit)(void __iomem *regbase); int (*set_vbus)(unsigned int vbus); }; +#ifndef CONFIG_HAVE_CLK +/* Dummy stub for clk framework */ +#define clk_get(dev, id) NULL +#define clk_put(clock) do {} while (0) +#define clk_enable(clock) do {} while (0) +#define clk_disable(clock) do {} while (0) +#endif + #endif -- cgit v1.2.3 From 277164f03f466b7a1ea0d0c3dac8b8a0599ce0dc Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Tue, 20 Dec 2011 13:20:22 +0800 Subject: USB: OTG: add Marvell usb OTG driver support This driver is for ChipIdea USB OTG controller on Marvell Socs. PXA9xx/MMP2/MMP3/MGx all have this USB OTG controller. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/otg/Kconfig | 12 + drivers/usb/otg/Makefile | 1 + drivers/usb/otg/mv_otg.c | 957 +++++++++++++++++++++++++++++++++++ drivers/usb/otg/mv_otg.h | 165 ++++++ include/linux/platform_data/mv_usb.h | 5 + 5 files changed, 1140 insertions(+) create mode 100644 drivers/usb/otg/mv_otg.c create mode 100644 drivers/usb/otg/mv_otg.h (limited to 'include') diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index c66481ad98d7..c4e2cb760c66 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -130,4 +130,16 @@ config FSL_USB2_OTG help Enable this to support Freescale USB OTG transceiver. +config USB_MV_OTG + tristate "Marvell USB OTG support" + depends on USB_MV_UDC + select USB_OTG + select USB_OTG_UTILS + help + Say Y here if you want to build Marvell USB OTG transciever + driver in kernel (including PXA and MMP series). This driver + implements role switch between EHCI host driver and gadget driver. + + To compile this driver as a module, choose M here. + endif # USB || OTG diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 566655c53331..b2c5a9598637 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o obj-$(CONFIG_AB8500_USB) += ab8500-usb.o fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o +obj-$(CONFIG_USB_MV_OTG) += mv_otg.o diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c new file mode 100644 index 000000000000..db0d4fcdc8e2 --- /dev/null +++ b/drivers/usb/otg/mv_otg.c @@ -0,0 +1,957 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * Author: Chao Xie + * Neil Zhang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "mv_otg.h" + +#define DRIVER_DESC "Marvell USB OTG transceiver driver" +#define DRIVER_VERSION "Jan 20, 2010" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +static const char driver_name[] = "mv-otg"; + +static char *state_string[] = { + "undefined", + "b_idle", + "b_srp_init", + "b_peripheral", + "b_wait_acon", + "b_host", + "a_idle", + "a_wait_vrise", + "a_wait_bcon", + "a_host", + "a_suspend", + "a_peripheral", + "a_wait_vfall", + "a_vbus_err" +}; + +static int mv_otg_set_vbus(struct otg_transceiver *otg, bool on) +{ + struct mv_otg *mvotg = container_of(otg, struct mv_otg, otg); + if (mvotg->pdata->set_vbus == NULL) + return -ENODEV; + + return mvotg->pdata->set_vbus(on); +} + +static int mv_otg_set_host(struct otg_transceiver *otg, + struct usb_bus *host) +{ + otg->host = host; + + return 0; +} + +static int mv_otg_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + + return 0; +} + +static void mv_otg_run_state_machine(struct mv_otg *mvotg, + unsigned long delay) +{ + dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n"); + if (!mvotg->qwork) + return; + + queue_delayed_work(mvotg->qwork, &mvotg->work, delay); +} + +static void mv_otg_timer_await_bcon(unsigned long data) +{ + struct mv_otg *mvotg = (struct mv_otg *) data; + + mvotg->otg_ctrl.a_wait_bcon_timeout = 1; + + dev_info(&mvotg->pdev->dev, "B Device No Response!\n"); + + if (spin_trylock(&mvotg->wq_lock)) { + mv_otg_run_state_machine(mvotg, 0); + spin_unlock(&mvotg->wq_lock); + } +} + +static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id) +{ + struct timer_list *timer; + + if (id >= OTG_TIMER_NUM) + return -EINVAL; + + timer = &mvotg->otg_ctrl.timer[id]; + + if (timer_pending(timer)) + del_timer(timer); + + return 0; +} + +static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id, + unsigned long interval, + void (*callback) (unsigned long)) +{ + struct timer_list *timer; + + if (id >= OTG_TIMER_NUM) + return -EINVAL; + + timer = &mvotg->otg_ctrl.timer[id]; + if (timer_pending(timer)) { + dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id); + return -EBUSY; + } + + init_timer(timer); + timer->data = (unsigned long) mvotg; + timer->function = callback; + timer->expires = jiffies + interval; + add_timer(timer); + + return 0; +} + +static int mv_otg_reset(struct mv_otg *mvotg) +{ + unsigned int loops; + u32 tmp; + + /* Stop the controller */ + tmp = readl(&mvotg->op_regs->usbcmd); + tmp &= ~USBCMD_RUN_STOP; + writel(tmp, &mvotg->op_regs->usbcmd); + + /* Reset the controller to get default values */ + writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd); + + loops = 500; + while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) { + if (loops == 0) { + dev_err(&mvotg->pdev->dev, + "Wait for RESET completed TIMEOUT\n"); + return -ETIMEDOUT; + } + loops--; + udelay(20); + } + + writel(0x0, &mvotg->op_regs->usbintr); + tmp = readl(&mvotg->op_regs->usbsts); + writel(tmp, &mvotg->op_regs->usbsts); + + return 0; +} + +static void mv_otg_init_irq(struct mv_otg *mvotg) +{ + u32 otgsc; + + mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID + | OTGSC_INTR_A_VBUS_VALID; + mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID + | OTGSC_INTSTS_A_VBUS_VALID; + + if (mvotg->pdata->vbus == NULL) { + mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID + | OTGSC_INTR_B_SESSION_END; + mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID + | OTGSC_INTSTS_B_SESSION_END; + } + + if (mvotg->pdata->id == NULL) { + mvotg->irq_en |= OTGSC_INTR_USB_ID; + mvotg->irq_status |= OTGSC_INTSTS_USB_ID; + } + + otgsc = readl(&mvotg->op_regs->otgsc); + otgsc |= mvotg->irq_en; + writel(otgsc, &mvotg->op_regs->otgsc); +} + +static void mv_otg_start_host(struct mv_otg *mvotg, int on) +{ + struct otg_transceiver *otg = &mvotg->otg; + struct usb_hcd *hcd; + + if (!otg->host) + return; + + dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop"); + + hcd = bus_to_hcd(otg->host); + + if (on) + usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); + else + usb_remove_hcd(hcd); +} + +static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on) +{ + struct otg_transceiver *otg = &mvotg->otg; + + if (!otg->gadget) + return; + + dev_info(otg->dev, "gadget %s\n", on ? "on" : "off"); + + if (on) + usb_gadget_vbus_connect(otg->gadget); + else + usb_gadget_vbus_disconnect(otg->gadget); +} + +static void otg_clock_enable(struct mv_otg *mvotg) +{ + unsigned int i; + + for (i = 0; i < mvotg->clknum; i++) + clk_enable(mvotg->clk[i]); +} + +static void otg_clock_disable(struct mv_otg *mvotg) +{ + unsigned int i; + + for (i = 0; i < mvotg->clknum; i++) + clk_disable(mvotg->clk[i]); +} + +static int mv_otg_enable_internal(struct mv_otg *mvotg) +{ + int retval = 0; + + if (mvotg->active) + return 0; + + dev_dbg(&mvotg->pdev->dev, "otg enabled\n"); + + otg_clock_enable(mvotg); + if (mvotg->pdata->phy_init) { + retval = mvotg->pdata->phy_init(mvotg->phy_regs); + if (retval) { + dev_err(&mvotg->pdev->dev, + "init phy error %d\n", retval); + otg_clock_disable(mvotg); + return retval; + } + } + mvotg->active = 1; + + return 0; + +} + +static int mv_otg_enable(struct mv_otg *mvotg) +{ + if (mvotg->clock_gating) + return mv_otg_enable_internal(mvotg); + + return 0; +} + +static void mv_otg_disable_internal(struct mv_otg *mvotg) +{ + if (mvotg->active) { + dev_dbg(&mvotg->pdev->dev, "otg disabled\n"); + if (mvotg->pdata->phy_deinit) + mvotg->pdata->phy_deinit(mvotg->phy_regs); + otg_clock_disable(mvotg); + mvotg->active = 0; + } +} + +static void mv_otg_disable(struct mv_otg *mvotg) +{ + if (mvotg->clock_gating) + mv_otg_disable_internal(mvotg); +} + +static void mv_otg_update_inputs(struct mv_otg *mvotg) +{ + struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; + u32 otgsc; + + otgsc = readl(&mvotg->op_regs->otgsc); + + if (mvotg->pdata->vbus) { + if (mvotg->pdata->vbus->poll() == VBUS_HIGH) { + otg_ctrl->b_sess_vld = 1; + otg_ctrl->b_sess_end = 0; + } else { + otg_ctrl->b_sess_vld = 0; + otg_ctrl->b_sess_end = 1; + } + } else { + otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID); + otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END); + } + + if (mvotg->pdata->id) + otg_ctrl->id = !!mvotg->pdata->id->poll(); + else + otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID); + + if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id) + otg_ctrl->a_bus_req = 1; + + otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID); + otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID); + + dev_dbg(&mvotg->pdev->dev, "%s: ", __func__); + dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id); + dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld); + dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end); + dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld); + dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld); +} + +static void mv_otg_update_state(struct mv_otg *mvotg) +{ + struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; + struct otg_transceiver *otg = &mvotg->otg; + int old_state = otg->state; + + switch (old_state) { + case OTG_STATE_UNDEFINED: + otg->state = OTG_STATE_B_IDLE; + /* FALL THROUGH */ + case OTG_STATE_B_IDLE: + if (otg_ctrl->id == 0) + otg->state = OTG_STATE_A_IDLE; + else if (otg_ctrl->b_sess_vld) + otg->state = OTG_STATE_B_PERIPHERAL; + break; + case OTG_STATE_B_PERIPHERAL: + if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0) + otg->state = OTG_STATE_B_IDLE; + break; + case OTG_STATE_A_IDLE: + if (otg_ctrl->id) + otg->state = OTG_STATE_B_IDLE; + else if (!(otg_ctrl->a_bus_drop) && + (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det)) + otg->state = OTG_STATE_A_WAIT_VRISE; + break; + case OTG_STATE_A_WAIT_VRISE: + if (otg_ctrl->a_vbus_vld) + otg->state = OTG_STATE_A_WAIT_BCON; + break; + case OTG_STATE_A_WAIT_BCON: + if (otg_ctrl->id || otg_ctrl->a_bus_drop + || otg_ctrl->a_wait_bcon_timeout) { + mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); + mvotg->otg_ctrl.a_wait_bcon_timeout = 0; + otg->state = OTG_STATE_A_WAIT_VFALL; + otg_ctrl->a_bus_req = 0; + } else if (!otg_ctrl->a_vbus_vld) { + mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); + mvotg->otg_ctrl.a_wait_bcon_timeout = 0; + otg->state = OTG_STATE_A_VBUS_ERR; + } else if (otg_ctrl->b_conn) { + mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); + mvotg->otg_ctrl.a_wait_bcon_timeout = 0; + otg->state = OTG_STATE_A_HOST; + } + break; + case OTG_STATE_A_HOST: + if (otg_ctrl->id || !otg_ctrl->b_conn + || otg_ctrl->a_bus_drop) + otg->state = OTG_STATE_A_WAIT_BCON; + else if (!otg_ctrl->a_vbus_vld) + otg->state = OTG_STATE_A_VBUS_ERR; + break; + case OTG_STATE_A_WAIT_VFALL: + if (otg_ctrl->id + || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld) + || otg_ctrl->a_bus_req) + otg->state = OTG_STATE_A_IDLE; + break; + case OTG_STATE_A_VBUS_ERR: + if (otg_ctrl->id || otg_ctrl->a_clr_err + || otg_ctrl->a_bus_drop) { + otg_ctrl->a_clr_err = 0; + otg->state = OTG_STATE_A_WAIT_VFALL; + } + break; + default: + break; + } +} + +static void mv_otg_work(struct work_struct *work) +{ + struct mv_otg *mvotg; + struct otg_transceiver *otg; + int old_state; + + mvotg = container_of((struct delayed_work *)work, struct mv_otg, work); + +run: + /* work queue is single thread, or we need spin_lock to protect */ + otg = &mvotg->otg; + old_state = otg->state; + + if (!mvotg->active) + return; + + mv_otg_update_inputs(mvotg); + mv_otg_update_state(mvotg); + + if (old_state != otg->state) { + dev_info(&mvotg->pdev->dev, "change from state %s to %s\n", + state_string[old_state], + state_string[otg->state]); + + switch (otg->state) { + case OTG_STATE_B_IDLE: + mvotg->otg.default_a = 0; + if (old_state == OTG_STATE_B_PERIPHERAL) + mv_otg_start_periphrals(mvotg, 0); + mv_otg_reset(mvotg); + mv_otg_disable(mvotg); + break; + case OTG_STATE_B_PERIPHERAL: + mv_otg_enable(mvotg); + mv_otg_start_periphrals(mvotg, 1); + break; + case OTG_STATE_A_IDLE: + mvotg->otg.default_a = 1; + mv_otg_enable(mvotg); + if (old_state == OTG_STATE_A_WAIT_VFALL) + mv_otg_start_host(mvotg, 0); + mv_otg_reset(mvotg); + break; + case OTG_STATE_A_WAIT_VRISE: + mv_otg_set_vbus(&mvotg->otg, 1); + break; + case OTG_STATE_A_WAIT_BCON: + if (old_state != OTG_STATE_A_HOST) + mv_otg_start_host(mvotg, 1); + mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER, + T_A_WAIT_BCON, + mv_otg_timer_await_bcon); + /* + * Now, we directly enter A_HOST. So set b_conn = 1 + * here. In fact, it need host driver to notify us. + */ + mvotg->otg_ctrl.b_conn = 1; + break; + case OTG_STATE_A_HOST: + break; + case OTG_STATE_A_WAIT_VFALL: + /* + * Now, we has exited A_HOST. So set b_conn = 0 + * here. In fact, it need host driver to notify us. + */ + mvotg->otg_ctrl.b_conn = 0; + mv_otg_set_vbus(&mvotg->otg, 0); + break; + case OTG_STATE_A_VBUS_ERR: + break; + default: + break; + } + goto run; + } +} + +static irqreturn_t mv_otg_irq(int irq, void *dev) +{ + struct mv_otg *mvotg = dev; + u32 otgsc; + + otgsc = readl(&mvotg->op_regs->otgsc); + writel(otgsc, &mvotg->op_regs->otgsc); + + /* + * if we have vbus, then the vbus detection for B-device + * will be done by mv_otg_inputs_irq(). + */ + if (mvotg->pdata->vbus) + if ((otgsc & OTGSC_STS_USB_ID) && + !(otgsc & OTGSC_INTSTS_USB_ID)) + return IRQ_NONE; + + if ((otgsc & mvotg->irq_status) == 0) + return IRQ_NONE; + + mv_otg_run_state_machine(mvotg, 0); + + return IRQ_HANDLED; +} + +static irqreturn_t mv_otg_inputs_irq(int irq, void *dev) +{ + struct mv_otg *mvotg = dev; + + /* The clock may disabled at this time */ + if (!mvotg->active) { + mv_otg_enable(mvotg); + mv_otg_init_irq(mvotg); + } + + mv_otg_run_state_machine(mvotg, 0); + + return IRQ_HANDLED; +} + +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mv_otg *mvotg = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", + mvotg->otg_ctrl.a_bus_req); +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mv_otg *mvotg = dev_get_drvdata(dev); + + if (count > 2) + return -1; + + /* We will use this interface to change to A device */ + if (mvotg->otg.state != OTG_STATE_B_IDLE + && mvotg->otg.state != OTG_STATE_A_IDLE) + return -1; + + /* The clock may disabled and we need to set irq for ID detected */ + mv_otg_enable(mvotg); + mv_otg_init_irq(mvotg); + + if (buf[0] == '1') { + mvotg->otg_ctrl.a_bus_req = 1; + mvotg->otg_ctrl.a_bus_drop = 0; + dev_dbg(&mvotg->pdev->dev, + "User request: a_bus_req = 1\n"); + + if (spin_trylock(&mvotg->wq_lock)) { + mv_otg_run_state_machine(mvotg, 0); + spin_unlock(&mvotg->wq_lock); + } + } + + return count; +} + +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, + set_a_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mv_otg *mvotg = dev_get_drvdata(dev); + if (!mvotg->otg.default_a) + return -1; + + if (count > 2) + return -1; + + if (buf[0] == '1') { + mvotg->otg_ctrl.a_clr_err = 1; + dev_dbg(&mvotg->pdev->dev, + "User request: a_clr_err = 1\n"); + } + + if (spin_trylock(&mvotg->wq_lock)) { + mv_otg_run_state_machine(mvotg, 0); + spin_unlock(&mvotg->wq_lock); + } + + return count; +} + +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mv_otg *mvotg = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", + mvotg->otg_ctrl.a_bus_drop); +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mv_otg *mvotg = dev_get_drvdata(dev); + if (!mvotg->otg.default_a) + return -1; + + if (count > 2) + return -1; + + if (buf[0] == '0') { + mvotg->otg_ctrl.a_bus_drop = 0; + dev_dbg(&mvotg->pdev->dev, + "User request: a_bus_drop = 0\n"); + } else if (buf[0] == '1') { + mvotg->otg_ctrl.a_bus_drop = 1; + mvotg->otg_ctrl.a_bus_req = 0; + dev_dbg(&mvotg->pdev->dev, + "User request: a_bus_drop = 1\n"); + dev_dbg(&mvotg->pdev->dev, + "User request: and a_bus_req = 0\n"); + } + + if (spin_trylock(&mvotg->wq_lock)) { + mv_otg_run_state_machine(mvotg, 0); + spin_unlock(&mvotg->wq_lock); + } + + return count; +} + +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, + get_a_bus_drop, set_a_bus_drop); + +static struct attribute *inputs_attrs[] = { + &dev_attr_a_bus_req.attr, + &dev_attr_a_clr_err.attr, + &dev_attr_a_bus_drop.attr, + NULL, +}; + +static struct attribute_group inputs_attr_group = { + .name = "inputs", + .attrs = inputs_attrs, +}; + +int mv_otg_remove(struct platform_device *pdev) +{ + struct mv_otg *mvotg = platform_get_drvdata(pdev); + int clk_i; + + sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group); + + if (mvotg->irq) + free_irq(mvotg->irq, mvotg); + + if (mvotg->pdata->vbus) + free_irq(mvotg->pdata->vbus->irq, mvotg); + if (mvotg->pdata->id) + free_irq(mvotg->pdata->id->irq, mvotg); + + if (mvotg->qwork) { + flush_workqueue(mvotg->qwork); + destroy_workqueue(mvotg->qwork); + } + + mv_otg_disable(mvotg); + + if (mvotg->cap_regs) + iounmap(mvotg->cap_regs); + + if (mvotg->phy_regs) + iounmap(mvotg->phy_regs); + + for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++) + clk_put(mvotg->clk[clk_i]); + + otg_set_transceiver(NULL); + platform_set_drvdata(pdev, NULL); + + kfree(mvotg); + + return 0; +} + +static int mv_otg_probe(struct platform_device *pdev) +{ + struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct mv_otg *mvotg; + struct resource *r; + int retval = 0, clk_i, i; + size_t size; + + if (pdata == NULL) { + dev_err(&pdev->dev, "failed to get platform data\n"); + return -ENODEV; + } + + size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum; + mvotg = kzalloc(size, GFP_KERNEL); + if (!mvotg) { + dev_err(&pdev->dev, "failed to allocate memory!\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, mvotg); + + mvotg->pdev = pdev; + mvotg->pdata = pdata; + + mvotg->clknum = pdata->clknum; + for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) { + mvotg->clk[clk_i] = clk_get(&pdev->dev, pdata->clkname[clk_i]); + if (IS_ERR(mvotg->clk[clk_i])) { + retval = PTR_ERR(mvotg->clk[clk_i]); + goto err_put_clk; + } + } + + mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); + if (!mvotg->qwork) { + dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); + retval = -ENOMEM; + goto err_put_clk; + } + + INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); + + /* OTG common part */ + mvotg->pdev = pdev; + mvotg->otg.dev = &pdev->dev; + mvotg->otg.label = driver_name; + mvotg->otg.set_host = mv_otg_set_host; + mvotg->otg.set_peripheral = mv_otg_set_peripheral; + mvotg->otg.set_vbus = mv_otg_set_vbus; + mvotg->otg.state = OTG_STATE_UNDEFINED; + + for (i = 0; i < OTG_TIMER_NUM; i++) + init_timer(&mvotg->otg_ctrl.timer[i]); + + r = platform_get_resource_byname(mvotg->pdev, + IORESOURCE_MEM, "phyregs"); + if (r == NULL) { + dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); + retval = -ENODEV; + goto err_destroy_workqueue; + } + + mvotg->phy_regs = ioremap(r->start, resource_size(r)); + if (mvotg->phy_regs == NULL) { + dev_err(&pdev->dev, "failed to map phy I/O memory\n"); + retval = -EFAULT; + goto err_destroy_workqueue; + } + + r = platform_get_resource_byname(mvotg->pdev, + IORESOURCE_MEM, "capregs"); + if (r == NULL) { + dev_err(&pdev->dev, "no I/O memory resource defined\n"); + retval = -ENODEV; + goto err_unmap_phyreg; + } + + mvotg->cap_regs = ioremap(r->start, resource_size(r)); + if (mvotg->cap_regs == NULL) { + dev_err(&pdev->dev, "failed to map I/O memory\n"); + retval = -EFAULT; + goto err_unmap_phyreg; + } + + /* we will acces controller register, so enable the udc controller */ + retval = mv_otg_enable_internal(mvotg); + if (retval) { + dev_err(&pdev->dev, "mv otg enable error %d\n", retval); + goto err_unmap_capreg; + } + + mvotg->op_regs = + (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs + + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); + + if (pdata->id) { + retval = request_threaded_irq(pdata->id->irq, NULL, + mv_otg_inputs_irq, + IRQF_ONESHOT, "id", mvotg); + if (retval) { + dev_info(&pdev->dev, + "Failed to request irq for ID\n"); + pdata->id = NULL; + } + } + + if (pdata->vbus) { + mvotg->clock_gating = 1; + retval = request_threaded_irq(pdata->vbus->irq, NULL, + mv_otg_inputs_irq, + IRQF_ONESHOT, "vbus", mvotg); + if (retval) { + dev_info(&pdev->dev, + "Failed to request irq for VBUS, " + "disable clock gating\n"); + mvotg->clock_gating = 0; + pdata->vbus = NULL; + } + } + + if (pdata->disable_otg_clock_gating) + mvotg->clock_gating = 0; + + mv_otg_reset(mvotg); + mv_otg_init_irq(mvotg); + + r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); + if (r == NULL) { + dev_err(&pdev->dev, "no IRQ resource defined\n"); + retval = -ENODEV; + goto err_disable_clk; + } + + mvotg->irq = r->start; + if (request_irq(mvotg->irq, mv_otg_irq, IRQF_SHARED, + driver_name, mvotg)) { + dev_err(&pdev->dev, "Request irq %d for OTG failed\n", + mvotg->irq); + mvotg->irq = 0; + retval = -ENODEV; + goto err_disable_clk; + } + + retval = otg_set_transceiver(&mvotg->otg); + if (retval < 0) { + dev_err(&pdev->dev, "can't register transceiver, %d\n", + retval); + goto err_free_irq; + } + + retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group); + if (retval < 0) { + dev_dbg(&pdev->dev, + "Can't register sysfs attr group: %d\n", retval); + goto err_set_transceiver; + } + + spin_lock_init(&mvotg->wq_lock); + if (spin_trylock(&mvotg->wq_lock)) { + mv_otg_run_state_machine(mvotg, 2 * HZ); + spin_unlock(&mvotg->wq_lock); + } + + dev_info(&pdev->dev, + "successful probe OTG device %s clock gating.\n", + mvotg->clock_gating ? "with" : "without"); + + return 0; + +err_set_transceiver: + otg_set_transceiver(NULL); +err_free_irq: + free_irq(mvotg->irq, mvotg); +err_disable_clk: + if (pdata->vbus) + free_irq(pdata->vbus->irq, mvotg); + if (pdata->id) + free_irq(pdata->id->irq, mvotg); + mv_otg_disable_internal(mvotg); +err_unmap_capreg: + iounmap(mvotg->cap_regs); +err_unmap_phyreg: + iounmap(mvotg->phy_regs); +err_destroy_workqueue: + flush_workqueue(mvotg->qwork); + destroy_workqueue(mvotg->qwork); +err_put_clk: + for (clk_i--; clk_i >= 0; clk_i--) + clk_put(mvotg->clk[clk_i]); + + platform_set_drvdata(pdev, NULL); + kfree(mvotg); + + return retval; +} + +#ifdef CONFIG_PM +static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct mv_otg *mvotg = platform_get_drvdata(pdev); + + if (mvotg->otg.state != OTG_STATE_B_IDLE) { + dev_info(&pdev->dev, + "OTG state is not B_IDLE, it is %d!\n", + mvotg->otg.state); + return -EAGAIN; + } + + if (!mvotg->clock_gating) + mv_otg_disable_internal(mvotg); + + return 0; +} + +static int mv_otg_resume(struct platform_device *pdev) +{ + struct mv_otg *mvotg = platform_get_drvdata(pdev); + u32 otgsc; + + if (!mvotg->clock_gating) { + mv_otg_enable_internal(mvotg); + + otgsc = readl(&mvotg->op_regs->otgsc); + otgsc |= mvotg->irq_en; + writel(otgsc, &mvotg->op_regs->otgsc); + + if (spin_trylock(&mvotg->wq_lock)) { + mv_otg_run_state_machine(mvotg, 0); + spin_unlock(&mvotg->wq_lock); + } + } + return 0; +} +#endif + +static struct platform_driver mv_otg_driver = { + .probe = mv_otg_probe, + .remove = __exit_p(mv_otg_remove), + .driver = { + .owner = THIS_MODULE, + .name = driver_name, + }, +#ifdef CONFIG_PM + .suspend = mv_otg_suspend, + .resume = mv_otg_resume, +#endif +}; + +static int __init mv_otg_init(void) +{ + return platform_driver_register(&mv_otg_driver); +} + +static void __exit mv_otg_exit(void) +{ + platform_driver_unregister(&mv_otg_driver); +} + +module_init(mv_otg_init); +module_exit(mv_otg_exit); diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h new file mode 100644 index 000000000000..be6ca1437645 --- /dev/null +++ b/drivers/usb/otg/mv_otg.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __MV_USB_OTG_CONTROLLER__ +#define __MV_USB_OTG_CONTROLLER__ + +#include + +/* Command Register Bit Masks */ +#define USBCMD_RUN_STOP (0x00000001) +#define USBCMD_CTRL_RESET (0x00000002) + +/* otgsc Register Bit Masks */ +#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001 +#define OTGSC_CTRL_VUSB_CHARGE 0x00000002 +#define OTGSC_CTRL_OTG_TERM 0x00000008 +#define OTGSC_CTRL_DATA_PULSING 0x00000010 +#define OTGSC_STS_USB_ID 0x00000100 +#define OTGSC_STS_A_VBUS_VALID 0x00000200 +#define OTGSC_STS_A_SESSION_VALID 0x00000400 +#define OTGSC_STS_B_SESSION_VALID 0x00000800 +#define OTGSC_STS_B_SESSION_END 0x00001000 +#define OTGSC_STS_1MS_TOGGLE 0x00002000 +#define OTGSC_STS_DATA_PULSING 0x00004000 +#define OTGSC_INTSTS_USB_ID 0x00010000 +#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000 +#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000 +#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000 +#define OTGSC_INTSTS_B_SESSION_END 0x00100000 +#define OTGSC_INTSTS_1MS 0x00200000 +#define OTGSC_INTSTS_DATA_PULSING 0x00400000 +#define OTGSC_INTR_USB_ID 0x01000000 +#define OTGSC_INTR_A_VBUS_VALID 0x02000000 +#define OTGSC_INTR_A_SESSION_VALID 0x04000000 +#define OTGSC_INTR_B_SESSION_VALID 0x08000000 +#define OTGSC_INTR_B_SESSION_END 0x10000000 +#define OTGSC_INTR_1MS_TIMER 0x20000000 +#define OTGSC_INTR_DATA_PULSING 0x40000000 + +#define CAPLENGTH_MASK (0xff) + +/* Timer's interval, unit 10ms */ +#define T_A_WAIT_VRISE 100 +#define T_A_WAIT_BCON 2000 +#define T_A_AIDL_BDIS 100 +#define T_A_BIDL_ADIS 20 +#define T_B_ASE0_BRST 400 +#define T_B_SE0_SRP 300 +#define T_B_SRP_FAIL 2000 +#define T_B_DATA_PLS 10 +#define T_B_SRP_INIT 100 +#define T_A_SRP_RSPNS 10 +#define T_A_DRV_RSM 5 + +enum otg_function { + OTG_B_DEVICE = 0, + OTG_A_DEVICE +}; + +enum mv_otg_timer { + A_WAIT_BCON_TIMER = 0, + OTG_TIMER_NUM +}; + +/* PXA OTG state machine */ +struct mv_otg_ctrl { + /* internal variables */ + u8 a_set_b_hnp_en; /* A-Device set b_hnp_en */ + u8 b_srp_done; + u8 b_hnp_en; + + /* OTG inputs */ + u8 a_bus_drop; + u8 a_bus_req; + u8 a_clr_err; + u8 a_bus_resume; + u8 a_bus_suspend; + u8 a_conn; + u8 a_sess_vld; + u8 a_srp_det; + u8 a_vbus_vld; + u8 b_bus_req; /* B-Device Require Bus */ + u8 b_bus_resume; + u8 b_bus_suspend; + u8 b_conn; + u8 b_se0_srp; + u8 b_sess_end; + u8 b_sess_vld; + u8 id; + u8 a_suspend_req; + + /*Timer event */ + u8 a_aidl_bdis_timeout; + u8 b_ase0_brst_timeout; + u8 a_bidl_adis_timeout; + u8 a_wait_bcon_timeout; + + struct timer_list timer[OTG_TIMER_NUM]; +}; + +#define VUSBHS_MAX_PORTS 8 + +struct mv_otg_regs { + u32 usbcmd; /* Command register */ + u32 usbsts; /* Status register */ + u32 usbintr; /* Interrupt enable */ + u32 frindex; /* Frame index */ + u32 reserved1[1]; + u32 deviceaddr; /* Device Address */ + u32 eplistaddr; /* Endpoint List Address */ + u32 ttctrl; /* HOST TT status and control */ + u32 burstsize; /* Programmable Burst Size */ + u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */ + u32 reserved[4]; + u32 epnak; /* Endpoint NAK */ + u32 epnaken; /* Endpoint NAK Enable */ + u32 configflag; /* Configured Flag register */ + u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */ + u32 otgsc; + u32 usbmode; /* USB Host/Device mode */ + u32 epsetupstat; /* Endpoint Setup Status */ + u32 epprime; /* Endpoint Initialize */ + u32 epflush; /* Endpoint De-initialize */ + u32 epstatus; /* Endpoint Status */ + u32 epcomplete; /* Endpoint Interrupt On Complete */ + u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */ + u32 mcr; /* Mux Control */ + u32 isr; /* Interrupt Status */ + u32 ier; /* Interrupt Enable */ +}; + +struct mv_otg { + struct otg_transceiver otg; + struct mv_otg_ctrl otg_ctrl; + + /* base address */ + void __iomem *phy_regs; + void __iomem *cap_regs; + struct mv_otg_regs __iomem *op_regs; + + struct platform_device *pdev; + int irq; + u32 irq_status; + u32 irq_en; + + struct delayed_work work; + struct workqueue_struct *qwork; + + spinlock_t wq_lock; + + struct mv_usb_platform_data *pdata; + + unsigned int active; + unsigned int clock_gating; + unsigned int clknum; + struct clk *clk[0]; +}; + +#endif diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h index a642cf20ad6e..f4cb0ec373c3 100644 --- a/include/linux/platform_data/mv_usb.h +++ b/include/linux/platform_data/mv_usb.h @@ -42,6 +42,11 @@ struct mv_usb_platform_data { /* only valid for HCD. OTG or Host only*/ unsigned int mode; + /* This flag is used for that needs id pin checked by otg */ + unsigned int disable_otg_clock_gating:1; + /* Force a_bus_req to be asserted */ + unsigned int otg_force_a_bus_req:1; + int (*phy_init)(void __iomem *regbase); void (*phy_deinit)(void __iomem *regbase); int (*set_vbus)(unsigned int vbus); -- cgit v1.2.3 From 3a082ec9b2f544a81e977cfa259e3f990a995dc8 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Tue, 20 Dec 2011 13:20:23 +0800 Subject: USB: EHCI: Add Marvell Host Controller driver This patch adds support for EHCI compliant HSUSB Host controller found on Marvell Socs. It fits both OTG and SPH controller on marvell Socs, including PXA9xx/MMP2/MMP3/MGx. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/host/Kconfig | 9 + drivers/usb/host/ehci-hcd.c | 5 + drivers/usb/host/ehci-mv.c | 391 +++++++++++++++++++++++++++++++++++ include/linux/platform_data/mv_usb.h | 1 + 4 files changed, 406 insertions(+) create mode 100644 drivers/usb/host/ehci-mv.c (limited to 'include') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 060e0e2b1ae6..a52769b5c904 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -194,6 +194,15 @@ config USB_EHCI_S5P help Enable support for the S5P SOC's on-chip EHCI controller. +config USB_EHCI_MV + bool "EHCI support for Marvell on-chip controller" + depends on USB_EHCI_HCD + select USB_EHCI_ROOT_HUB_TT + ---help--- + Enables support for Marvell (including PXA and MMP series) on-chip + USB SPH and OTG controller. SPH is a single port host, and it can + only be EHCI host. OTG is controller that can switch to host mode. + config USB_W90X900_EHCI bool "W90X900(W90P910) EHCI support" depends on USB_EHCI_HCD && ARCH_W90X900 diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 3ff9f82f7263..b05e7533d08f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1329,6 +1329,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_xls_driver #endif +#ifdef CONFIG_USB_EHCI_MV +#include "ehci-mv.c" +#define PLATFORM_DRIVER ehci_mv_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ !defined(XILINX_OF_PLATFORM_DRIVER) diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c new file mode 100644 index 000000000000..52a604fb9321 --- /dev/null +++ b/drivers/usb/host/ehci-mv.c @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * Author: Chao Xie + * Neil Zhang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#define CAPLENGTH_MASK (0xff) + +struct ehci_hcd_mv { + struct usb_hcd *hcd; + + /* Which mode does this ehci running OTG/Host ? */ + int mode; + + void __iomem *phy_regs; + void __iomem *cap_regs; + void __iomem *op_regs; + + struct otg_transceiver *otg; + + struct mv_usb_platform_data *pdata; + + /* clock source and total clock number */ + unsigned int clknum; + struct clk *clk[0]; +}; + +static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) +{ + unsigned int i; + + for (i = 0; i < ehci_mv->clknum; i++) + clk_enable(ehci_mv->clk[i]); +} + +static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) +{ + unsigned int i; + + for (i = 0; i < ehci_mv->clknum; i++) + clk_disable(ehci_mv->clk[i]); +} + +static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) +{ + int retval; + + ehci_clock_enable(ehci_mv); + if (ehci_mv->pdata->phy_init) { + retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs); + if (retval) + return retval; + } + + return 0; +} + +static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) +{ + if (ehci_mv->pdata->phy_deinit) + ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs); + ehci_clock_disable(ehci_mv); +} + +static int mv_ehci_reset(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct device *dev = hcd->self.controller; + struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev); + int retval; + + if (ehci_mv == NULL) { + dev_err(dev, "Can not find private ehci data\n"); + return -ENODEV; + } + + /* + * data structure init + */ + retval = ehci_init(hcd); + if (retval) { + dev_err(dev, "ehci_init failed %d\n", retval); + return retval; + } + + hcd->has_tt = 1; + ehci->sbrn = 0x20; + + retval = ehci_reset(ehci); + if (retval) { + dev_err(dev, "ehci_reset failed %d\n", retval); + return retval; + } + + return 0; +} + +static const struct hc_driver mv_ehci_hc_driver = { + .description = hcd_name, + .product_desc = "Marvell EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = mv_ehci_reset, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +}; + +static int mv_ehci_probe(struct platform_device *pdev) +{ + struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct ehci_hcd_mv *ehci_mv; + struct resource *r; + int clk_i, retval = -ENODEV; + u32 offset; + size_t size; + + if (!pdata) { + dev_err(&pdev->dev, "missing platform_data\n"); + return -ENODEV; + } + + if (usb_disabled()) + return -ENODEV; + + hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci"); + if (!hcd) + return -ENOMEM; + + size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum; + ehci_mv = kzalloc(size, GFP_KERNEL); + if (ehci_mv == NULL) { + dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); + retval = -ENOMEM; + goto err_put_hcd; + } + + platform_set_drvdata(pdev, ehci_mv); + ehci_mv->pdata = pdata; + ehci_mv->hcd = hcd; + + ehci_mv->clknum = pdata->clknum; + for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) { + ehci_mv->clk[clk_i] = + clk_get(&pdev->dev, pdata->clkname[clk_i]); + if (IS_ERR(ehci_mv->clk[clk_i])) { + dev_err(&pdev->dev, "error get clck \"%s\"\n", + pdata->clkname[clk_i]); + retval = PTR_ERR(ehci_mv->clk[clk_i]); + goto err_put_clk; + } + } + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); + if (r == NULL) { + dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); + retval = -ENODEV; + goto err_put_clk; + } + + ehci_mv->phy_regs = ioremap(r->start, resource_size(r)); + if (ehci_mv->phy_regs == 0) { + dev_err(&pdev->dev, "failed to map phy I/O memory\n"); + retval = -EFAULT; + goto err_put_clk; + } + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); + if (!r) { + dev_err(&pdev->dev, "no I/O memory resource defined\n"); + retval = -ENODEV; + goto err_iounmap_phyreg; + } + + ehci_mv->cap_regs = ioremap(r->start, resource_size(r)); + if (ehci_mv->cap_regs == NULL) { + dev_err(&pdev->dev, "failed to map I/O memory\n"); + retval = -EFAULT; + goto err_iounmap_phyreg; + } + + retval = mv_ehci_enable(ehci_mv); + if (retval) { + dev_err(&pdev->dev, "init phy error %d\n", retval); + goto err_iounmap_capreg; + } + + offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; + ehci_mv->op_regs = + (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); + + hcd->rsrc_start = r->start; + hcd->rsrc_len = r->end - r->start + 1; + hcd->regs = ehci_mv->op_regs; + + hcd->irq = platform_get_irq(pdev, 0); + if (!hcd->irq) { + dev_err(&pdev->dev, "Cannot get irq."); + retval = -ENODEV; + goto err_disable_clk; + } + + ehci = hcd_to_ehci(hcd); + ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; + ehci->regs = (struct ehci_regs *) ehci_mv->op_regs; + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + ehci_mv->mode = pdata->mode; + if (ehci_mv->mode == MV_USB_MODE_OTG) { +#ifdef CONFIG_USB_OTG_UTILS + ehci_mv->otg = otg_get_transceiver(); + if (!ehci_mv->otg) { + dev_err(&pdev->dev, + "unable to find transceiver\n"); + retval = -ENODEV; + goto err_disable_clk; + } + + retval = otg_set_host(ehci_mv->otg, &hcd->self); + if (retval < 0) { + dev_err(&pdev->dev, + "unable to register with transceiver\n"); + retval = -ENODEV; + goto err_put_transceiver; + } + /* otg will enable clock before use as host */ + mv_ehci_disable(ehci_mv); +#else + dev_info(&pdev->dev, "MV_USB_MODE_OTG " + "must have CONFIG_USB_OTG_UTILS enabled\n"); + goto err_disable_clk; +#endif + } else { + if (pdata->set_vbus) + pdata->set_vbus(1); + + retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); + if (retval) { + dev_err(&pdev->dev, + "failed to add hcd with err %d\n", retval); + goto err_set_vbus; + } + } + + if (pdata->private_init) + pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs); + + dev_info(&pdev->dev, + "successful find EHCI device with regs 0x%p irq %d" + " working in %s mode\n", hcd->regs, hcd->irq, + ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host"); + + return 0; + +err_set_vbus: + if (pdata->set_vbus) + pdata->set_vbus(0); +#ifdef CONFIG_USB_OTG_UTILS +err_put_transceiver: + if (ehci_mv->otg) + otg_put_transceiver(ehci_mv->otg); +#endif +err_disable_clk: + mv_ehci_disable(ehci_mv); +err_iounmap_capreg: + iounmap(ehci_mv->cap_regs); +err_iounmap_phyreg: + iounmap(ehci_mv->phy_regs); +err_put_clk: + for (clk_i--; clk_i >= 0; clk_i--) + clk_put(ehci_mv->clk[clk_i]); + platform_set_drvdata(pdev, NULL); + kfree(ehci_mv); +err_put_hcd: + usb_put_hcd(hcd); + + return retval; +} + +static int mv_ehci_remove(struct platform_device *pdev) +{ + struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); + struct usb_hcd *hcd = ehci_mv->hcd; + int clk_i; + + if (hcd->rh_registered) + usb_remove_hcd(hcd); + + if (ehci_mv->otg) { + otg_set_host(ehci_mv->otg, NULL); + otg_put_transceiver(ehci_mv->otg); + } + + if (ehci_mv->mode == MV_USB_MODE_HOST) { + if (ehci_mv->pdata->set_vbus) + ehci_mv->pdata->set_vbus(0); + + mv_ehci_disable(ehci_mv); + } + + iounmap(ehci_mv->cap_regs); + iounmap(ehci_mv->phy_regs); + + for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) + clk_put(ehci_mv->clk[clk_i]); + + platform_set_drvdata(pdev, NULL); + + kfree(ehci_mv); + usb_put_hcd(hcd); + + return 0; +} + +MODULE_ALIAS("mv-ehci"); + +static const struct platform_device_id ehci_id_table[] = { + {"pxa-u2oehci", PXA_U2OEHCI}, + {"pxa-sph", PXA_SPH}, + {"mmp3-hsic", MMP3_HSIC}, + {"mmp3-fsic", MMP3_FSIC}, + {}, +}; + +static void mv_ehci_shutdown(struct platform_device *pdev) +{ + struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); + struct usb_hcd *hcd = ehci_mv->hcd; + + if (!hcd->rh_registered) + return; + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); +} + +static struct platform_driver ehci_mv_driver = { + .probe = mv_ehci_probe, + .remove = mv_ehci_remove, + .shutdown = mv_ehci_shutdown, + .driver = { + .name = "mv-ehci", + .bus = &platform_bus_type, + }, + .id_table = ehci_id_table, +}; diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h index f4cb0ec373c3..d94804aca764 100644 --- a/include/linux/platform_data/mv_usb.h +++ b/include/linux/platform_data/mv_usb.h @@ -50,6 +50,7 @@ struct mv_usb_platform_data { int (*phy_init)(void __iomem *regbase); void (*phy_deinit)(void __iomem *regbase); int (*set_vbus)(unsigned int vbus); + int (*private_init)(void __iomem *opregs, void __iomem *phyregs); }; #ifndef CONFIG_HAVE_CLK -- cgit v1.2.3 From 715a3e41e78a40e1e711298667435d5a2cef1972 Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Mon, 19 Dec 2011 19:39:15 +0100 Subject: usb: gadget: s3c-hsudc: move platform_data struct to global header Gadget drivers should be compilable on all architectures. This patch removes one dependency on architecture-specific code. Acked-by: Kukjin Kim Signed-off-by: Heiko Stuebner Signed-off-by: Felipe Balbi --- arch/arm/mach-s3c2416/mach-smdk2416.c | 1 + arch/arm/plat-samsung/devs.c | 1 + arch/arm/plat-samsung/include/plat/udc.h | 15 +------------- drivers/usb/gadget/s3c-hsudc.c | 2 +- include/linux/platform_data/s3c-hsudc.h | 34 ++++++++++++++++++++++++++++++++ 5 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 include/linux/platform_data/s3c-hsudc.h (limited to 'include') diff --git a/arch/arm/mach-s3c2416/mach-smdk2416.c b/arch/arm/mach-s3c2416/mach-smdk2416.c index a9eee531ca76..6345bcbf5c73 100644 --- a/arch/arm/mach-s3c2416/mach-smdk2416.c +++ b/arch/arm/mach-s3c2416/mach-smdk2416.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 4ca8b571f971..92b4c025d37a 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/plat-samsung/include/plat/udc.h b/arch/arm/plat-samsung/include/plat/udc.h index 8c22d586befb..de8e2288a509 100644 --- a/arch/arm/plat-samsung/include/plat/udc.h +++ b/arch/arm/plat-samsung/include/plat/udc.h @@ -37,20 +37,7 @@ struct s3c2410_udc_mach_info { extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *); -/** - * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller. - * @epnum: Number of endpoints to be instantiated by the controller driver. - * @gpio_init: Platform specific USB related GPIO initialization. - * @gpio_uninit: Platform specific USB releted GPIO uninitialzation. - * - * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget - * controllers. - */ -struct s3c24xx_hsudc_platdata { - unsigned int epnum; - void (*gpio_init)(void); - void (*gpio_uninit)(void); -}; +struct s3c24xx_hsudc_platdata; extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index f398b8590f9c..2f9f8409031b 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -28,9 +28,9 @@ #include #include #include +#include #include -#include #define S3C_HSUDC_REG(x) (x) diff --git a/include/linux/platform_data/s3c-hsudc.h b/include/linux/platform_data/s3c-hsudc.h new file mode 100644 index 000000000000..6fa109339bf9 --- /dev/null +++ b/include/linux/platform_data/s3c-hsudc.h @@ -0,0 +1,34 @@ +/* + * S3C24XX USB 2.0 High-speed USB controller gadget driver + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints. + * Each endpoint can be configured as either in or out endpoint. Endpoints + * can be configured for Bulk or Interrupt transfer mode. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __LINUX_USB_S3C_HSUDC_H +#define __LINUX_USB_S3C_HSUDC_H + +/** + * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller. + * @epnum: Number of endpoints to be instantiated by the controller driver. + * @gpio_init: Platform specific USB related GPIO initialization. + * @gpio_uninit: Platform specific USB releted GPIO uninitialzation. + * + * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget + * controllers. + */ +struct s3c24xx_hsudc_platdata { + unsigned int epnum; + void (*gpio_init)(void); + void (*gpio_uninit)(void); +}; + +#endif /* __LINUX_USB_S3C_HSUDC_H */ -- cgit v1.2.3 From 898c60867827796f0f6f84e5de446098d776c866 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 22 Nov 2011 11:11:50 +0200 Subject: usb: gadget: introduce support for sg lists Some controllers support scatter/gather transfers and that might be very useful for some gadget drivers. This means that we can make use of larger buffer allocations which means we will have less completion IRQs overtime, thus improving the perceived performance. Signed-off-by: Felipe Balbi --- include/linux/usb/gadget.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 4d99805bcbb7..da653b5c7134 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,9 @@ struct usb_ep; * @dma: DMA address corresponding to 'buf'. If you don't set this * field, and the usb controller needs one, it is responsible * for mapping and unmapping the buffer. + * @sg: a scatterlist for SG-capable controllers. + * @num_sgs: number of SG entries + * @num_mapped_sgs: number of SG entries mapped to DMA (internal) * @length: Length of that data * @stream_id: The stream id, when USB3.0 bulk streams are being used * @no_interrupt: If true, hints that no completion irq is needed. @@ -88,6 +92,10 @@ struct usb_request { unsigned length; dma_addr_t dma; + struct scatterlist *sg; + unsigned num_sgs; + unsigned num_mapped_sgs; + unsigned stream_id:16; unsigned no_interrupt:1; unsigned zero:1; @@ -479,6 +487,7 @@ struct usb_gadget_ops { * @speed: Speed of current connection to USB host. * @max_speed: Maximal speed the UDC can handle. UDC must support this * and all slower speeds. + * @sg_supported: true if we can handle scatter-gather * @is_otg: True if the USB device port uses a Mini-AB jack, so that the * gadget driver must provide a USB OTG descriptor. * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable @@ -519,6 +528,7 @@ struct usb_gadget { struct list_head ep_list; /* of usb_ep */ enum usb_device_speed speed; enum usb_device_speed max_speed; + unsigned sg_supported:1; unsigned is_otg:1; unsigned is_a_peripheral:1; unsigned b_hnp_enable:1; -- cgit v1.2.3 From 18b7ede5f7ee2092aedcb578d3ac30bd5d4fc23c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 2 Jan 2012 13:35:41 +0200 Subject: usb: ch9: fix up MaxStreams helper According to USB 3.0 Specification Table 9-22, if bmAttributes [4:0] are set to zero, it means "no streams supported", but the way this helper was defined on Linux, we will *always* have one stream which might cause several problems. For example on DWC3, we would tell the controller endpoint has streams enabled and yet start transfers with Stream ID set to 0, which would goof up the host side. While doing that, convert the macro to an inline function due to the different checks we now need. Signed-off-by: Felipe Balbi Signed-off-by: Sarah Sharp Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 3 +-- drivers/usb/host/xhci.c | 3 +-- include/linux/usb/ch9.h | 20 +++++++++++++++++++- 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4c6bedad51fd..a696bde53222 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -297,8 +297,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN | DWC3_DEPCFG_XFER_NOT_READY_EN; - if (comp_desc && USB_SS_MAX_STREAMS(comp_desc->bmAttributes) - && usb_endpoint_xfer_bulk(desc)) { + if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) { params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE | DWC3_DEPCFG_STREAM_EVENT_EN; dep->stream_capable = true; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f3d0b8d96440..dda84756c465 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2799,8 +2799,7 @@ static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci, if (ret < 0) return ret; - max_streams = USB_SS_MAX_STREAMS( - eps[i]->ss_ep_comp.bmAttributes); + max_streams = usb_ss_max_streams(&eps[i]->ss_ep_comp); if (max_streams < (*num_streams - 1)) { xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n", eps[i]->desc.bEndpointAddress, diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index d5da6c68c250..61b29057b054 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -605,8 +605,26 @@ struct usb_ss_ep_comp_descriptor { } __attribute__ ((packed)); #define USB_DT_SS_EP_COMP_SIZE 6 + /* Bits 4:0 of bmAttributes if this is a bulk endpoint */ -#define USB_SS_MAX_STREAMS(p) (1 << ((p) & 0x1f)) +static inline int +usb_ss_max_streams(const struct usb_ss_ep_comp_descriptor *comp) +{ + int max_streams; + + if (!comp) + return 0; + + max_streams = comp->bmAttributes & 0x1f; + + if (!max_streams) + return 0; + + max_streams = 1 << max_streams; + + return max_streams; +} + /* Bits 1:0 of bmAttributes if this is an isoc endpoint */ #define USB_SS_MULT(p) (1 + ((p) & 0x3)) -- cgit v1.2.3