From 5f9f975b7984ffec0a25f55e58246aebf68794f4 Mon Sep 17 00:00:00 2001 From: Mark Knibbs Date: Sat, 4 Oct 2014 12:19:59 +0100 Subject: USB: serial: keyspan_pda: fix Entrega company name spelling Entrega is misspelled as Entregra or Entrgra, so fix that. Signed-off-by: Mark Knibbs Signed-off-by: Johan Hovold diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 5bd7926..947fa62 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -145,7 +145,7 @@ Keyspan PDA Serial Adapter Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly sold in Macintosh catalogs, comes in a translucent white/green dongle). Fairly simple device. Firmware is homebrew. - This driver also works for the Xircom/Entrgra single port serial adapter. + This driver also works for the Xircom/Entrega single port serial adapter. Current status: Things that work: diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index a69f7cd..d185613 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -606,10 +606,10 @@ config USB_SERIAL_CYBERJACK If unsure, say N. config USB_SERIAL_XIRCOM - tristate "USB Xircom / Entregra Single Port Serial Driver" + tristate "USB Xircom / Entrega Single Port Serial Driver" select USB_EZUSB_FX2 help - Say Y here if you want to use a Xircom or Entregra single port USB to + Say Y here if you want to use a Xircom or Entrega single port USB to serial converter device. This driver makes use of firmware developed from scratch by Brian Warner. diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 742d827..dd97d8b 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -1,5 +1,5 @@ /* - * USB Keyspan PDA / Xircom / Entregra Converter driver + * USB Keyspan PDA / Xircom / Entrega Converter driver * * Copyright (C) 1999 - 2001 Greg Kroah-Hartman * Copyright (C) 1999, 2000 Brian Warner @@ -58,11 +58,11 @@ struct keyspan_pda_private { #define KEYSPAN_PDA_FAKE_ID 0x0103 #define KEYSPAN_PDA_ID 0x0104 /* no clue */ -/* For Xircom PGSDB9 and older Entregra version of the same device */ +/* For Xircom PGSDB9 and older Entrega version of the same device */ #define XIRCOM_VENDOR_ID 0x085a #define XIRCOM_FAKE_ID 0x8027 -#define ENTREGRA_VENDOR_ID 0x1645 -#define ENTREGRA_FAKE_ID 0x8093 +#define ENTREGA_VENDOR_ID 0x1645 +#define ENTREGA_FAKE_ID 0x8093 static const struct usb_device_id id_table_combined[] = { #ifdef KEYSPAN @@ -70,7 +70,7 @@ static const struct usb_device_id id_table_combined[] = { #endif #ifdef XIRCOM { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, - { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) }, + { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, #endif { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, { } /* Terminating entry */ @@ -93,7 +93,7 @@ static const struct usb_device_id id_table_fake[] = { #ifdef XIRCOM static const struct usb_device_id id_table_fake_xircom[] = { { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, - { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) }, + { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, { } }; #endif @@ -667,7 +667,7 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) #endif #ifdef XIRCOM else if ((le16_to_cpu(serial->dev->descriptor.idVendor) == XIRCOM_VENDOR_ID) || - (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGRA_VENDOR_ID)) + (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGA_VENDOR_ID)) fw_name = "keyspan_pda/xircom_pgs.fw"; #endif else { @@ -744,7 +744,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = { .owner = THIS_MODULE, .name = "xircom_no_firm", }, - .description = "Xircom / Entregra PGS - (prerenumeration)", + .description = "Xircom / Entrega PGS - (prerenumeration)", .id_table = id_table_fake_xircom, .num_ports = 1, .attach = keyspan_pda_fake_startup, -- cgit v0.10.2 From 811c37078042980b5b9ed6845303a3cc9e6d48e3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Oct 2014 09:07:32 +0100 Subject: USB: kobil_sct: replace unnecessary atomic allocation Use GFP_KERNEL instead of GFP_ATOMIC for allocation in open(), which may sleep. Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 078f9ed..a65042c 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -244,7 +244,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { /* start reading (Adapter B 'cause PNP string) */ - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); dev_dbg(dev, "%s - Send read URB returns: %i\n", __func__, result); } -- cgit v0.10.2 From 1dbd11be69927d2d119e900f5487a01ad09a26b8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Oct 2014 09:07:33 +0100 Subject: USB: mos7720: replace unnecessary atomic allocations Use GFP_KERNEL instead of GFP_ATOMIC for allocations in set_termios and port-setting helper which both may and do sleep. Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index dfd728a..312b0fe 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1657,7 +1657,7 @@ static void change_port_settings(struct tty_struct *tty, write_mos_reg(serial, port_number, IER, 0x0c); if (port->read_urb->status != -EINPROGRESS) { - status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + status = usb_submit_urb(port->read_urb, GFP_KERNEL); if (status) dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); } @@ -1702,7 +1702,7 @@ static void mos7720_set_termios(struct tty_struct *tty, change_port_settings(tty, mos7720_port, old_termios); if (port->read_urb->status != -EINPROGRESS) { - status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + status = usb_submit_urb(port->read_urb, GFP_KERNEL); if (status) dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); } -- cgit v0.10.2 From 9d3801903851a2be51f0b2d85f25f952a7da9969 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Oct 2014 09:07:34 +0100 Subject: USB: mos7840: replace unnecessary atomic allocations Use GFP_KERNEL instead of GFP_ATOMIC for allocations in set_termios and port-setting helper which both may and do sleep. Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 3d88eef..220b4be 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1904,7 +1904,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (mos7840_port->read_urb_busy == false) { mos7840_port->read_urb_busy = true; - status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); + status = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL); if (status) { dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); @@ -1968,7 +1968,7 @@ static void mos7840_set_termios(struct tty_struct *tty, if (mos7840_port->read_urb_busy == false) { mos7840_port->read_urb_busy = true; - status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); + status = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL); if (status) { dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); -- cgit v0.10.2 From fa0ea13e9f1c2b4707879ca3dbe4cf29c741857a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 19 Sep 2014 15:51:11 -0500 Subject: usb: dwc3: core: write LINUX_VERSION_CODE to our GUID register DWC3's GUID register is supposed to be used to write any sort of version we might want. It helps when getting bug reports for platforms you don't have HW to know which kernel version of the driver was running on the platform. Because we don't really track driver version, but we _do_ track the kernel version, let's write LINUX_VERSION_CODE to that register and use it for debugging. Reviewed-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b0f4d52..ddfe771 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -19,6 +19,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -384,6 +385,12 @@ static int dwc3_core_init(struct dwc3 *dwc) } dwc->revision = reg; + /* + * Write Linux Version Code to our GUID register so it's easy to figure + * out which kernel version a bug was found. + */ + dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); + /* Handle USB2.0-only core configuration */ if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { -- cgit v0.10.2 From dab716cd9aeea6f2b2524523461326aefa219291 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Sep 2014 11:22:23 -0500 Subject: usb: dwc3: trace: remove unnecessary newline character tracing infrastructure already adds those for us. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 711b230..df964d8 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -700,35 +700,35 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) switch (ctrl->bRequest) { case USB_REQ_GET_STATUS: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_GET_STATUS\n"); + dwc3_trace(trace_dwc3_ep0, "USB_REQ_GET_STATUS"); ret = dwc3_ep0_handle_status(dwc, ctrl); break; case USB_REQ_CLEAR_FEATURE: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_CLEAR_FEATURE\n"); + dwc3_trace(trace_dwc3_ep0, "USB_REQ_CLEAR_FEATURE"); ret = dwc3_ep0_handle_feature(dwc, ctrl, 0); break; case USB_REQ_SET_FEATURE: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_FEATURE\n"); + dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_FEATURE"); ret = dwc3_ep0_handle_feature(dwc, ctrl, 1); break; case USB_REQ_SET_ADDRESS: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ADDRESS\n"); + dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ADDRESS"); ret = dwc3_ep0_set_address(dwc, ctrl); break; case USB_REQ_SET_CONFIGURATION: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_CONFIGURATION\n"); + dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_CONFIGURATION"); ret = dwc3_ep0_set_config(dwc, ctrl); break; case USB_REQ_SET_SEL: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_SEL\n"); + dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_SEL"); ret = dwc3_ep0_set_sel(dwc, ctrl); break; case USB_REQ_SET_ISOCH_DELAY: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY\n"); + dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY"); ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); break; default: - dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver\n"); + dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver"); ret = dwc3_ep0_delegate_req(dwc, ctrl); break; } @@ -875,7 +875,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (status == DWC3_TRBSTS_SETUP_PENDING) - dwc3_trace(trace_dwc3_ep0, "Setup Pending received\n"); + dwc3_trace(trace_dwc3_ep0, "Setup Pending received"); dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 60b0f41..7a9d780 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -61,7 +61,7 @@ DECLARE_EVENT_CLASS(dwc3_log_event, TP_fast_assign( __entry->event = event; ), - TP_printk("event %08x\n", __entry->event) + TP_printk("event %08x", __entry->event) ); DEFINE_EVENT(dwc3_log_event, dwc3_event, @@ -157,7 +157,7 @@ DECLARE_EVENT_CLASS(dwc3_log_generic_cmd, __entry->cmd = cmd; __entry->param = param; ), - TP_printk("cmd '%s' [%d] param %08x\n", + TP_printk("cmd '%s' [%d] param %08x", dwc3_gadget_generic_cmd_string(__entry->cmd), __entry->cmd, __entry->param ) @@ -182,7 +182,7 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd, __entry->cmd = cmd; __entry->params = params; ), - TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x\n", + TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x", __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd), __entry->cmd, __entry->params->param0, __entry->params->param1, __entry->params->param2 @@ -214,7 +214,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, __entry->size = trb->size; __entry->ctrl = trb->ctrl; ), - TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x\n", + TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x", __get_str(name), __entry->trb, __entry->bph, __entry->bpl, __entry->size, __entry->ctrl ) -- cgit v0.10.2 From 19bacdc925055f020ad36da04bd72dc8b28637b8 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 24 Sep 2014 11:00:38 +0300 Subject: usb: dwc3: core: only setting the dma_mask when needed If the probe drivers have already set the dma_mask, not replacing the value. Signed-off-by: Heikki Krogerus Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ddfe771..1384300 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -715,9 +715,11 @@ static int dwc3_probe(struct platform_device *pdev) spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); - dev->dma_mask = dev->parent->dma_mask; - dev->dma_parms = dev->parent->dma_parms; - dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); + if (!dev->dma_mask) { + dev->dma_mask = dev->parent->dma_mask; + dev->dma_parms = dev->parent->dma_parms; + dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); + } pm_runtime_enable(dev); pm_runtime_get_sync(dev); -- cgit v0.10.2 From 404905a604d8565b62a2889c5045acf57aa434be Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 25 Sep 2014 10:57:02 +0300 Subject: usb: dwc3: add ACPI support Adding ACPI ID used on newer Intel SoCs. Signed-off-by: Heikki Krogerus Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 1384300..4d4e854 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -967,12 +968,24 @@ static const struct of_device_id of_dwc3_match[] = { MODULE_DEVICE_TABLE(of, of_dwc3_match); #endif +#ifdef CONFIG_ACPI + +#define ACPI_ID_INTEL_BSW "808622B7" + +static const struct acpi_device_id dwc3_acpi_match[] = { + { ACPI_ID_INTEL_BSW, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); +#endif + static struct platform_driver dwc3_driver = { .probe = dwc3_probe, .remove = dwc3_remove, .driver = { .name = "dwc3", .of_match_table = of_match_ptr(of_dwc3_match), + .acpi_match_table = ACPI_PTR(dwc3_acpi_match), .pm = DWC3_PM_OPS, }, }; -- cgit v0.10.2 From 6c93b5342374b3ff2a8beac050ed6e07373cbe95 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 18 Sep 2014 09:51:23 -0500 Subject: usb: gadget: composite: introduce setup and os_desc pending flags These flags we be set to true whenever their matching request is queued. They will be cleared to false when that request completes. Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index c330f5e..ed3811c 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -427,6 +427,8 @@ static inline struct usb_composite_driver *to_cdriver( * @b_vendor_code: bMS_VendorCode part of the OS string * @use_os_string: false by default, interested gadgets set it * @os_desc_config: the configuration to be used with OS descriptors + * @setup_pending: true when setup request is queued but not completed + * @os_desc_pending: true when os_desc request is queued but not completed * * One of these devices is allocated and initialized before the * associated device driver's bind() is called. @@ -488,6 +490,9 @@ struct usb_composite_dev { /* protects deactivations and delayed_status counts*/ spinlock_t lock; + + unsigned setup_pending:1; + unsigned os_desc_pending:1; }; extern int usb_string_id(struct usb_composite_dev *c); -- cgit v0.10.2 From 57943716ff1b0733ab0d9879e572bad04166660a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 18 Sep 2014 09:54:54 -0500 Subject: usb: gadget: composite: set our req->context to cdev by doing that we will be able to match our requests against req and os_desc_req and also clear our pending flags from complete callback. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f6a51fd..09602dc 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1428,6 +1428,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * when we delegate to it. */ req->zero = 0; + req->context = cdev; req->complete = composite_setup_complete; req->length = 0; gadget->ep0->driver_data = cdev; @@ -1624,6 +1625,7 @@ unknown: int count = 0; req = cdev->os_desc_req; + req->context = cdev; req->complete = composite_setup_complete; buf = req->buf; os_desc_cfg = cdev->os_desc_config; @@ -1686,6 +1688,7 @@ unknown: break; } req->length = value; + req->context = cdev; req->zero = value < w_length; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { @@ -1757,6 +1760,7 @@ unknown: /* respond with data transfer before status phase? */ if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) { req->length = value; + req->context = cdev; req->zero = value < w_length; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { @@ -1893,6 +1897,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite, goto fail_dev; cdev->req->complete = composite_setup_complete; + cdev->req->context = cdev; gadget->ep0->driver_data = cdev; cdev->driver = composite; @@ -1937,6 +1942,7 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, kfree(cdev->os_desc_req); goto end; } + cdev->os_desc_req->context = cdev; cdev->os_desc_req->complete = composite_setup_complete; end: return ret; @@ -2158,6 +2164,7 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) } else if (--cdev->delayed_status == 0) { DBG(cdev, "%s: Completing delayed status\n", __func__); req->length = 0; + req->context = cdev; value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); -- cgit v0.10.2 From a7c12eaf2e5eea0c15242ebb7d1d3b6e7fcb62bb Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 18 Sep 2014 10:01:55 -0500 Subject: usb: gadget: composite: conditionally dequeue os_desc and setup requests In case we unload a gadget driver while any of os_desc_req or req are still pending, we need to make sure to dequeue them. By using our setup_pending and os_desc_pending flags we achieve that in a way that doesn't cause any regressions because we won't dequeue a request which was already completed. The original idea came from Li Jun's commit f2267089ea17fa97b796b1b4247e3f8957655df3 (usb: gadget: composite: dequeue cdev->req before free it in composite_dev_cleanup) which, unfortunately, caused two regressions (kfree() being called before usb_ep_dequeue() and calling usb_ep_dequeue() when the request was already completed). That commit also didn't take care of os_desc_req which can fall into the same situation so we must care for that one too. Note that in order to make code slightly easier to read, we introduce composite_ep_queue() which hides details about how to fiddle with our pending flags. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 09602dc..e071d58 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1246,10 +1246,49 @@ EXPORT_SYMBOL_GPL(usb_string_ids_n); static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) { + struct usb_composite_dev *cdev; + if (req->status || req->actual != req->length) DBG((struct usb_composite_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); + + /* + * REVIST The same ep0 requests are shared with function drivers + * so they don't have to maintain the same ->complete() stubs. + * + * Because of that, we need to check for the validity of ->context + * here, even though we know we've set it to something useful. + */ + if (!req->context) + return; + + cdev = req->context; + + if (cdev->req == req) + cdev->setup_pending = false; + else if (cdev->os_desc_req == req) + cdev->os_desc_pending = false; + else + WARN(1, "unknown request %p\n", req); +} + +static int composite_ep0_queue(struct usb_composite_dev *cdev, + struct usb_request *req, gfp_t gfp_flags) +{ + int ret; + + ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags); + if (ret == 0) { + if (cdev->req == req) + cdev->setup_pending = true; + else if (cdev->os_desc_req == req) + cdev->os_desc_pending = true; + else + WARN(1, "unknown request %p\n", req); + } + + return ret; } static int count_ext_compat(struct usb_configuration *c) @@ -1690,7 +1729,7 @@ unknown: req->length = value; req->context = cdev; req->zero = value < w_length; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + value = composite_ep0_queue(cdev, req, GFP_ATOMIC); if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); req->status = 0; @@ -1762,7 +1801,7 @@ unknown: req->length = value; req->context = cdev; req->zero = value < w_length; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + value = composite_ep0_queue(cdev, req, GFP_ATOMIC); if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); req->status = 0; @@ -1957,10 +1996,16 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) kfree(uc); } if (cdev->os_desc_req) { + if (cdev->os_desc_pending) + usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req); + kfree(cdev->os_desc_req->buf); usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); } if (cdev->req) { + if (cdev->setup_pending) + usb_ep_dequeue(cdev->gadget->ep0, cdev->req); + kfree(cdev->req->buf); usb_ep_free_request(cdev->gadget->ep0, cdev->req); } @@ -2165,7 +2210,7 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) DBG(cdev, "%s: Completing delayed status\n", __func__); req->length = 0; req->context = cdev; - value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + value = composite_ep0_queue(cdev, req, GFP_ATOMIC); if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); req->status = 0; -- cgit v0.10.2 From ccb072de5702a50270172e8613db186d136fce16 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 1 Oct 2014 12:20:29 -0500 Subject: usb: dwc3: ep0: trace ep0 TRBs too Add TRB tracepoints for ep0 TRBs as that might help finding bugs with ep0 handling. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index df964d8..4c86772 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -86,6 +86,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, params.param0 = upper_32_bits(dwc->ep0_trb_addr); params.param1 = lower_32_bits(dwc->ep0_trb_addr); + trace_dwc3_prepare_trb(dep, trb); + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_STARTTRANSFER, ¶ms); if (ret < 0) { @@ -791,6 +793,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, trb = dwc->ep0_trb; + trace_dwc3_complete_trb(ep0, trb); + status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (status == DWC3_TRBSTS_SETUP_PENDING) { dwc3_trace(trace_dwc3_ep0, "Setup Pending received"); @@ -855,6 +859,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, dep = dwc->eps[0]; trb = dwc->ep0_trb; + trace_dwc3_complete_trb(dep, trb); + if (!list_empty(&dep->request_list)) { r = next_request(&dep->request_list); -- cgit v0.10.2 From c042b85a2cbb0c612e9ed3c7ea1af684bba5dcd3 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 7 Oct 2014 12:43:04 +0900 Subject: usb: renesas_usbhs: rename phy to usb_phy in usbhs_priv To support a generic phy driver in this driver later, this patch renames "struct usb_phy *phy" to "struct usb_phy *usb_phy". Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index a7996da..e0d53c5 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -269,7 +269,7 @@ struct usbhs_priv { */ struct usbhs_fifo_info fifo_info; - struct usb_phy *phy; + struct usb_phy *usb_phy; }; /* diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c index e6b9dcc..f264cad 100644 --- a/drivers/usb/renesas_usbhs/rcar2.c +++ b/drivers/usb/renesas_usbhs/rcar2.c @@ -20,13 +20,13 @@ static int usbhs_rcar2_hardware_init(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - struct usb_phy *phy; + struct usb_phy *usb_phy; - phy = usb_get_phy_dev(&pdev->dev, 0); - if (IS_ERR(phy)) - return PTR_ERR(phy); + usb_phy = usb_get_phy_dev(&pdev->dev, 0); + if (IS_ERR(usb_phy)) + return PTR_ERR(usb_phy); - priv->phy = phy; + priv->usb_phy = usb_phy; return 0; } @@ -34,11 +34,11 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - if (!priv->phy) + if (!priv->usb_phy) return 0; - usb_put_phy(priv->phy); - priv->phy = NULL; + usb_put_phy(priv->usb_phy); + priv->usb_phy = NULL; return 0; } @@ -48,19 +48,19 @@ static int usbhs_rcar2_power_ctrl(struct platform_device *pdev, { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - if (!priv->phy) + if (!priv->usb_phy) return -ENODEV; if (enable) { - int retval = usb_phy_init(priv->phy); + int retval = usb_phy_init(priv->usb_phy); if (!retval) - retval = usb_phy_set_suspend(priv->phy, 0); + retval = usb_phy_set_suspend(priv->usb_phy, 0); return retval; } - usb_phy_set_suspend(priv->phy, 1); - usb_phy_shutdown(priv->phy); + usb_phy_set_suspend(priv->usb_phy, 1); + usb_phy_shutdown(priv->usb_phy); return 0; } -- cgit v0.10.2 From 5f6aea3453ccafc0c3e16f9f7db79ce91b377e9a Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 7 Oct 2014 12:43:05 +0900 Subject: usb: renesas_usbhs: clean up rcar2.c to support a generic PHY To support both usb PHY and generic PHY, this patch cleans up rcar2.c. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c index f264cad..485b889 100644 --- a/drivers/usb/renesas_usbhs/rcar2.c +++ b/drivers/usb/renesas_usbhs/rcar2.c @@ -20,25 +20,28 @@ static int usbhs_rcar2_hardware_init(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - struct usb_phy *usb_phy; - usb_phy = usb_get_phy_dev(&pdev->dev, 0); - if (IS_ERR(usb_phy)) - return PTR_ERR(usb_phy); + if (IS_ENABLED(CONFIG_USB_PHY)) { + struct usb_phy *usb_phy = usb_get_phy_dev(&pdev->dev, 0); - priv->usb_phy = usb_phy; - return 0; + if (IS_ERR(usb_phy)) + return PTR_ERR(usb_phy); + + priv->usb_phy = usb_phy; + return 0; + } + + return -ENXIO; } static int usbhs_rcar2_hardware_exit(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - if (!priv->usb_phy) - return 0; - - usb_put_phy(priv->usb_phy); - priv->usb_phy = NULL; + if (priv->usb_phy) { + usb_put_phy(priv->usb_phy); + priv->usb_phy = NULL; + } return 0; } @@ -47,21 +50,22 @@ static int usbhs_rcar2_power_ctrl(struct platform_device *pdev, void __iomem *base, int enable) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + int retval = -ENODEV; - if (!priv->usb_phy) - return -ENODEV; + if (priv->usb_phy) { + if (enable) { + retval = usb_phy_init(priv->usb_phy); - if (enable) { - int retval = usb_phy_init(priv->usb_phy); - - if (!retval) - retval = usb_phy_set_suspend(priv->usb_phy, 0); - return retval; + if (!retval) + retval = usb_phy_set_suspend(priv->usb_phy, 0); + } else { + usb_phy_set_suspend(priv->usb_phy, 1); + usb_phy_shutdown(priv->usb_phy); + retval = 0; + } } - usb_phy_set_suspend(priv->usb_phy, 1); - usb_phy_shutdown(priv->usb_phy); - return 0; + return retval; } static int usbhs_rcar2_get_id(struct platform_device *pdev) -- cgit v0.10.2 From 420974a0ed2d9da76637c2c2dc9324850e4f9a24 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 7 Oct 2014 12:43:06 +0900 Subject: usb: renesas_usbhs: add support for generic PHY This patch adds support for the generic PHY. The generic PHY will be used in multiplatform environment. Acked-by: Kishon Vijay Abraham I Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index e0d53c5..c45667f 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -270,6 +270,7 @@ struct usbhs_priv { struct usbhs_fifo_info fifo_info; struct usb_phy *usb_phy; + struct phy *phy; }; /* diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c index 485b889..8fc15c0 100644 --- a/drivers/usb/renesas_usbhs/rcar2.c +++ b/drivers/usb/renesas_usbhs/rcar2.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include "common.h" @@ -21,6 +22,16 @@ static int usbhs_rcar2_hardware_init(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + if (IS_ENABLED(CONFIG_GENERIC_PHY)) { + struct phy *phy = phy_get(&pdev->dev, "usb"); + + if (IS_ERR(phy)) + return PTR_ERR(phy); + + priv->phy = phy; + return 0; + } + if (IS_ENABLED(CONFIG_USB_PHY)) { struct usb_phy *usb_phy = usb_get_phy_dev(&pdev->dev, 0); @@ -38,6 +49,11 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + if (priv->phy) { + phy_put(priv->phy); + priv->phy = NULL; + } + if (priv->usb_phy) { usb_put_phy(priv->usb_phy); priv->usb_phy = NULL; @@ -52,6 +68,19 @@ static int usbhs_rcar2_power_ctrl(struct platform_device *pdev, struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); int retval = -ENODEV; + if (priv->phy) { + if (enable) { + retval = phy_init(priv->phy); + + if (!retval) + retval = phy_power_on(priv->phy); + } else { + phy_power_off(priv->phy); + phy_exit(priv->phy); + retval = 0; + } + } + if (priv->usb_phy) { if (enable) { retval = usb_phy_init(priv->usb_phy); -- cgit v0.10.2 From 2db88a76960747fb1af3757a81b94451c4bdfc49 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 1 Oct 2014 22:06:14 +0200 Subject: usb: gadget: pxa27x_udc: prepare device-tree support For this preparation, a preliminary cleanup is done : - convert the probing of pxa27x_udc to gpio_desc. The conversion is partial because : - the platform data still provides a gpio number, not a gpio desc Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 4868369..d583197 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1507,17 +1508,12 @@ static struct usb_ep_ops pxa_ep_ops = { */ static void dplus_pullup(struct pxa_udc *udc, int on) { - if (on) { - if (gpio_is_valid(udc->mach->gpio_pullup)) - gpio_set_value(udc->mach->gpio_pullup, - !udc->mach->gpio_pullup_inverted); - if (udc->mach->udc_command) + if (udc->gpiod) { + gpiod_set_value(udc->gpiod, on); + } else if (udc->mach && udc->mach->udc_command) { + if (on) udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); - } else { - if (gpio_is_valid(udc->mach->gpio_pullup)) - gpio_set_value(udc->mach->gpio_pullup, - udc->mach->gpio_pullup_inverted); - if (udc->mach->udc_command) + else udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } udc->pullup_on = on; @@ -1609,7 +1605,7 @@ static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active) { struct pxa_udc *udc = to_gadget_udc(_gadget); - if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) + if (!udc->gpiod && !udc->mach->udc_command) return -EOPNOTSUPP; dplus_pullup(udc, is_active); @@ -2416,6 +2412,22 @@ static int pxa_udc_probe(struct platform_device *pdev) struct resource *regs; struct pxa_udc *udc = &memory; int retval = 0, gpio; + struct pxa2xx_udc_mach_info *mach = dev_get_platdata(&pdev->dev); + unsigned long gpio_flags; + + if (mach) { + gpio_flags = mach->gpio_pullup_inverted ? GPIOF_ACTIVE_LOW : 0; + gpio = mach->gpio_pullup; + if (gpio_is_valid(gpio)) { + retval = devm_gpio_request_one(&pdev->dev, gpio, + gpio_flags, + "USB D+ pullup"); + if (retval) + return retval; + udc->gpiod = gpio_to_desc(mach->gpio_pullup); + } + udc->mach = mach; + } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) @@ -2425,21 +2437,15 @@ static int pxa_udc_probe(struct platform_device *pdev) return udc->irq; udc->dev = &pdev->dev; - udc->mach = dev_get_platdata(&pdev->dev); udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); - gpio = udc->mach->gpio_pullup; - if (gpio_is_valid(gpio)) { - retval = gpio_request(gpio, "USB D+ pullup"); - if (retval == 0) - gpio_direction_output(gpio, - udc->mach->gpio_pullup_inverted); - } - if (retval) { - dev_err(&pdev->dev, "Couldn't request gpio %d : %d\n", - gpio, retval); - return retval; + if (IS_ERR(udc->gpiod)) { + dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n", + PTR_ERR(udc->gpiod)); + return PTR_ERR(udc->gpiod); } + if (udc->gpiod) + gpiod_direction_output(udc->gpiod, 0); udc->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(udc->clk)) { @@ -2501,14 +2507,11 @@ err_clk: static int pxa_udc_remove(struct platform_device *_dev) { struct pxa_udc *udc = platform_get_drvdata(_dev); - int gpio = udc->mach->gpio_pullup; usb_del_gadget_udc(&udc->gadget); usb_gadget_unregister_driver(udc->driver); free_irq(udc->irq, udc); pxa_cleanup_debugfs(udc); - if (gpio_is_valid(gpio)) - gpio_free(gpio); usb_put_phy(udc->transceiver); diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h index 28f2b53..f025693 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.h +++ b/drivers/usb/gadget/udc/pxa27x_udc.h @@ -421,6 +421,7 @@ struct udc_stats { * @driver: bound gadget (zero, g_ether, g_mass_storage, ...) * @dev: device * @mach: machine info, used to activate specific GPIO + * @gpiod: gpio descriptor of gpio for D+ pullup (or NULL if none) * @transceiver: external transceiver to handle vbus sense and D+ pullup * @ep0state: control endpoint state machine state * @stats: statistics on udc usage @@ -447,6 +448,7 @@ struct pxa_udc { struct usb_gadget_driver *driver; struct device *dev; struct pxa2xx_udc_mach_info *mach; + struct gpio_desc *gpiod; struct usb_phy *transceiver; enum ep0_state ep0state; -- cgit v0.10.2 From 3ec8347bfa6e671666d04fc62c8302f5ffa344ba Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 1 Oct 2014 22:06:15 +0200 Subject: usb: gadget: pxa27x_udc: transfer mach_info into pxa_udc Convert the mach info, and store the udc_command in the pxa_udc control structure. It is to be noticed that the udc_is_connected() in mach info is not transfered. This was not used, as mioa701 machine doesn't need it, balloon3 doesn't really use it, and most importantly the current driver never uses it. Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index d583197..5280f64 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1510,11 +1510,11 @@ static void dplus_pullup(struct pxa_udc *udc, int on) { if (udc->gpiod) { gpiod_set_value(udc->gpiod, on); - } else if (udc->mach && udc->mach->udc_command) { + } else if (udc->udc_command) { if (on) - udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); + udc->udc_command(PXA2XX_UDC_CMD_CONNECT); else - udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); + udc->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } udc->pullup_on = on; } @@ -1605,7 +1605,7 @@ static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active) { struct pxa_udc *udc = to_gadget_udc(_gadget); - if (!udc->gpiod && !udc->mach->udc_command) + if (!udc->gpiod && !udc->udc_command) return -EOPNOTSUPP; dplus_pullup(udc, is_active); @@ -2426,7 +2426,7 @@ static int pxa_udc_probe(struct platform_device *pdev) return retval; udc->gpiod = gpio_to_desc(mach->gpio_pullup); } - udc->mach = mach; + udc->udc_command = mach->udc_command; } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h index f025693..11e1423 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.h +++ b/drivers/usb/gadget/udc/pxa27x_udc.h @@ -420,7 +420,7 @@ struct udc_stats { * @usb_gadget: udc gadget structure * @driver: bound gadget (zero, g_ether, g_mass_storage, ...) * @dev: device - * @mach: machine info, used to activate specific GPIO + * @udc_command: machine specific function to activate D+ pullup * @gpiod: gpio descriptor of gpio for D+ pullup (or NULL if none) * @transceiver: external transceiver to handle vbus sense and D+ pullup * @ep0state: control endpoint state machine state @@ -447,7 +447,7 @@ struct pxa_udc { struct usb_gadget gadget; struct usb_gadget_driver *driver; struct device *dev; - struct pxa2xx_udc_mach_info *mach; + void (*udc_command)(int); struct gpio_desc *gpiod; struct usb_phy *transceiver; -- cgit v0.10.2 From 1803fe15ad54e68aae8b2b44e04a635e9b5d52f2 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 1 Oct 2014 22:06:16 +0200 Subject: usb: gadget: pxa27x_udc: add devicetree support Add support for device-tree device discovery. If devicetree is not provided, fallback to legacy platform data "discovery". Signed-off-by: Robert Jarzmik Cc: devicetree@vger.kernel.org Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 5280f64..55598c0 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -2400,6 +2402,12 @@ static struct pxa_udc memory = { } }; +static struct of_device_id udc_pxa_dt_ids[] = { + { .compatible = "marvell,pxa270-udc" }, + {} +}; +MODULE_DEVICE_TABLE(of, udc_pxa_dt_ids); + /** * pxa_udc_probe - probes the udc device * @_dev: platform device @@ -2427,6 +2435,8 @@ static int pxa_udc_probe(struct platform_device *pdev) udc->gpiod = gpio_to_desc(mach->gpio_pullup); } udc->udc_command = mach->udc_command; + } else { + udc->gpiod = devm_gpiod_get(&pdev->dev, NULL); } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -2618,6 +2628,7 @@ static struct platform_driver udc_driver = { .driver = { .name = "pxa27x-udc", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(udc_pxa_dt_ids), }, .probe = pxa_udc_probe, .remove = pxa_udc_remove, -- cgit v0.10.2 From 7ee2566ff53e0620a80548689c74505fe8f10ec8 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Tue, 17 Dec 2013 18:47:54 +0530 Subject: usb: dwc3: dwc3-omap: get rid of ->prepare()/->complete() Enabling the core interrupts in complete is too late for XHCI, and stops it from proper operation. The root of the problem is due to a disagreement between dwc3-omap and XHCI about when IRQs should be enabled. As it turns out, ->resume's documentation states that: "... generally the driver is expected to start working again, responding to hardware events and software requests (the device itself may be left in a low-power state, waiting for a runtime resume to occur) ..." From that we infer that IRQs must be unmasked by the end of ->resume(). Due to that, we will remove ->prepare() and ->complete() and disable/enable interrupts in ->suspend()/->resume(). Acked-by: Roger Quadros Signed-off-by: George Cherian Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index a0aa9f3..172d64e 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -593,27 +593,12 @@ static const struct of_device_id of_dwc3_match[] = { MODULE_DEVICE_TABLE(of, of_dwc3_match); #ifdef CONFIG_PM_SLEEP -static int dwc3_omap_prepare(struct device *dev) -{ - struct dwc3_omap *omap = dev_get_drvdata(dev); - - dwc3_omap_disable_irqs(omap); - - return 0; -} - -static void dwc3_omap_complete(struct device *dev) -{ - struct dwc3_omap *omap = dev_get_drvdata(dev); - - dwc3_omap_enable_irqs(omap); -} - static int dwc3_omap_suspend(struct device *dev) { struct dwc3_omap *omap = dev_get_drvdata(dev); omap->utmi_otg_status = dwc3_omap_read_utmi_status(omap); + dwc3_omap_disable_irqs(omap); return 0; } @@ -623,6 +608,7 @@ static int dwc3_omap_resume(struct device *dev) struct dwc3_omap *omap = dev_get_drvdata(dev); dwc3_omap_write_utmi_status(omap, omap->utmi_otg_status); + dwc3_omap_enable_irqs(omap); pm_runtime_disable(dev); pm_runtime_set_active(dev); @@ -632,8 +618,6 @@ static int dwc3_omap_resume(struct device *dev) } static const struct dev_pm_ops dwc3_omap_dev_pm_ops = { - .prepare = dwc3_omap_prepare, - .complete = dwc3_omap_complete, SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume) }; -- cgit v0.10.2 From 0b0231aa246cbfdcf0a07f5e8914c0f1b80002f6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 7 Oct 2014 10:19:23 -0500 Subject: usb: dwc3: get rid of ->prepare()/->complete() Using ->prepare()/->complete() to mask/unmask IRQs is wrong at least for dwc3. We need to make sure that by the end of ->resume(), IRQs are working and ready to fire because a child device may need working IRQs for its own ->resume() method. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4d4e854..fa396fc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -825,50 +825,6 @@ static int dwc3_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int dwc3_prepare(struct device *dev) -{ - struct dwc3 *dwc = dev_get_drvdata(dev); - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - case USB_DR_MODE_OTG: - dwc3_gadget_prepare(dwc); - /* FALLTHROUGH */ - case USB_DR_MODE_HOST: - default: - dwc3_event_buffers_cleanup(dwc); - break; - } - - spin_unlock_irqrestore(&dwc->lock, flags); - - return 0; -} - -static void dwc3_complete(struct device *dev) -{ - struct dwc3 *dwc = dev_get_drvdata(dev); - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - - dwc3_event_buffers_setup(dwc); - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - case USB_DR_MODE_OTG: - dwc3_gadget_complete(dwc); - /* FALLTHROUGH */ - case USB_DR_MODE_HOST: - default: - break; - } - - spin_unlock_irqrestore(&dwc->lock, flags); -} - static int dwc3_suspend(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); @@ -883,7 +839,7 @@ static int dwc3_suspend(struct device *dev) /* FALLTHROUGH */ case USB_DR_MODE_HOST: default: - /* do nothing */ + dwc3_event_buffers_cleanup(dwc); break; } @@ -916,6 +872,7 @@ static int dwc3_resume(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); + dwc3_event_buffers_setup(dwc); dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); switch (dwc->dr_mode) { @@ -944,9 +901,6 @@ err_usb2phy_init: } static const struct dev_pm_ops dwc3_dev_pm_ops = { - .prepare = dwc3_prepare, - .complete = dwc3_complete, - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) }; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 66f6256..a715ee1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -964,20 +964,9 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, /* power management interface */ #if !IS_ENABLED(CONFIG_USB_DWC3_HOST) -int dwc3_gadget_prepare(struct dwc3 *dwc); -void dwc3_gadget_complete(struct dwc3 *dwc); int dwc3_gadget_suspend(struct dwc3 *dwc); int dwc3_gadget_resume(struct dwc3 *dwc); #else -static inline int dwc3_gadget_prepare(struct dwc3 *dwc) -{ - return 0; -} - -static inline void dwc3_gadget_complete(struct dwc3 *dwc) -{ -} - static inline int dwc3_gadget_suspend(struct dwc3 *dwc) { return 0; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 546ea54..748b87b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2744,26 +2744,13 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc->ctrl_req, dwc->ctrl_req_addr); } -int dwc3_gadget_prepare(struct dwc3 *dwc) +int dwc3_gadget_suspend(struct dwc3 *dwc) { if (dwc->pullups_connected) { dwc3_gadget_disable_irq(dwc); dwc3_gadget_run_stop(dwc, true, true); } - return 0; -} - -void dwc3_gadget_complete(struct dwc3 *dwc) -{ - if (dwc->pullups_connected) { - dwc3_gadget_enable_irq(dwc); - dwc3_gadget_run_stop(dwc, true, false); - } -} - -int dwc3_gadget_suspend(struct dwc3 *dwc) -{ __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); @@ -2798,6 +2785,11 @@ int dwc3_gadget_resume(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg); + if (dwc->pullups_connected) { + dwc3_gadget_enable_irq(dwc); + dwc3_gadget_run_stop(dwc, true, false); + } + return 0; err1: -- cgit v0.10.2 From 0abd0696982534a5cf75e8129989fa3d4b734797 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 9 Oct 2014 10:12:24 -0500 Subject: usb: gadget: udc-core: call ->disconnect() when soft disconnecting when disconnecting from host using our soft_connect sysfs interface, also let the gadget driver know about it by calling the gadget driver's ->disconnect() method. No problems have been found while not calling ->disconnect() so far, it's just good convention. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f205465..ddc6f57 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -517,6 +517,7 @@ static ssize_t usb_udc_softconn_store(struct device *dev, usb_gadget_connect(udc->gadget); } else if (sysfs_streq(buf, "disconnect")) { usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); usb_gadget_udc_stop(udc->gadget, udc->driver); } else { dev_err(dev, "unsupported command '%s'\n", buf); -- cgit v0.10.2 From 60b388befb42d1e90a8594cdcfe80dbf57542ac0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 8 Oct 2014 13:40:37 +0300 Subject: usb: gadget: f_uac1: remove an unneeded NULL check This NULL check sets off a static checker warning because we already dereferenced "card" earlier in the function. However, since "card" is never NULL so we can just remove the check. Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c index a44a07f..53842a1 100644 --- a/drivers/usb/gadget/function/u_uac1.c +++ b/drivers/usb/gadget/function/u_uac1.c @@ -213,9 +213,6 @@ static int gaudio_open_snd_dev(struct gaudio *card) fn_cap = opts->fn_cap; fn_cntl = opts->fn_cntl; - if (!card) - return -ENODEV; - /* Open control device */ snd = &card->control; snd->filp = filp_open(fn_cntl, O_RDWR, 0); -- cgit v0.10.2 From 3a571870856f63064a3a45d7ffa2526d597b7fbe Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 8 Oct 2014 12:03:36 +0200 Subject: usb: gadget: configfs: add suspend/resume USB gadgets composed with configfs lack suspend and resume methods. This patch uses composite_suspend()/composite_resume() the same way e.g. composite_setup() or composite_disconnect() are used in a configfs-based gadget. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index e071d58..6178353 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2064,8 +2064,7 @@ fail: /*-------------------------------------------------------------------------*/ -static void -composite_suspend(struct usb_gadget *gadget) +void composite_suspend(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; @@ -2088,8 +2087,7 @@ composite_suspend(struct usb_gadget *gadget) usb_gadget_vbus_draw(gadget, 2); } -static void -composite_resume(struct usb_gadget *gadget) +void composite_resume(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 3403433..d25f9f3 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1453,6 +1453,9 @@ static const struct usb_gadget_driver configfs_driver_template = { .reset = composite_disconnect, .disconnect = composite_disconnect, + .suspend = composite_suspend, + .resume = composite_resume, + .max_speed = USB_SPEED_SUPER, .driver = { .owner = THIS_MODULE, diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index ed3811c..3d87def 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -506,6 +506,8 @@ extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n); extern void composite_disconnect(struct usb_gadget *gadget); extern int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl); +extern void composite_suspend(struct usb_gadget *gadget); +extern void composite_resume(struct usb_gadget *gadget); /* * Some systems will need runtime overrides for the product identifiers -- cgit v0.10.2 From f2918ad89df5a5deb4773e13b5f6e21eabfce282 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Oct 2014 15:21:56 -0500 Subject: usb: gadget: udc: document our sysfs ABI I noticed that this has been missing for quite some time so I decided it was about time to document it. Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/stable/sysfs-class-udc b/Documentation/ABI/stable/sysfs-class-udc new file mode 100644 index 0000000..85d3dac --- /dev/null +++ b/Documentation/ABI/stable/sysfs-class-udc @@ -0,0 +1,93 @@ +What: /sys/class/udc//a_alt_hnp_support +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates if an OTG A-Host supports HNP at an alternate port. +Users: + +What: /sys/class/udc//a_hnp_support +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates if an OTG A-Host supports HNP at this port. +Users: + +What: /sys/class/udc//b_hnp_enable +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates if an OTG A-Host enabled HNP support. +Users: + +What: /sys/class/udc//current_speed +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates the current negotiated speed at this port. +Users: + +What: /sys/class/udc//is_a_peripheral +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates that this port is the default Host on an OTG session + but HNP was used to switch roles. +Users: + +What: /sys/class/udc//is_otg +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates that this port support OTG. +Users: + +What: /sys/class/udc//maximum_speed +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates the maximum USB speed supported by this port. +Users: + +What: /sys/class/udc//maximum_speed +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates the maximum USB speed supported by this port. +Users: + +What: /sys/class/udc//soft_connect +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Allows users to disconnect data pullup resistors thus causing a + logical disconnection from the USB Host. +Users: + +What: /sys/class/udc//srp +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Allows users to manually start Session Request Protocol. +Users: + +What: /sys/class/udc//state +Date: June 2011 +KernelVersion: 3.1 +Contact: Felipe Balbi +Description: + Indicates current state of the USB Device Controller. Valid + states are: 'not-attached', 'attached', 'powered', + 'reconnecting', 'unauthenticated', 'default', 'addressed', + 'configured', and 'suspended'; however not all USB Device + Controllers support reporting all states. +Users: -- cgit v0.10.2 From 06a374ed13fdb7c6b2edd8cbdcf52bd1b0cc67b9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Oct 2014 15:24:00 -0500 Subject: usb: dwc3: gadget: set state to NOT_ATTACHED on disconnect_irq whenever we get a Disconnect Interrupt, we should make sure to update out udc state to NOT_ATTACHED, otherwise sysfs will show wrong values. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 748b87b..12f4284 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2140,6 +2140,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; + usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED); } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) -- cgit v0.10.2 From 73359cef4fcc322c96019b2a5c1e99b08f3bbb57 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 13 Oct 2014 15:36:16 -0500 Subject: usb: dwc3: gadget: WARN() on bogus usb_ep_queue() Some gadget/function drivers might want to do improper request recycling by allocating a single request from one particular endpoint and queueing it to another completely unrelated endpoint. One such case was found with f_loopback.c. To prevent such cases from happening again, let's WARN() so we get a loud enough failure and persuade users to report errors. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 12f4284..20e4ee9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1140,8 +1140,14 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, if (!dep->endpoint.desc) { dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", request, ep->name); - spin_unlock_irqrestore(&dwc->lock, flags); - return -ESHUTDOWN; + ret = -ESHUTDOWN; + goto out; + } + + if (WARN(req->dep != dep, "request %p belongs to '%s'\n", + request, req->dep->name)) { + ret = -EINVAL; + goto out; } dev_vdbg(dwc->dev, "queing request %p to %s length %d\n", @@ -1149,6 +1155,8 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, trace_dwc3_ep_queue(req); ret = __dwc3_gadget_ep_queue(dep, req); + +out: spin_unlock_irqrestore(&dwc->lock, flags); return ret; -- cgit v0.10.2 From d6163f2ca5a4f1cd8a577db68a9c59f78b30a99b Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:55:57 +0800 Subject: usb: gadget: mv_udc_core: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 3c5db80..cebb948 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2107,10 +2107,8 @@ static int mv_udc_probe(struct platform_device *pdev) } udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); - if (udc == NULL) { - dev_err(&pdev->dev, "failed to allocate memory for udc\n"); + if (udc == NULL) return -ENOMEM; - } udc->done = &release_done; udc->pdata = dev_get_platdata(&pdev->dev); @@ -2207,7 +2205,6 @@ static int mv_udc_probe(struct platform_device *pdev) size = udc->max_eps * sizeof(struct mv_ep) *2; udc->eps = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (udc->eps == NULL) { - dev_err(&pdev->dev, "allocate ep memory failed\n"); retval = -ENOMEM; goto err_destroy_dma; } @@ -2216,7 +2213,6 @@ static int mv_udc_probe(struct platform_device *pdev) udc->status_req = devm_kzalloc(&pdev->dev, sizeof(struct mv_req), GFP_KERNEL); if (!udc->status_req) { - dev_err(&pdev->dev, "allocate status_req memory failed\n"); retval = -ENOMEM; goto err_destroy_dma; } -- cgit v0.10.2 From 3efe90e995e72084505ee49680f698e8d5730b48 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:55:58 +0800 Subject: usb: gadget: fsl_qe_udc: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index dd18ea3..6601b0f 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -2538,7 +2538,6 @@ static int qe_udc_probe(struct platform_device *ofdev) /* create a buf for ZLP send, need to remain zeroed */ udc->nullbuf = devm_kzalloc(&ofdev->dev, 256, GFP_KERNEL); if (udc->nullbuf == NULL) { - dev_err(udc->dev, "cannot alloc nullbuf\n"); ret = -ENOMEM; goto err3; } -- cgit v0.10.2 From 0590c4bf4bbbc608cf963dbf7d5aa4f202c8cf71 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:55:59 +0800 Subject: usb: gadget: bcm63xx_udc: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 2235b88..485c8c2 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -2324,10 +2324,8 @@ static int bcm63xx_udc_probe(struct platform_device *pdev) int rc = -ENOMEM, i, irq; udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL); - if (!udc) { - dev_err(dev, "cannot allocate memory\n"); + if (!udc) return -ENOMEM; - } platform_set_drvdata(pdev, udc); udc->dev = dev; -- cgit v0.10.2 From 3dc3b4e15e09d785f06c7122a9d3e564e7065119 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:00 +0800 Subject: usb: gadget: s3c-hsudc: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index dfbf557..f658f69 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -1267,10 +1267,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev) hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) + sizeof(struct s3c_hsudc_ep) * pd->epnum, GFP_KERNEL); - if (!hsudc) { - dev_err(dev, "cannot allocate memory\n"); + if (!hsudc) return -ENOMEM; - } platform_set_drvdata(pdev, dev); hsudc->dev = dev; -- cgit v0.10.2 From 26c07010c4ba82b52627ff18deacbee8900d868d Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:06 +0800 Subject: usb: musb: davinci: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 110b784..04de3ac 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -520,10 +520,8 @@ static int davinci_probe(struct platform_device *pdev) int ret = -ENOMEM; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); + if (!glue) goto err0; - } clk = devm_clk_get(&pdev->dev, "usb"); if (IS_ERR(clk)) { -- cgit v0.10.2 From 24c611b925b79e64d396265ae1853f3bbb0656db Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:07 +0800 Subject: usb: musb: ux500: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index dc666e9..d0180a7 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -247,10 +247,8 @@ static int ux500_probe(struct platform_device *pdev) } glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); + if (!glue) goto err0; - } musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { -- cgit v0.10.2 From af1bdfc999e7690a3b47c75c43a238f6c619a170 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:08 +0800 Subject: usb: musb: omap2430: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index d369bf1..6669f26 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -518,10 +518,8 @@ static int omap2430_probe(struct platform_device *pdev) int ret = -ENOMEM; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); + if (!glue) goto err0; - } musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { @@ -543,25 +541,16 @@ static int omap2430_probe(struct platform_device *pdev) struct platform_device *control_pdev; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, - "failed to allocate musb platform data\n"); + if (!pdata) goto err2; - } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, - "failed to allocate musb board data\n"); + if (!data) goto err2; - } config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); - if (!config) { - dev_err(&pdev->dev, - "failed to allocate musb hdrc config\n"); + if (!config) goto err2; - } of_property_read_u32(np, "mode", (u32 *)&pdata->mode); of_property_read_u32(np, "interface-type", -- cgit v0.10.2 From 65469790c6b060113f7438470fceeb2ae3cfba91 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:09 +0800 Subject: usb: musb: blackfin: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index ac4422b..8554c6f 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -456,16 +456,12 @@ static int bfin_probe(struct platform_device *pdev) int ret = -ENOMEM; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); + if (!glue) goto err0; - } musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); + if (!musb) goto err0; - } musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &bfin_dmamask; -- cgit v0.10.2 From 6a58856f25e1fedd7362a1ee598d5c890c3ed334 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:10 +0800 Subject: usb: musb: tusb6010: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2daa779..25f02df 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1164,10 +1164,8 @@ static int tusb_probe(struct platform_device *pdev) int ret; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); + if (!glue) return -ENOMEM; - } glue->dev = &pdev->dev; -- cgit v0.10.2 From 0816ea2fa3c046b8c867aadbaadf19eb2fc3ac87 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:11 +0800 Subject: usb: musb: musb_dsps: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 48bc09e..6209456 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -729,7 +729,6 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); if (!config) { - dev_err(dev, "failed to allocate musb hdrc config\n"); ret = -ENOMEM; goto err; } @@ -781,10 +780,8 @@ static int dsps_probe(struct platform_device *pdev) /* allocate glue */ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "unable to allocate glue memory\n"); + if (!glue) return -ENOMEM; - } glue->dev = &pdev->dev; glue->wrp = wrp; -- cgit v0.10.2 From 87fb3dec36bc1823b810107b69435dc66f763543 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:12 +0800 Subject: usb: phy: phy-rcar-usb: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c index 33265a5..4879596 100644 --- a/drivers/usb/phy/phy-rcar-usb.c +++ b/drivers/usb/phy/phy-rcar-usb.c @@ -202,10 +202,8 @@ static int rcar_usb_phy_probe(struct platform_device *pdev) } priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(dev, "priv data allocation error\n"); + if (!priv) return -ENOMEM; - } priv->reg0 = reg0; priv->reg1 = reg1; -- cgit v0.10.2 From 01ad32d5b5289b00d03a94dd9f6d975f1314a541 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:13 +0800 Subject: usb: phy: phy-tegra-usb: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 886f180..fa2bfa4 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -880,11 +880,8 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, tegra_phy->config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); - if (!tegra_phy->config) { - dev_err(&pdev->dev, - "unable to allocate memory for USB UTMIP config\n"); + if (!tegra_phy->config) return -ENOMEM; - } config = tegra_phy->config; @@ -979,10 +976,8 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) int err; tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL); - if (!tegra_phy) { - dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n"); + if (!tegra_phy) return -ENOMEM; - } match = of_match_device(tegra_usb_phy_id_table, &pdev->dev); if (!match) { -- cgit v0.10.2 From 9aabd03272c8dc0b91341da865ae742fe0ecb2c3 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:14 +0800 Subject: usb: phy: phy-am335x-control: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 35b6083..2e923c5 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -147,10 +147,8 @@ static int am335x_control_usb_probe(struct platform_device *pdev) phy_ctrl = of_id->data; ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL); - if (!ctrl_usb) { - dev_err(&pdev->dev, "unable to alloc memory for control usb\n"); + if (!ctrl_usb) return -ENOMEM; - } ctrl_usb->dev = &pdev->dev; -- cgit v0.10.2 From 3f8acf35b019aa996cc16b3658b72ad361cc7931 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:15 +0800 Subject: usb: phy: phy-rcar-gen2-usb: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c index 388d89f..f838084 100644 --- a/drivers/usb/phy/phy-rcar-gen2-usb.c +++ b/drivers/usb/phy/phy-rcar-gen2-usb.c @@ -195,10 +195,8 @@ static int rcar_gen2_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(base); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(dev, "Memory allocation failed\n"); + if (!priv) return -ENOMEM; - } spin_lock_init(&priv->lock); priv->clk = clk; -- cgit v0.10.2 From c62fe55648702c5e736861a4238a58b92072202b Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:16 +0800 Subject: usb: phy: phy-mxs-usb: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 0e0c415..a55dadc 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -390,10 +390,8 @@ static int mxs_phy_probe(struct platform_device *pdev) } mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL); - if (!mxs_phy) { - dev_err(&pdev->dev, "Failed to allocate USB PHY structure!\n"); + if (!mxs_phy) return -ENOMEM; - } /* Some SoCs don't have anatop registers */ if (of_get_property(np, "fsl,anatop", NULL)) { -- cgit v0.10.2 From 9da22206c2dad28f4a1dd8c6d9f66030524965b2 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:17 +0800 Subject: usb: phy: phy-msm-usb: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 7843ef7..471e69d 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1505,10 +1505,8 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) } pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); - if (!pdata->phy_init_seq) { - dev_warn(&pdev->dev, "No space for PHY init sequence\n"); + if (!pdata->phy_init_seq) return 0; - } ret = of_property_read_u32_array(node, "qcom,phy-init-sequence", pdata->phy_init_seq, words); @@ -1530,10 +1528,8 @@ static int msm_otg_probe(struct platform_device *pdev) void __iomem *phy_select; motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL); - if (!motg) { - dev_err(&pdev->dev, "unable to allocate msm_otg\n"); + if (!motg) return -ENOMEM; - } pdata = dev_get_platdata(&pdev->dev); if (!pdata) { @@ -1546,10 +1542,8 @@ static int msm_otg_probe(struct platform_device *pdev) motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), GFP_KERNEL); - if (!motg->phy.otg) { - dev_err(&pdev->dev, "unable to allocate msm_otg\n"); + if (!motg->phy.otg) return -ENOMEM; - } phy = &motg->phy; phy->dev = &pdev->dev; -- cgit v0.10.2 From aa10c7b00eff826bceee2b9f9cd005efc028d881 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:18 +0800 Subject: usb: phy: phy-mv-usb: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 7d80c54..c9517d8 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -686,10 +686,8 @@ static int mv_otg_probe(struct platform_device *pdev) } mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL); - if (!mvotg) { - dev_err(&pdev->dev, "failed to allocate memory!\n"); + if (!mvotg) return -ENOMEM; - } otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); if (!otg) -- cgit v0.10.2 From b1cb07cdee8f0247b1a6b3ba63ad4214ee2032a4 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:19 +0800 Subject: usb: renesas_usbhs: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index b3b6813..6dae115 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -505,10 +505,8 @@ static int usbhs_probe(struct platform_device *pdev) /* usb private data */ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "Could not allocate priv\n"); + if (!priv) return -ENOMEM; - } priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) -- cgit v0.10.2 From 3da6702f577be7249ece5799fb91cf2bf5e243fd Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:38 +0530 Subject: usb: musb: ux500_dma: use dmaengine_xxx() APIs The drivers should use dmaengine_terminate_all() or dmaengine_slave_config() API instead of accessing the device_control which will be deprecated soon Signed-off-by: Vinod Koul Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 221faed..734dc84 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -121,8 +121,7 @@ static bool ux500_configure_channel(struct dma_channel *channel, slave_conf.dst_maxburst = 16; slave_conf.device_fc = false; - dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG, - (unsigned long) &slave_conf); + dmaengine_slave_config(dma_chan, &slave_conf); dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -246,9 +245,7 @@ static int ux500_dma_channel_abort(struct dma_channel *channel) musb_writew(epio, MUSB_RXCSR, csr); } - ux500_channel->dma_chan->device-> - device_control(ux500_channel->dma_chan, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(ux500_channel->dma_chan); channel->status = MUSB_DMA_STATUS_FREE; } return 0; -- cgit v0.10.2 From 21090f06f09f72f2806c19f0bdcd4fde622c2676 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:16:04 -0500 Subject: usb: gadget: udc: amd5536: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c index 3b9d138..7d0e0b8 100644 --- a/drivers/usb/gadget/udc/amd5536udc.c +++ b/drivers/usb/gadget/udc/amd5536udc.c @@ -1971,7 +1971,7 @@ static int amd5536_udc_stop(struct usb_gadget *g, spin_lock_irqsave(&dev->lock, flags); udc_mask_unused_interrupts(dev); - shutdown(dev, driver); + shutdown(dev, NULL); spin_unlock_irqrestore(&dev->lock, flags); dev->driver = NULL; -- cgit v0.10.2 From af9501f656d2250dbf04e48f77025b3783cc0505 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:17:08 -0500 Subject: usb: gadget: udc: at91: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 9968f53..cffd2a2 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1657,9 +1657,9 @@ static int at91_stop(struct usb_gadget *gadget, at91_udp_write(udc, AT91_UDP_IDR, ~0); spin_unlock_irqrestore(&udc->lock, flags); + DBG("unbound from %s\n", udc->driver->driver.name); udc->driver = NULL; - DBG("unbound from %s\n", driver->driver.name); return 0; } -- cgit v0.10.2 From 96a5361aab7a89cf80cb4fe03966f55f00b0d91f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:18:29 -0500 Subject: usb: gadget: udc: dummy: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 81dc595..32bdd78 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -921,9 +921,8 @@ static int dummy_udc_stop(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - if (driver) - dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", - driver->driver.name); + dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", + dum->driver->driver.name); dum->driver = NULL; -- cgit v0.10.2 From 5d82ff915f019bb4f479914e4a43de00ef38da8a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:20:10 -0500 Subject: usb: gadget: udc: fsl_qe: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 6601b0f..be78857 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -2334,10 +2334,10 @@ static int fsl_qe_stop(struct usb_gadget *gadget, nuke(loop_ep, -ESHUTDOWN); spin_unlock_irqrestore(&udc->lock, flags); + dev_info(udc->dev, "unregistered gadget driver '%s'\r\n", + udc->driver->driver.name); udc->driver = NULL; - dev_info(udc->dev, "unregistered gadget driver '%s'\r\n", - driver->driver.name); return 0; } -- cgit v0.10.2 From d3cb25bfcdf6806dccd154ca2d62f9f447fdad5a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:21:03 -0500 Subject: usb: gadget: udc: lpc32xx: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index feab0ba..cef64b9 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -2967,9 +2967,6 @@ static int lpc32xx_stop(struct usb_gadget *gadget, int i; struct lpc32xx_udc *udc = to_udc(gadget); - if (!driver || driver != udc->driver) - return -EINVAL; - for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) disable_irq(udc->udp_irq[i]); -- cgit v0.10.2 From a19f378772ffdc18962a76102a424c21b79348a9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:21:34 -0500 Subject: usb: gadget: udc: mv_u3d: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 046a1f8..e3ef744 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1284,7 +1284,7 @@ static int mv_u3d_stop(struct usb_gadget *g, mv_u3d_controller_stop(u3d); /* stop all usb activities */ u3d->gadget.speed = USB_SPEED_UNKNOWN; - mv_u3d_stop_activity(u3d, driver); + mv_u3d_stop_activity(u3d, NULL); mv_u3d_disable(u3d); if (pdata->phy_deinit) -- cgit v0.10.2 From 2f1ae5010861b92d665d11e1069566fc4c28689b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:22:11 -0500 Subject: usb: gadget: udc: mv_udc: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index cebb948..32d24ff 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -1386,7 +1386,7 @@ static int mv_udc_stop(struct usb_gadget *gadget, /* stop all usb activities */ udc->gadget.speed = USB_SPEED_UNKNOWN; - stop_activity(udc, driver); + stop_activity(udc, NULL); mv_udc_disable(udc); spin_unlock_irqrestore(&udc->lock, flags); -- cgit v0.10.2 From 5baca5cf255d9a9d2bc97fe2531e12e37ebdd77d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:22:52 -0500 Subject: usb: gadget: udc: net2272: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 84d7162..6fb54f5 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1511,12 +1511,13 @@ static int net2272_stop(struct usb_gadget *_gadget, dev = container_of(_gadget, struct net2272, gadget); spin_lock_irqsave(&dev->lock, flags); - stop_activity(dev, driver); + stop_activity(dev, NULL); spin_unlock_irqrestore(&dev->lock, flags); + dev_dbg(dev->dev, "unregistered driver '%s'\n", + dev->driver->driver.name); dev->driver = NULL; - dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name); return 0; } -- cgit v0.10.2 From bfd0ed576dbf9cc71af7dbe42841fc9246524961 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:23:33 -0500 Subject: usb: gadget: udc: net2280: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 8d13337..ee74b9d 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -2446,11 +2446,9 @@ static int net2280_stop(struct usb_gadget *_gadget, dev = container_of(_gadget, struct net2280, gadget); spin_lock_irqsave(&dev->lock, flags); - stop_activity(dev, driver); + stop_activity(dev, NULL); spin_unlock_irqrestore(&dev->lock, flags); - dev->driver = NULL; - net2280_led_active(dev, 0); /* Disable full-speed test mode */ @@ -2460,8 +2458,8 @@ static int net2280_stop(struct usb_gadget *_gadget, device_remove_file(&dev->pdev->dev, &dev_attr_function); device_remove_file(&dev->pdev->dev, &dev_attr_queues); - ep_dbg(dev, "unregistered driver '%s'\n", - driver ? driver->driver.name : ""); + ep_dbg(dev, "unregistered driver '%s'\n", dev->driver->driver.name); + dev->driver = NULL; return 0; } -- cgit v0.10.2 From d7343161fd1250a8c4eadf98a0db690f3257f0c5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:24:37 -0500 Subject: usb: gadget: udc: pxa25x: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 42f7eeb..098fa57 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1319,7 +1319,7 @@ static int pxa25x_udc_stop(struct usb_gadget*g, local_irq_disable(); dev->pullup = 0; pullup(dev); - stop_activity(dev, driver); + stop_activity(dev, NULL); local_irq_enable(); if (!IS_ERR_OR_NULL(dev->transceiver)) -- cgit v0.10.2 From c3d84dfb7f6027fff4723330620f63c08ab0e253 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:25:04 -0500 Subject: usb: gadget: udc: pxa27x: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 55598c0..b90b1f3 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1862,7 +1862,7 @@ static int pxa27x_udc_stop(struct usb_gadget *g, { struct pxa_udc *udc = to_pxa(g); - stop_activity(udc, driver); + stop_activity(udc, NULL); udc_disable(udc); dplus_pullup(udc, 0); -- cgit v0.10.2 From 82891b959cbb2cd1827bc2713d46840fcf8dbe14 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:25:50 -0500 Subject: usb: gadget: udc: s3c-hsudc: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index f658f69..f3bb2fa 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -1199,11 +1199,7 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget, if (!hsudc) return -ENODEV; - if (!driver || driver != hsudc->driver) - return -EINVAL; - spin_lock_irqsave(&hsudc->lock, flags); - hsudc->driver = NULL; hsudc->gadget.speed = USB_SPEED_UNKNOWN; s3c_hsudc_uninit_phy(); @@ -1222,7 +1218,9 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget, regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); dev_info(hsudc->dev, "unregistered gadget driver '%s'\n", - driver->driver.name); + hsudc->driver->driver.name); + hsudc->driver = NULL; + return 0; } -- cgit v0.10.2 From 69e28882dc7a4ad80f1a0de1a2e7f346a15b6564 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:26:46 -0500 Subject: usb: musb: gadget: do not rely on 'driver' argument future patches will remove the extra 'driver' argument to ->udc_stop(), in order to do that, we must make sure that our UDC does not rely on it first. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 24c8c02..fdb8b31 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1946,11 +1946,11 @@ static int musb_gadget_stop(struct usb_gadget *g, (void) musb_gadget_vbus_draw(&musb->g, 0); musb->xceiv->state = OTG_STATE_UNDEFINED; - stop_activity(musb, driver); + stop_activity(musb, NULL); otg_set_peripheral(musb->xceiv->otg, NULL); dev_dbg(musb->controller, "unregistering driver %s\n", - driver ? driver->function : "(removed)"); + musb->gadget_driver->function); musb->is_active = 0; musb->gadget_driver = NULL; -- cgit v0.10.2 From 2c683347f5be4efee5b8abba84f9bad6ed4fe47d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:34:07 -0500 Subject: usb: gadget: udc: pass a single argument to usb_gadget_udc_start/stop We know that our udc points to our gadget and our gadget_driver, simplify the interface by passing a single argument. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index ddc6f57..3fed7a2 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -174,8 +174,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); /** * usb_gadget_udc_start - tells usb device controller to start up - * @gadget: The gadget we want to get started - * @driver: The driver we want to bind to @gadget + * @udc: The UDC to be started * * This call is issued by the UDC Class driver when it's about * to register a gadget driver to the device controller, before @@ -186,10 +185,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); * * Returns zero on success, else negative errno. */ -static inline int usb_gadget_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static inline int usb_gadget_udc_start(struct usb_udc *udc) { - return gadget->ops->udc_start(gadget, driver); + return udc->gadget->ops->udc_start(udc->gadget, udc->driver); } /** @@ -204,10 +202,9 @@ static inline int usb_gadget_udc_start(struct usb_gadget *gadget, * far as powering off UDC completely and disable its data * line pullups. */ -static inline void usb_gadget_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static inline void usb_gadget_udc_stop(struct usb_udc *udc) { - gadget->ops->udc_stop(gadget, driver); + udc->gadget->ops->udc_stop(udc->gadget, udc->driver); } /** @@ -335,7 +332,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) usb_gadget_disconnect(udc->gadget); udc->driver->disconnect(udc->gadget); udc->driver->unbind(udc->gadget); - usb_gadget_udc_stop(udc->gadget, NULL); + usb_gadget_udc_stop(udc); udc->driver = NULL; udc->dev.driver = NULL; @@ -395,7 +392,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri ret = driver->bind(udc->gadget, driver); if (ret) goto err1; - ret = usb_gadget_udc_start(udc->gadget, driver); + ret = usb_gadget_udc_start(udc); if (ret) { driver->unbind(udc->gadget); goto err1; @@ -513,12 +510,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev, } if (sysfs_streq(buf, "connect")) { - usb_gadget_udc_start(udc->gadget, udc->driver); + usb_gadget_udc_start(udc); usb_gadget_connect(udc->gadget); } else if (sysfs_streq(buf, "disconnect")) { usb_gadget_disconnect(udc->gadget); udc->driver->disconnect(udc->gadget); - usb_gadget_udc_stop(udc->gadget, udc->driver); + usb_gadget_udc_stop(udc); } else { dev_err(dev, "unsupported command '%s'\n", buf); return -EINVAL; -- cgit v0.10.2 From dea87f9d13615c03b7160be0b108d92da9a111cd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:35:52 -0500 Subject: usb: gadget: udc: at91: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index cffd2a2..5c4cede 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1641,7 +1641,6 @@ static int at91_start(struct usb_gadget *gadget, udc->enabled = 1; udc->selfpowered = 1; - DBG("bound to %s\n", driver->driver.name); return 0; } @@ -1657,7 +1656,6 @@ static int at91_stop(struct usb_gadget *gadget, at91_udp_write(udc, AT91_UDP_IDR, ~0); spin_unlock_irqrestore(&udc->lock, flags); - DBG("unbound from %s\n", udc->driver->driver.name); udc->driver = NULL; return 0; -- cgit v0.10.2 From 3364aecc8c72e4e2f4957fce45b97fbf35b87c3a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:37:04 -0500 Subject: usb: gadget: udc: atmel_usba: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 1529926..eaee5f9 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1791,8 +1791,6 @@ static int atmel_usba_start(struct usb_gadget *gadget, return ret; } - DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); - udc->vbus_prev = 0; if (gpio_is_valid(udc->vbus_pin)) enable_irq(gpio_to_irq(udc->vbus_pin)); @@ -1830,8 +1828,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget, clk_disable_unprepare(udc->hclk); clk_disable_unprepare(udc->pclk); - DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name); - udc->driver = NULL; return 0; -- cgit v0.10.2 From dd7e6dd546c69b6166268dedb787b0839c1fd4d5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:37:38 -0500 Subject: usb: gadget: udc: dummy: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 32bdd78..5c72ade 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -908,10 +908,8 @@ static int dummy_udc_start(struct usb_gadget *g, */ dum->devstatus = 0; - dum->driver = driver; - dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n", - driver->driver.name); + return 0; } @@ -921,9 +919,6 @@ static int dummy_udc_stop(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", - dum->driver->driver.name); - dum->driver = NULL; return 0; -- cgit v0.10.2 From 703584768ae4dc6bab3872a36b873a01c62eb045 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:38:09 -0500 Subject: usb: gadget: udc: fsl_qe: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index be78857..6ca61e6 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -2305,8 +2305,6 @@ static int fsl_qe_start(struct usb_gadget *gadget, udc->ep0_dir = USB_DIR_OUT; spin_unlock_irqrestore(&udc->lock, flags); - dev_info(udc->dev, "%s bind to driver %s\n", udc->gadget.name, - driver->driver.name); return 0; } @@ -2334,8 +2332,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget, nuke(loop_ep, -ESHUTDOWN); spin_unlock_irqrestore(&udc->lock, flags); - dev_info(udc->dev, "unregistered gadget driver '%s'\r\n", - udc->driver->driver.name); udc->driver = NULL; return 0; -- cgit v0.10.2 From 70bbd56b7d456adc686873e548c5690b1b01856f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:38:39 -0500 Subject: usb: gadget: udc: gr_udc: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index 1b3048a..bde989f 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -1932,9 +1932,6 @@ static int gr_udc_start(struct usb_gadget *gadget, spin_unlock(&dev->lock); - dev_info(dev->dev, "Started with gadget driver '%s'\n", - driver->driver.name); - return 0; } @@ -1951,8 +1948,6 @@ static int gr_udc_stop(struct usb_gadget *gadget, spin_unlock_irqrestore(&dev->lock, flags); - dev_info(dev->dev, "Stopped\n"); - return 0; } -- cgit v0.10.2 From 812a40bee7b7e121f492ec9cd2f5cfafc086e70d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:39:29 -0500 Subject: usb: gadget: udc: net2272: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 6fb54f5..4641df5 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1471,8 +1471,6 @@ static int net2272_start(struct usb_gadget *_gadget, */ net2272_ep0_start(dev); - dev_dbg(dev->dev, "%s ready\n", driver->driver.name); - return 0; } @@ -1514,8 +1512,6 @@ static int net2272_stop(struct usb_gadget *_gadget, stop_activity(dev, NULL); spin_unlock_irqrestore(&dev->lock, flags); - dev_dbg(dev->dev, "unregistered driver '%s'\n", - dev->driver->driver.name); dev->driver = NULL; return 0; -- cgit v0.10.2 From 1ca12b24087666959f166f24cca5bbaf5d74be78 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:40:05 -0500 Subject: usb: gadget: udc: net2280: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index ee74b9d..a30df8ef 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -2397,11 +2397,6 @@ static int net2280_start(struct usb_gadget *_gadget, ep0_start(dev); - ep_dbg(dev, "%s ready, usbctl %08x stdrsp %08x\n", - driver->driver.name, - readl(&dev->usb->usbctl), - readl(&dev->usb->stdrsp)); - /* pci writes may still be posted */ return 0; @@ -2458,7 +2453,6 @@ static int net2280_stop(struct usb_gadget *_gadget, device_remove_file(&dev->pdev->dev, &dev_attr_function); device_remove_file(&dev->pdev->dev, &dev_attr_queues); - ep_dbg(dev, "unregistered driver '%s'\n", dev->driver->driver.name); dev->driver = NULL; return 0; -- cgit v0.10.2 From 6ce372fed2cb67a7e27400b0c96df161189e0407 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:40:56 -0500 Subject: usb: gadget: udc: s3c-hsudc: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index f3bb2fa..de95e9d 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -1172,8 +1172,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget, } enable_irq(hsudc->irq); - dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name); - s3c_hsudc_reconfig(hsudc); pm_runtime_get_sync(hsudc->dev); @@ -1216,9 +1214,6 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget, disable_irq(hsudc->irq); regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); - - dev_info(hsudc->dev, "unregistered gadget driver '%s'\n", - hsudc->driver->driver.name); hsudc->driver = NULL; return 0; -- cgit v0.10.2 From fae5afb98d88108a188e57c035834e3fc2bdbf80 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:41:33 -0500 Subject: usb: musb: gadget: remove bind/unbind messages now that we provide generic register/unregister debugging messages from udc-core, we can remove the same messages from this driver. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index fdb8b31..88d63e0 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1851,8 +1851,6 @@ static int musb_gadget_start(struct usb_gadget *g, pm_runtime_get_sync(musb->controller); - dev_dbg(musb->controller, "registering driver %s\n", driver->function); - musb->softconnect = 0; musb->gadget_driver = driver; @@ -1949,9 +1947,6 @@ static int musb_gadget_stop(struct usb_gadget *g, stop_activity(musb, NULL); otg_set_peripheral(musb->xceiv->otg, NULL); - dev_dbg(musb->controller, "unregistering driver %s\n", - musb->gadget_driver->function); - musb->is_active = 0; musb->gadget_driver = NULL; musb_platform_try_idle(musb, 0); -- cgit v0.10.2 From 8da9fe8af8e3fd953b346c800976a5db6c0115a4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 11:54:46 -0500 Subject: usb: gadget: udc: core: fix unregistering message Currently, we're printing gadget driver name when registering and UDC name when unregistering. Standardize on always printing gadget driver name. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 3fed7a2..52f457b 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -325,7 +325,7 @@ EXPORT_SYMBOL_GPL(usb_add_gadget_udc); static void usb_gadget_remove_driver(struct usb_udc *udc) { dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", - udc->gadget->name); + udc->driver->function); kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); -- cgit v0.10.2 From 22835b807e7ca946a4d1fbd4c7af56aa09cd273e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 12:05:12 -0500 Subject: usb: gadget: remove unnecessary 'driver' argument now that no UDC driver relies on the extra 'driver' argument to ->udc_stop(), we can safely remove it. This commit is based on previous work by Robert Baldyga which can be found at [1]; however that patch turned out to have a high probability of regressing many UDC drivers because of a blind search & replace s/driver/$udc->driver/ which caused the 'driver' argument to stop_activity() to be a valid non-NULL pointer when it should be NULL, thus causing UDCs to mistakenly call gadget driver's ->disconnect() callback. [1] http://markmail.org/message/x5zneg4xea4zntab Acked-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 0444d3f..f4397b2 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1544,8 +1544,7 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on) static int ci_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); -static int ci_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); +static int ci_udc_stop(struct usb_gadget *gadget); /** * Device operations part of the API to the USB controller hardware, * which don't involve endpoints (or i/o) @@ -1682,8 +1681,7 @@ static int ci_udc_start(struct usb_gadget *gadget, /** * ci_udc_stop: unregister a gadget driver */ -static int ci_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int ci_udc_stop(struct usb_gadget *gadget) { struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget); unsigned long flags; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index eee8709..441f1c4 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2921,8 +2921,7 @@ err: * * Stop udc hw block and stay tunned for future transmissions */ -static int s3c_hsotg_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) { struct s3c_hsotg *hsotg = to_hsotg(gadget); unsigned long flags = 0; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 20e4ee9..20dda60 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1630,8 +1630,7 @@ err0: return ret; } -static int dwc3_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int dwc3_gadget_stop(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c index 7d0e0b8..606b900 100644 --- a/drivers/usb/gadget/udc/amd5536udc.c +++ b/drivers/usb/gadget/udc/amd5536udc.c @@ -1401,9 +1401,8 @@ static int udc_wakeup(struct usb_gadget *gadget) static int amd5536_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int amd5536_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); -/* gadget operations */ +static int amd5536_udc_stop(struct usb_gadget *g); + static const struct usb_gadget_ops udc_ops = { .wakeup = udc_wakeup, .get_frame = udc_get_frame, @@ -1962,8 +1961,7 @@ __acquires(dev->lock) } /* Called by gadget driver to unregister itself */ -static int amd5536_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int amd5536_udc_stop(struct usb_gadget *g) { struct udc *dev = to_amd5536_udc(g); unsigned long flags; diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 5c4cede..f47f16c 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -984,8 +984,8 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) static int at91_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); -static int at91_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); +static int at91_stop(struct usb_gadget *gadget); + static const struct usb_gadget_ops at91_udc_ops = { .get_frame = at91_get_frame, .wakeup = at91_wakeup, @@ -1644,8 +1644,7 @@ static int at91_start(struct usb_gadget *gadget, return 0; } -static int at91_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int at91_stop(struct usb_gadget *gadget) { struct at91_udc *udc; unsigned long flags; diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index eaee5f9..c537a66 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -987,8 +987,8 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) static int atmel_usba_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); -static int atmel_usba_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); +static int atmel_usba_stop(struct usb_gadget *gadget); + static const struct usb_gadget_ops usba_udc_ops = { .get_frame = usba_udc_get_frame, .wakeup = usba_udc_wakeup, @@ -1807,8 +1807,7 @@ static int atmel_usba_start(struct usb_gadget *gadget, return 0; } -static int atmel_usba_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int atmel_usba_stop(struct usb_gadget *gadget) { struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); unsigned long flags; diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 485c8c2..9319ff2 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -1836,8 +1836,7 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget, * @gadget: USB slave device. * @driver: Driver for USB slave devices. */ -static int bcm63xx_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int bcm63xx_udc_stop(struct usb_gadget *gadget) { struct bcm63xx_udc *udc = gadget_to_udc(gadget); unsigned long flags; diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 5c72ade..5bffb75 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -851,8 +851,7 @@ static int dummy_pullup(struct usb_gadget *_gadget, int value) static int dummy_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int dummy_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int dummy_udc_stop(struct usb_gadget *g); static const struct usb_gadget_ops dummy_ops = { .get_frame = dummy_g_get_frame, @@ -913,8 +912,7 @@ static int dummy_udc_start(struct usb_gadget *g, return 0; } -static int dummy_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int dummy_udc_stop(struct usb_gadget *g) { struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 1d31592..1ca52e11 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -1053,8 +1053,7 @@ static void fotg210_init(struct fotg210_udc *fotg210) iowrite32(value, fotg210->reg + FOTG210_DMISGR0); } -static int fotg210_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int fotg210_udc_stop(struct usb_gadget *g) { struct fotg210_udc *fotg210 = gadget_to_fotg210(g); unsigned long flags; diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 6ca61e6..01f29ef 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -1887,8 +1887,7 @@ static int qe_get_frame(struct usb_gadget *gadget) static int fsl_qe_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); -static int fsl_qe_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); +static int fsl_qe_stop(struct usb_gadget *gadget); /* defined in usb_gadget.h */ static const struct usb_gadget_ops qe_gadget_ops = { @@ -2308,8 +2307,7 @@ static int fsl_qe_start(struct usb_gadget *gadget, return 0; } -static int fsl_qe_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int fsl_qe_stop(struct usb_gadget *gadget) { struct qe_udc *udc; struct qe_ep *loop_ep; diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index c362079..b184ed3 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1236,9 +1236,8 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) static int fsl_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int fsl_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); -/* defined in gadget.h */ +static int fsl_udc_stop(struct usb_gadget *g); + static const struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, .wakeup = fsl_wakeup, @@ -1975,8 +1974,7 @@ static int fsl_udc_start(struct usb_gadget *g, } /* Disconnect from gadget driver */ -static int fsl_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int fsl_udc_stop(struct usb_gadget *g) { struct fsl_ep *loop_ep; unsigned long flags; diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index 8286df7..a1b33f5 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -1320,8 +1320,7 @@ static int fusb300_udc_start(struct usb_gadget *g, return 0; } -static int fusb300_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int fusb300_udc_stop(struct usb_gadget *g) { struct fusb300 *fusb300 = to_fusb300(g); diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index bf9c5ef..5b9176e 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -992,8 +992,7 @@ static int goku_get_frame(struct usb_gadget *_gadget) static int goku_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int goku_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int goku_udc_stop(struct usb_gadget *g); static const struct usb_gadget_ops goku_ops = { .get_frame = goku_get_frame, @@ -1364,8 +1363,7 @@ static void stop_activity(struct goku_udc *dev) udc_enable(dev); } -static int goku_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int goku_udc_stop(struct usb_gadget *g) { struct goku_udc *dev = to_goku_udc(g); unsigned long flags; diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index bde989f..320df9a2 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -1935,8 +1935,7 @@ static int gr_udc_start(struct usb_gadget *gadget, return 0; } -static int gr_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int gr_udc_stop(struct usb_gadget *gadget) { struct gr_udc *dev = to_gr_udc(gadget); unsigned long flags; diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index cef64b9..4be497d 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -2559,7 +2559,7 @@ static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on) } static int lpc32xx_start(struct usb_gadget *, struct usb_gadget_driver *); -static int lpc32xx_stop(struct usb_gadget *, struct usb_gadget_driver *); +static int lpc32xx_stop(struct usb_gadget *); static const struct usb_gadget_ops lpc32xx_udc_ops = { .get_frame = lpc32xx_get_frame, @@ -2961,8 +2961,7 @@ static int lpc32xx_start(struct usb_gadget *gadget, return 0; } -static int lpc32xx_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int lpc32xx_stop(struct usb_gadget *gadget) { int i; struct lpc32xx_udc *udc = to_udc(gadget); diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 8985656..311ec5f 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1485,8 +1485,7 @@ static int m66592_udc_start(struct usb_gadget *g, return 0; } -static int m66592_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int m66592_udc_stop(struct usb_gadget *g) { struct m66592 *m66592 = to_m66592(g); diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index e3ef744..ea422ac 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1266,8 +1266,7 @@ static int mv_u3d_start(struct usb_gadget *g, return 0; } -static int mv_u3d_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int mv_u3d_stop(struct usb_gadget *g) { struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget); struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 32d24ff..f104ac0 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -1223,7 +1223,7 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) } static int mv_udc_start(struct usb_gadget *, struct usb_gadget_driver *); -static int mv_udc_stop(struct usb_gadget *, struct usb_gadget_driver *); +static int mv_udc_stop(struct usb_gadget *); /* device controller usb_gadget_ops structure */ static const struct usb_gadget_ops mv_ops = { @@ -1371,8 +1371,7 @@ static int mv_udc_start(struct usb_gadget *gadget, return 0; } -static int mv_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int mv_udc_stop(struct usb_gadget *gadget) { struct mv_udc *udc; unsigned long flags; diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 4641df5..887bea4 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1169,8 +1169,7 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on) static int net2272_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver); -static int net2272_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver); +static int net2272_stop(struct usb_gadget *_gadget); static const struct usb_gadget_ops net2272_ops = { .get_frame = net2272_get_frame, @@ -1500,8 +1499,7 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) net2272_usb_reinit(dev); } -static int net2272_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver) +static int net2272_stop(struct usb_gadget *_gadget) { struct net2272 *dev; unsigned long flags; diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index a30df8ef..bd03a1b 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1548,8 +1548,7 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) static int net2280_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver); -static int net2280_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver); +static int net2280_stop(struct usb_gadget *_gadget); static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, @@ -2432,8 +2431,7 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver) usb_reinit(dev); } -static int net2280_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver) +static int net2280_stop(struct usb_gadget *_gadget) { struct net2280 *dev; unsigned long flags; diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index dcdfea4..534b85c 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -1311,8 +1311,7 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on) static int omap_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int omap_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int omap_udc_stop(struct usb_gadget *g); static const struct usb_gadget_ops omap_gadget_ops = { .get_frame = omap_get_frame, @@ -2102,8 +2101,7 @@ done: return status; } -static int omap_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int omap_udc_stop(struct usb_gadget *g) { unsigned long flags; int status = -ENODEV; diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index ccbe3d4..6534f36 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1240,8 +1240,8 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA) static int pch_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int pch_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int pch_udc_stop(struct usb_gadget *g); + static const struct usb_gadget_ops pch_udc_ops = { .get_frame = pch_udc_pcd_get_frame, .wakeup = pch_udc_pcd_wakeup, @@ -3008,8 +3008,7 @@ static int pch_udc_start(struct usb_gadget *g, return 0; } -static int pch_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int pch_udc_stop(struct usb_gadget *g) { struct pch_udc_dev *dev = to_pch_udc(g); diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 098fa57..2944092 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -998,8 +998,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) static int pxa25x_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int pxa25x_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int pxa25x_udc_stop(struct usb_gadget *g); static const struct usb_gadget_ops pxa25x_udc_ops = { .get_frame = pxa25x_udc_get_frame, @@ -1311,8 +1310,7 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) udc_reinit(dev); } -static int pxa25x_udc_stop(struct usb_gadget*g, - struct usb_gadget_driver *driver) +static int pxa25x_udc_stop(struct usb_gadget*g) { struct pxa25x_udc *dev = to_pxa25x(g); diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index b90b1f3..17a0193 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1669,8 +1669,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) static int pxa27x_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int pxa27x_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int pxa27x_udc_stop(struct usb_gadget *g); static const struct usb_gadget_ops pxa_udc_ops = { .get_frame = pxa_udc_get_frame, @@ -1857,8 +1856,7 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) * * Returns 0 if no error, -ENODEV, -EINVAL otherwise */ -static int pxa27x_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int pxa27x_udc_stop(struct usb_gadget *g) { struct pxa_udc *udc = to_pxa(g); diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index f818661..b63a527 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1763,8 +1763,7 @@ static int r8a66597_start(struct usb_gadget *gadget, return 0; } -static int r8a66597_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int r8a66597_stop(struct usb_gadget *gadget) { struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); unsigned long flags; diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index de95e9d..97d3a91 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -1188,8 +1188,7 @@ err_supplies: return ret; } -static int s3c_hsudc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int s3c_hsudc_stop(struct usb_gadget *gadget) { struct s3c_hsudc *hsudc = to_hsudc(gadget); unsigned long flags; diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index ff423d1..2a8e36d 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -1541,8 +1541,7 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma) static int s3c2410_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int s3c2410_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int s3c2410_udc_stop(struct usb_gadget *g); static const struct usb_gadget_ops s3c2410_ops = { .get_frame = s3c2410_udc_get_frame, @@ -1683,8 +1682,7 @@ static int s3c2410_udc_start(struct usb_gadget *g, return 0; } -static int s3c2410_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int s3c2410_udc_stop(struct usb_gadget *g) { struct s3c2410_udc *udc = to_s3c2410(g); diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 52f457b..135504b 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -204,7 +204,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc) */ static inline void usb_gadget_udc_stop(struct usb_udc *udc) { - udc->gadget->ops->udc_stop(udc->gadget, udc->driver); + udc->gadget->ops->udc_stop(udc->gadget); } /** diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index ed27e16..1eac56f 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -1403,8 +1403,7 @@ err: * * Return: zero always */ -static int xudc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int xudc_stop(struct usb_gadget *gadget) { struct xusb_udc *udc = to_udc(gadget); unsigned long flags; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 88d63e0..4ab1896 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1684,8 +1684,7 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) static int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int musb_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int musb_gadget_stop(struct usb_gadget *g); static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, @@ -1923,8 +1922,7 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) * * @param driver the gadget driver to unregister */ -static int musb_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int musb_gadget_stop(struct usb_gadget *g) { struct musb *musb = gadget_to_musb(g); unsigned long flags; diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 2d17c10..7a45210 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -851,8 +851,7 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD); } -static int usbhsg_gadget_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int usbhsg_gadget_stop(struct usb_gadget *gadget) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 522cafe..70965fc 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -490,8 +490,7 @@ struct usb_gadget_ops { void (*get_config_params)(struct usb_dcd_config_params *); int (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); - int (*udc_stop)(struct usb_gadget *, - struct usb_gadget_driver *); + int (*udc_stop)(struct usb_gadget *); }; /** -- cgit v0.10.2 From 02e8c966274f1049cca8d3f17092f8275979b8eb Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 18:57:06 -0500 Subject: usb: gadget: udc: core: prepend udc_attach_driver with usb_ No functional changes, just adding a prefix which should have been there from the start. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index d25f9f3..7564814 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -271,7 +271,7 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, ret = -EBUSY; goto err; } - ret = udc_attach_driver(name, &gi->composite.gadget_driver); + ret = usb_udc_attach_driver(name, &gi->composite.gadget_driver); if (ret) goto err; gi->udc_name = name; diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 135504b..e31d574 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -411,7 +411,7 @@ err1: return ret; } -int udc_attach_driver(const char *name, struct usb_gadget_driver *driver) +int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; int ret = -ENODEV; @@ -435,7 +435,7 @@ out: mutex_unlock(&udc_lock); return ret; } -EXPORT_SYMBOL_GPL(udc_attach_driver); +EXPORT_SYMBOL_GPL(usb_udc_attach_driver); int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 70965fc..70ddb39 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -924,7 +924,7 @@ extern int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)); extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget); extern void usb_del_gadget_udc(struct usb_gadget *gadget); -extern int udc_attach_driver(const char *name, +extern int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver); /*-------------------------------------------------------------------------*/ -- cgit v0.10.2 From 545d64a46c1ed04eb96802a3bf5b6627c4d28dbd Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 17 Oct 2014 22:43:04 +0200 Subject: usb: gadget: pxa27x_udc device-tree documentation Add documentation for device-tree binding of arm PXA 27x udc (usb device) driver. Signed-off-by: Robert Jarzmik Cc: devicetree@vger.kernel.org Acked-by: Arnd Bergmann Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt index 79729a9..9c33179 100644 --- a/Documentation/devicetree/bindings/usb/pxa-usb.txt +++ b/Documentation/devicetree/bindings/usb/pxa-usb.txt @@ -29,3 +29,25 @@ Example: marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */ }; +UDC + +Required properties: + - compatible: Should be "marvell,pxa270-udc" for USB controllers + used in device mode. + - reg: usb device MMIO address space + - interrupts: single interrupt generated by the UDC IP + - clocks: input clock of the UDC IP (see clock-bindings.txt) + +Optional properties: + - gpios: + - gpio activated to control the USB D+ pullup (see gpio.txt) + +Example: + + pxa27x_udc: udc@40600000 { + compatible = "marvell,pxa270-udc"; + reg = <0x40600000 0x10000>; + interrupts = <11>; + clocks = <&pxa2xx_clks 11>; + gpios = <&gpio 22 GPIO_ACTIVE_LOW>; + }; -- cgit v0.10.2 From 95fcc6a9014f1ea6419d1e8ce796173410c5ad63 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 17 Oct 2014 22:43:05 +0200 Subject: usb: gadget: pxa27x_udc: use devm_* helpers Use devm_* helpers in the probe function to simplify the error path and the remove path. Signed-off-by: Robert Jarzmik Cc: Sergei Shtylyov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 17a0193..c7deac4 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2438,8 +2438,9 @@ static int pxa_udc_probe(struct platform_device *pdev) } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) - return -ENXIO; + udc->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(udc->regs)) + return PTR_ERR(udc->regs); udc->irq = platform_get_irq(pdev, 0); if (udc->irq < 0) return udc->irq; @@ -2455,21 +2456,13 @@ static int pxa_udc_probe(struct platform_device *pdev) if (udc->gpiod) gpiod_direction_output(udc->gpiod, 0); - udc->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(udc->clk)) { - retval = PTR_ERR(udc->clk); - goto err_clk; - } + udc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(udc->clk)) + return PTR_ERR(udc->clk); + retval = clk_prepare(udc->clk); if (retval) - goto err_clk_prepare; - - retval = -ENOMEM; - udc->regs = ioremap(regs->start, resource_size(regs)); - if (!udc->regs) { - dev_err(&pdev->dev, "Unable to map UDC I/O memory\n"); - goto err_map; - } + return retval; udc->vbus_sensed = 0; @@ -2479,32 +2472,23 @@ static int pxa_udc_probe(struct platform_device *pdev) pxa_eps_setup(udc); /* irq setup after old hardware state is cleaned up */ - retval = request_irq(udc->irq, pxa_udc_irq, - IRQF_SHARED, driver_name, udc); + retval = devm_request_irq(&pdev->dev, udc->irq, pxa_udc_irq, + IRQF_SHARED, driver_name, udc); if (retval != 0) { dev_err(udc->dev, "%s: can't get irq %i, err %d\n", driver_name, udc->irq, retval); - goto err_irq; + goto err; } retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (retval) - goto err_add_udc; + goto err; pxa_init_debugfs(udc); return 0; - -err_add_udc: - free_irq(udc->irq, udc); -err_irq: - iounmap(udc->regs); -err_map: +err: clk_unprepare(udc->clk); -err_clk_prepare: - clk_put(udc->clk); - udc->clk = NULL; -err_clk: return retval; } @@ -2518,7 +2502,6 @@ static int pxa_udc_remove(struct platform_device *_dev) usb_del_gadget_udc(&udc->gadget); usb_gadget_unregister_driver(udc->driver); - free_irq(udc->irq, udc); pxa_cleanup_debugfs(udc); usb_put_phy(udc->transceiver); @@ -2526,8 +2509,6 @@ static int pxa_udc_remove(struct platform_device *_dev) udc->transceiver = NULL; the_controller = NULL; clk_unprepare(udc->clk); - clk_put(udc->clk); - iounmap(udc->regs); return 0; } -- cgit v0.10.2 From f4fd094cdfd124d7653a500e81ec3bb7ae3e9919 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 17 Oct 2014 22:43:06 +0200 Subject: usb: gadget: pxa27x_udc: fix clock prepare and enable As the udc clock controls both the output signals and the internal IP, it must be enabled before any UDC register is touched. The bug is revealed when the clock framework disables the clock for a couple of milliseconds during the boot sequence, and the endpoint configuration is lost. The bug is hidden when clock framework is not used, because no "unused clocks disable" occurs. This patch fixes the wrong behaviour by ensuring that : - whenever a UDC register is read or written, the clock is enabled - reworks the endpoints programming to have it done under running clock - reworks suspend/resume to ensure the same thing Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index c7deac4..dd6890d 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1698,10 +1698,10 @@ static void udc_disable(struct pxa_udc *udc) udc_writel(udc, UDCICR1, 0); udc_clear_mask_UDCCR(udc, UDCCR_UDE); - clk_disable(udc->clk); ep0_idle(udc); udc->gadget.speed = USB_SPEED_UNKNOWN; + clk_disable(udc->clk); udc->enabled = 0; } @@ -1754,16 +1754,16 @@ static void udc_enable(struct pxa_udc *udc) if (udc->enabled) return; + clk_enable(udc->clk); udc_writel(udc, UDCICR0, 0); udc_writel(udc, UDCICR1, 0); udc_clear_mask_UDCCR(udc, UDCCR_UDE); - clk_enable(udc->clk); - ep0_idle(udc); udc->gadget.speed = USB_SPEED_FULL; memset(&udc->stats, 0, sizeof(udc->stats)); + pxa_eps_setup(udc); udc_set_mask_UDCCR(udc, UDCCR_UDE); ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_ACM); udelay(2); @@ -2469,7 +2469,6 @@ static int pxa_udc_probe(struct platform_device *pdev) the_controller = udc; platform_set_drvdata(pdev, udc); udc_init_data(udc); - pxa_eps_setup(udc); /* irq setup after old hardware state is cleaned up */ retval = devm_request_irq(&pdev->dev, udc->irq, pxa_udc_irq, @@ -2485,7 +2484,8 @@ static int pxa_udc_probe(struct platform_device *pdev) goto err; pxa_init_debugfs(udc); - + if (should_enable_udc(udc)) + udc_enable(udc); return 0; err: clk_unprepare(udc->clk); @@ -2538,19 +2538,11 @@ extern void pxa27x_clear_otgph(void); */ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state) { - int i; struct pxa_udc *udc = platform_get_drvdata(_dev); struct pxa_ep *ep; ep = &udc->pxa_ep[0]; udc->udccsr0 = udc_ep_readl(ep, UDCCSR); - for (i = 1; i < NR_PXA_ENDPOINTS; i++) { - ep = &udc->pxa_ep[i]; - ep->udccsr_value = udc_ep_readl(ep, UDCCSR); - ep->udccr_value = udc_ep_readl(ep, UDCCR); - ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n", - ep->udccsr_value, ep->udccr_value); - } udc_disable(udc); udc->pullup_resume = udc->pullup_on; @@ -2568,19 +2560,11 @@ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state) */ static int pxa_udc_resume(struct platform_device *_dev) { - int i; struct pxa_udc *udc = platform_get_drvdata(_dev); struct pxa_ep *ep; ep = &udc->pxa_ep[0]; udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME)); - for (i = 1; i < NR_PXA_ENDPOINTS; i++) { - ep = &udc->pxa_ep[i]; - udc_ep_writel(ep, UDCCSR, ep->udccsr_value); - udc_ep_writel(ep, UDCCR, ep->udccr_value); - ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n", - ep->udccsr_value, ep->udccr_value); - } dplus_pullup(udc, udc->pullup_resume); if (should_enable_udc(udc)) -- cgit v0.10.2 From 0d3ca262699fd6d7c5dcc25ff29a711851797117 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 20:15:08 -0500 Subject: usb: dwc2: gadget: do not call usb_gadget_unregister_driver() that call is completely unnecessary because usb_del_gadget_udc() already makes sure the gadget driver is properly unregistered from the UDC. Acked-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 441f1c4..701d3e1 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3605,14 +3605,7 @@ static int s3c_hsotg_remove(struct platform_device *pdev) struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); usb_del_gadget_udc(&hsotg->gadget); - s3c_hsotg_delete_debug(hsotg); - - if (hsotg->driver) { - /* should have been done already by driver model core */ - usb_gadget_unregister_driver(hsotg->driver); - } - clk_disable_unprepare(hsotg->clk); return 0; -- cgit v0.10.2 From c77f570fe2ec9d205cdd90805dd78fcd70b860ec Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 20:18:23 -0500 Subject: usb: gadget: udc: dummy: do not call usb_gadget_unregister_driver() that call is completely unnecessary because usb_del_gadget_udc() already makes sure the gadget driver is properly unregistered from the UDC. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 5bffb75..254b9e7 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2362,7 +2362,6 @@ static void dummy_stop(struct usb_hcd *hcd) dum = hcd_to_dummy_hcd(hcd)->dum; device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); - usb_gadget_unregister_driver(dum->driver); dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n"); } -- cgit v0.10.2 From 7fd1f9d6663fa20997d2d951ef7ee7e2cd0d266e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 20:19:02 -0500 Subject: usb: gadget: udc: net2272: do not call usb_gadget_unregister_driver() that call is completely unnecessary because usb_del_gadget_udc() already makes sure the gadget driver is properly unregistered from the UDC. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 887bea4..ab3a739 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -2195,18 +2195,8 @@ static void net2272_remove(struct net2272 *dev) { usb_del_gadget_udc(&dev->gadget); - - /* start with the driver above us */ - if (dev->driver) { - /* should have been done already by driver model core */ - dev_warn(dev->dev, "pci remove, driver '%s' is still registered\n", - dev->driver->driver.name); - usb_gadget_unregister_driver(dev->driver); - } - free_irq(dev->irq, dev); iounmap(dev->base_addr); - device_remove_file(dev->dev, &dev_attr_registers); dev_info(dev->dev, "unbind\n"); -- cgit v0.10.2 From 76bfa95eab10f6bfd7e7d33a9b7cccbefa036f5c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 17 Oct 2014 20:19:41 -0500 Subject: usb: gadget: udc: pxa27x: do not call usb_gadget_unregister_driver() that call is completely unnecessary because usb_del_gadget_udc() already makes sure the gadget driver is properly unregistered from the UDC. Acked-by: Robert Jarzmik Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index dd6890d..69e7b816 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2501,7 +2501,6 @@ static int pxa_udc_remove(struct platform_device *_dev) struct pxa_udc *udc = platform_get_drvdata(_dev); usb_del_gadget_udc(&udc->gadget); - usb_gadget_unregister_driver(udc->driver); pxa_cleanup_debugfs(udc); usb_put_phy(udc->transceiver); -- cgit v0.10.2 From 5a8053099c4a3fb47189575be34350ac40fb6080 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 24 Oct 2014 00:34:12 +0400 Subject: usb: musb: omap2430: use MUSB_DEVCTL_BDEVICE The OMAP2+ MUSB glue layer still uses a bare number for the DEVCTL.B-Device bit in one place, while there's #define MUSB_DEVCTL_BDEVICE for that. Signed-off-by: Sergei Shtylyov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 6669f26..20fc2a5 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -162,7 +162,8 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) * Wait for the musb to set as A device to enable the * VBUS */ - while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + while (musb_readb(musb->mregs, MUSB_DEVCTL) & + MUSB_DEVCTL_BDEVICE) { mdelay(5); cpu_relax(); -- cgit v0.10.2 From 4d852011a505005aab50250b211c132a654cb507 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 29 Oct 2014 21:30:15 +0530 Subject: usb: dwc3: keystone: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 7ec8495..dd8d2df 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -104,11 +104,6 @@ static int kdwc3_probe(struct platform_device *pdev) kdwc->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing usbss resource\n"); - return -EINVAL; - } - kdwc->usbss = devm_ioremap_resource(dev, res); if (IS_ERR(kdwc->usbss)) return PTR_ERR(kdwc->usbss); -- cgit v0.10.2 From 687f16b8599bed84dc4484a70509b9443dfc3baa Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 29 Oct 2014 21:30:16 +0530 Subject: usb: renesas_usbhs: common: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 6dae115..169307b 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -496,9 +496,8 @@ static int usbhs_probe(struct platform_device *pdev) } /* platform data */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res || !irq_res) { + if (!irq_res) { dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n"); return -ENODEV; } @@ -508,6 +507,7 @@ static int usbhs_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); -- cgit v0.10.2 From 28a26945df3ac3a4c80eef48b73be88fb53744ae Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 29 Oct 2014 21:30:17 +0530 Subject: usb: phy: rcar-usb: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c index 4879596..1e09b83 100644 --- a/drivers/usb/phy/phy-rcar-usb.c +++ b/drivers/usb/phy/phy-rcar-usb.c @@ -195,11 +195,9 @@ static int rcar_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(reg0); res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res1) { - reg1 = devm_ioremap_resource(dev, res1); - if (IS_ERR(reg1)) - return PTR_ERR(reg1); - } + reg1 = devm_ioremap_resource(dev, res1); + if (IS_ERR(reg1)) + return PTR_ERR(reg1); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) -- cgit v0.10.2 From 768330756d9bbfee6eca573b96c828adb1ba9058 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 29 Oct 2014 21:30:18 +0530 Subject: usb: musb: dsps: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 6209456..759ef1d 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -447,9 +447,6 @@ static int dsps_musb_init(struct musb *musb) int ret; r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); - if (!r) - return -EINVAL; - reg_base = devm_ioremap_resource(dev, r); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); -- cgit v0.10.2 From 1f79b26cf3090f024b3a02cfc3b692bc6482c576 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 29 Oct 2014 21:30:19 +0530 Subject: usb: musb: core: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b841ee0..55ebd4b 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2080,10 +2080,10 @@ static int musb_probe(struct platform_device *pdev) struct resource *iomem; void __iomem *base; - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem || irq <= 0) + if (irq <= 0) return -ENODEV; + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, iomem); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v0.10.2 From ac3c81f3e8dcb435a92e03e2fa069d1e60687cfe Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 20 Oct 2014 12:45:35 +0200 Subject: usb: dwc2: gadget: move setting last reset time to s3c_hsotg_core_init This patch removes duplicated code and sets last_rst variable in the function which does the hardware reset. Acked-by: Paul Zimmerman Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 701d3e1..f1cde25 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2247,6 +2247,8 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) /* must be at-least 3ms to allow bus to see disconnect */ mdelay(3); + hsotg->last_rst = jiffies; + /* remove the soft-disconnect and let's go */ __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); } @@ -2341,7 +2343,6 @@ irq_retry: -ECONNRESET, true); s3c_hsotg_core_init(hsotg); - hsotg->last_rst = jiffies; } } } @@ -2905,7 +2906,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, goto err; } - hsotg->last_rst = jiffies; dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0; @@ -3656,7 +3656,6 @@ static int s3c_hsotg_resume(struct platform_device *pdev) } spin_lock_irqsave(&hsotg->lock, flags); - hsotg->last_rst = jiffies; s3c_hsotg_phy_enable(hsotg); s3c_hsotg_core_init(hsotg); spin_unlock_irqrestore(&hsotg->lock, flags); -- cgit v0.10.2 From ad38dc5dac5d8df80c0c394459f950eed1dccbcd Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 20 Oct 2014 12:45:36 +0200 Subject: usb: dwc2: gadget: decouple setting soft-disconnect from s3c_hsotg_core_init This patch changes s3c_hsotg_core_init function to leave hardware in soft disconnect mode, so the moment of coupling the hardware to the usb bus can be later controlled by the separate functions for enabling and disabling soft disconnect mode. This patch is a preparation to rework pullup() method. Acked-by: Paul Zimmerman Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index f1cde25..5109936 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2124,7 +2124,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) * * Issue a soft reset to the core, and await the core finishing it. */ -static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) +static void s3c_hsotg_core_init_disconnected(struct s3c_hsotg *hsotg) { s3c_hsotg_corereset(hsotg); @@ -2241,14 +2241,23 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) readl(hsotg->regs + DOEPCTL0)); /* clear global NAKs */ - writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK, + writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK | DCTL_SFTDISCON, hsotg->regs + DCTL); /* must be at-least 3ms to allow bus to see disconnect */ mdelay(3); hsotg->last_rst = jiffies; +} + +static void s3c_hsotg_core_disconnect(struct s3c_hsotg *hsotg) +{ + /* set the soft-disconnect bit */ + __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); +} +static void s3c_hsotg_core_connect(struct s3c_hsotg *hsotg) +{ /* remove the soft-disconnect and let's go */ __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); } @@ -2342,7 +2351,8 @@ irq_retry: kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); - s3c_hsotg_core_init(hsotg); + s3c_hsotg_core_init_disconnected(hsotg); + s3c_hsotg_core_connect(hsotg); } } } @@ -2977,7 +2987,8 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) if (is_on) { s3c_hsotg_phy_enable(hsotg); clk_enable(hsotg->clk); - s3c_hsotg_core_init(hsotg); + s3c_hsotg_core_init_disconnected(hsotg); + s3c_hsotg_core_connect(hsotg); } else { clk_disable(hsotg->clk); s3c_hsotg_phy_disable(hsotg); @@ -3657,7 +3668,8 @@ static int s3c_hsotg_resume(struct platform_device *pdev) spin_lock_irqsave(&hsotg->lock, flags); s3c_hsotg_phy_enable(hsotg); - s3c_hsotg_core_init(hsotg); + s3c_hsotg_core_init_disconnected(hsotg); + s3c_hsotg_core_connect(hsotg); spin_unlock_irqrestore(&hsotg->lock, flags); return ret; -- cgit v0.10.2 From c816c47fe6205b18ff6f8843c258ca35c1536dac Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 20 Oct 2014 12:45:37 +0200 Subject: usb: dwc2: gadget: move phy control calls out of pullup() method This patch moves phy enable/disable calls from pullup() method to udc_start/stop functions. This solves the issue related to limited caller context for PHY functions, because they cannot be called from non-sleeping context. This is also a preparation for using soft-disconnect feature of udc controller in pullup() method. Acked-by: Paul Zimmerman Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 5109936..68865e5 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2916,6 +2916,8 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, goto err; } + s3c_hsotg_phy_enable(hsotg); + dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0; @@ -2951,6 +2953,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) spin_unlock_irqrestore(&hsotg->lock, flags); + s3c_hsotg_phy_disable(hsotg); + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); clk_disable(hsotg->clk); @@ -2985,13 +2989,11 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) spin_lock_irqsave(&hsotg->lock, flags); if (is_on) { - s3c_hsotg_phy_enable(hsotg); clk_enable(hsotg->clk); s3c_hsotg_core_init_disconnected(hsotg); s3c_hsotg_core_connect(hsotg); } else { clk_disable(hsotg->clk); - s3c_hsotg_phy_disable(hsotg); } hsotg->gadget.speed = USB_SPEED_UNKNOWN; -- cgit v0.10.2 From 5b9451f8c4fbaf0549139755fb45ff2b57975b7f Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 20 Oct 2014 12:45:38 +0200 Subject: usb: dwc2: gadget: use soft-disconnect udc feature in pullup() method This patch moves udc initialization from pullup() method to s3c_hsotg_udc_start(), so that method ends with hardware fully initialized and left in soft-disconnected state. After this change, the pullup() method simply clears soft-disconnect start() when called with is_on=1. For completeness, a call to s3c_hsotg_core_disconnect() has been added when pullup() method is called with is_on=0, what puts the udc hardware back to soft-disconnected state. Acked-by: Paul Zimmerman Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 68865e5..5872db9 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2880,6 +2880,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct s3c_hsotg *hsotg = to_hsotg(gadget); + unsigned long flags; int ret; if (!hsotg) { @@ -2918,7 +2919,13 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, s3c_hsotg_phy_enable(hsotg); + spin_lock_irqsave(&hsotg->lock, flags); + s3c_hsotg_init(hsotg); + s3c_hsotg_core_init_disconnected(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); + return 0; err: @@ -2990,9 +2997,9 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) spin_lock_irqsave(&hsotg->lock, flags); if (is_on) { clk_enable(hsotg->clk); - s3c_hsotg_core_init_disconnected(hsotg); s3c_hsotg_core_connect(hsotg); } else { + s3c_hsotg_core_disconnect(hsotg); clk_disable(hsotg->clk); } -- cgit v0.10.2 From 7b093f773b85dd816c5717193ec94a7cfec73a09 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 20 Oct 2014 12:45:39 +0200 Subject: usb: dwc2: gadget: fix calls to phy control functions in suspend/resume code This patch moves calls to phy enable/disable out of spinlock protected blocks in device suspend/resume to fix incorrect caller context. Phy related functions must not be called from atomic context. To protect device internal state from a race during suspend, a call to s3c_hsotg_core_disconnect() is added under a spinlock, what prevents any further activity on the usb bus. Acked-by: Paul Zimmerman Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 5872db9..fcd2bb5 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3642,11 +3642,13 @@ static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) hsotg->driver->driver.name); spin_lock_irqsave(&hsotg->lock, flags); + s3c_hsotg_core_disconnect(hsotg); s3c_hsotg_disconnect(hsotg); - s3c_hsotg_phy_disable(hsotg); hsotg->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock_irqrestore(&hsotg->lock, flags); + s3c_hsotg_phy_disable(hsotg); + if (hsotg->driver) { int ep; for (ep = 0; ep < hsotg->num_of_eps; ep++) @@ -3675,8 +3677,9 @@ static int s3c_hsotg_resume(struct platform_device *pdev) hsotg->supplies); } - spin_lock_irqsave(&hsotg->lock, flags); s3c_hsotg_phy_enable(hsotg); + + spin_lock_irqsave(&hsotg->lock, flags); s3c_hsotg_core_init_disconnected(hsotg); s3c_hsotg_core_connect(hsotg); spin_unlock_irqrestore(&hsotg->lock, flags); -- cgit v0.10.2 From 3e87d9a3dee0ad5416c3fb599a6019a24bfe6e64 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 27 Oct 2014 10:49:42 +0100 Subject: usb: musb: core: use ->resume instead ->resume_noirq In commit 0ec8fd70fb ("USB: musb: fix possible panic while resuming") musb_resume() became musb_resume_early() in order to enable the clocks early on resume. This piece of the resume code was removed later in commit 034917612 ("usb: musb: move clock handling to glue layer"). In between the function was renamed from musb_resume_early() to musb_resume_noirq() by commit commit 48fea9659e ("USB: Rework musb suspend()/resume_early()"). Now I see that first musb_core is resumed followed by phy and glue layer and I ask myself is this really what we intend to do? This kind of revoked the purpose of the first commit (0ec8fd70fb). Because of this and because it looks wrong to resume (core) before the glue layer I push it to the ->resume callback. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 55ebd4b..e46e295 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2297,7 +2297,7 @@ static int musb_suspend(struct device *dev) return 0; } -static int musb_resume_noirq(struct device *dev) +static int musb_resume(struct device *dev) { struct musb *musb = dev_to_musb(dev); @@ -2348,7 +2348,7 @@ static int musb_runtime_resume(struct device *dev) static const struct dev_pm_ops musb_dev_pm_ops = { .suspend = musb_suspend, - .resume_noirq = musb_resume_noirq, + .resume = musb_resume, .runtime_suspend = musb_runtime_suspend, .runtime_resume = musb_runtime_resume, }; -- cgit v0.10.2 From 8b920f16e69550d3f6c7c67dc3cef42aafca498d Mon Sep 17 00:00:00 2001 From: Pavitrakumar Managutte Date: Mon, 27 Oct 2014 22:49:26 +0530 Subject: usb: gadget: function: Added usb_assign_descriptors failure check Added failure check for usb_assign_descriptors call in bind function. Acked-By: Sebastian Andrzej Siewior Signed-off-by: Pavitrakumar Managutte Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 16361b0..bdcda9f 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1441,6 +1441,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, NULL); + if (status) + goto fail; + /* * NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code -- cgit v0.10.2 From a2655e4a8edb66d21b0967940172e83a51d30ef3 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 29 Oct 2014 22:18:55 +0800 Subject: usb: gadget: fix ptr_ret.cocci warnings drivers/usb/gadget/udc/r8a66597-udc.c:1849:1-3: WARNING: PTR_ERR_OR_ZERO can be used Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Generated by: scripts/coccinelle/api/ptr_ret.cocci Signed-off-by: Fengguang Wu Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index b63a527..be31b57 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1845,10 +1845,7 @@ static int r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac"); r8a66597->sudmac_reg = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(r8a66597->sudmac_reg)) - return PTR_ERR(r8a66597->sudmac_reg); - - return 0; + return PTR_ERR_OR_ZERO(r8a66597->sudmac_reg); } static int r8a66597_probe(struct platform_device *pdev) -- cgit v0.10.2 From e47d92545c2972bcf3711e7db80f481e402163c7 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 30 Oct 2014 18:41:13 +0100 Subject: usb: move the OTG state from the USB PHY to the OTG structure Before using the PHY framework instead of the USB PHY one, we need to move the OTG state into another place, since it won't be available when USB PHY isn't used. This patch moves the OTG state into the OTG structure, and makes all the needed modifications in the drivers using the OTG state. [ balbi@ti.com : fix build regressions with phy-tahvo.c, musb_dsps.c, phy-isp1301-omap, and chipidea's debug.c ] Acked-by: Kishon Vijay Abraham I Acked-by: Peter Chen Signed-off-by: Antoine Tenart Signed-off-by: Felipe Balbi diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index 8c84298..9f409359 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -80,11 +80,9 @@ static int omap_usb_start_srp(struct usb_otg *otg) static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host) { - struct usb_phy *phy = otg->phy; - otg->host = host; if (!host) - phy->state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; return 0; } @@ -92,11 +90,9 @@ static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host) static int omap_usb_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { - struct usb_phy *phy = otg->phy; - otg->gadget = gadget; if (!gadget) - phy->state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; return 0; } diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 795d653..f038804 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -220,7 +220,7 @@ static int ci_otg_show(struct seq_file *s, void *unused) /* ------ State ----- */ seq_printf(s, "OTG state: %s\n\n", - usb_otg_state_string(ci->transceiver->state)); + usb_otg_state_string(ci->transceiver->otg->state)); /* ------ State Machine Variables ----- */ seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop); diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index caaabc5..8cb2508 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -328,7 +328,7 @@ static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator) set_tmout(ci, indicator); /* only vbus fall below B_sess_vld in b_idle state */ - if (ci->transceiver->state == OTG_STATE_B_IDLE) + if (ci->fsm.otg->state == OTG_STATE_B_IDLE) ci_otg_queue_work(ci); } @@ -582,11 +582,11 @@ int ci_otg_fsm_work(struct ci_hdrc *ci) * when there is no gadget class driver */ if (ci->fsm.id && !(ci->driver) && - ci->transceiver->state < OTG_STATE_A_IDLE) + ci->fsm.otg->state < OTG_STATE_A_IDLE) return 0; if (otg_statemachine(&ci->fsm)) { - if (ci->transceiver->state == OTG_STATE_A_IDLE) { + if (ci->fsm.otg->state == OTG_STATE_A_IDLE) { /* * Further state change for cases: * a_idle to b_idle; or @@ -600,7 +600,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci) ci_otg_queue_work(ci); if (ci->id_event) ci->id_event = false; - } else if (ci->transceiver->state == OTG_STATE_B_IDLE) { + } else if (ci->fsm.otg->state == OTG_STATE_B_IDLE) { if (ci->fsm.b_sess_vld) { ci->fsm.power_up = 0; /* @@ -627,7 +627,7 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci) otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV); port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS); - switch (ci->transceiver->state) { + switch (ci->fsm.otg->state) { case OTG_STATE_A_WAIT_BCON: if (port_conn) { fsm->b_conn = 1; @@ -794,7 +794,7 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) ci->transceiver->otg = ci->fsm.otg; ci->fsm.power_up = 1; ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; - ci->transceiver->state = OTG_STATE_UNDEFINED; + ci->fsm.otg->state = OTG_STATE_UNDEFINED; ci->fsm.ops = &ci_otg_ops; mutex_init(&ci->fsm.lock); diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c index 98e8340..c6b35b7 100644 --- a/drivers/usb/common/usb-otg-fsm.c +++ b/drivers/usb/common/usb-otg-fsm.c @@ -124,10 +124,10 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) { state_changed = 1; - if (fsm->otg->phy->state == new_state) + if (fsm->otg->state == new_state) return 0; VDBG("Set state: %s\n", usb_otg_state_string(new_state)); - otg_leave_state(fsm, fsm->otg->phy->state); + otg_leave_state(fsm, fsm->otg->state); switch (new_state) { case OTG_STATE_B_IDLE: otg_drv_vbus(fsm, 0); @@ -236,7 +236,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) break; } - fsm->otg->phy->state = new_state; + fsm->otg->state = new_state; return 0; } @@ -247,7 +247,7 @@ int otg_statemachine(struct otg_fsm *fsm) mutex_lock(&fsm->lock); - state = fsm->otg->phy->state; + state = fsm->otg->state; state_changed = 0; /* State machine state change judgement */ diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 0231606d..cf89b4b1 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -183,7 +183,7 @@ static void start_hnp(struct ohci_hcd *ohci) otg_start_hnp(hcd->usb_phy->otg); local_irq_save(flags); - hcd->usb_phy->state = OTG_STATE_A_SUSPEND; + hcd->usb_phy->otg.state = OTG_STATE_A_SUSPEND; writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]); l = omap_readl(OTG_CTRL); l &= ~OTG_A_BUSREQ; diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index a2735df..d836a3e 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -149,25 +149,25 @@ static void otg_timer(unsigned long _musb) */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_BCON: devctl &= ~MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } break; case OTG_STATE_A_WAIT_VFALL: - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG, MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT); break; @@ -176,7 +176,7 @@ static void otg_timer(unsigned long _musb) if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; break; default: break; @@ -193,9 +193,9 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || (musb->a_wait_bcon == 0 && - musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); del_timer(&otg_workaround); last_timer = jiffies; return; @@ -208,7 +208,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), jiffies_to_msecs(timeout - jiffies)); mod_timer(&otg_workaround, timeout); } @@ -278,27 +278,27 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci) * devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; portstate(musb->port1_status |= USB_PORT_STAT_POWER); del_timer(&otg_workaround); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } /* NOTE: this must complete power-on within 100 ms. */ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; @@ -324,7 +324,7 @@ eoi: } /* Poll for ID change */ - if (musb->xceiv->state == OTG_STATE_B_IDLE) + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 8554c6f..f23ce40b 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -185,8 +185,8 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci) } /* Start sampling ID pin, when plug is removed from MUSB */ - if ((musb->xceiv->state == OTG_STATE_B_IDLE - || musb->xceiv->state == OTG_STATE_A_WAIT_BCON) || + if ((musb->xceiv->otg->state == OTG_STATE_B_IDLE + || musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON) || (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) { mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); musb->a_wait_bcon = TIMER_DELAY; @@ -205,7 +205,7 @@ static void musb_conn_timer_handler(unsigned long _musb) static u8 toggle; spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_IDLE: case OTG_STATE_A_WAIT_BCON: /* Start a new session */ @@ -219,7 +219,7 @@ static void musb_conn_timer_handler(unsigned long _musb) if (!(val & MUSB_DEVCTL_BDEVICE)) { gpio_set_value(musb->config->gpio_vrsel, 1); - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; } else { gpio_set_value(musb->config->gpio_vrsel, 0); /* Ignore VBUSERROR and SUSPEND IRQ */ @@ -229,7 +229,7 @@ static void musb_conn_timer_handler(unsigned long _musb) val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; musb_writeb(musb->mregs, MUSB_INTRUSB, val); - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; } mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); break; @@ -245,7 +245,7 @@ static void musb_conn_timer_handler(unsigned long _musb) if (!(val & MUSB_DEVCTL_BDEVICE)) { gpio_set_value(musb->config->gpio_vrsel, 1); - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; } else { gpio_set_value(musb->config->gpio_vrsel, 0); @@ -280,13 +280,13 @@ static void musb_conn_timer_handler(unsigned long _musb) break; default: dev_dbg(musb->controller, "%s state not handled\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); break; } spin_unlock_irqrestore(&musb->lock, flags); dev_dbg(musb->controller, "state is %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } static void bfin_musb_enable(struct musb *musb) @@ -307,7 +307,7 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on) dev_dbg(musb->controller, "VBUS %s, devctl %02x " /* otg %3x conf %08x prcm %08x */ "\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), musb_readb(musb->mregs, MUSB_DEVCTL)); } diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 058775e..527c7fe 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -198,20 +198,20 @@ static void otg_timer(unsigned long _musb) */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_BCON: devctl &= ~MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } break; @@ -226,7 +226,7 @@ static void otg_timer(unsigned long _musb) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); break; } - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DA8XX_USB_INTR_SRC_SET_REG, MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT); break; @@ -248,7 +248,7 @@ static void otg_timer(unsigned long _musb) if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; break; default: break; @@ -265,9 +265,9 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || (musb->a_wait_bcon == 0 && - musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); del_timer(&otg_workaround); last_timer = jiffies; return; @@ -280,7 +280,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), jiffies_to_msecs(timeout - jiffies)); mod_timer(&otg_workaround, timeout); } @@ -341,26 +341,26 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) * devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; portstate(musb->port1_status |= USB_PORT_STAT_POWER); del_timer(&otg_workaround); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; @@ -375,7 +375,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); /* Poll for ID change */ - if (musb->xceiv->state == OTG_STATE_B_IDLE) + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 04de3ac..3c1d9b2 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -214,10 +214,10 @@ static void otg_timer(unsigned long _musb) */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl, - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_VFALL: /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL * seems to mis-handle session "start" otherwise (or in our @@ -228,7 +228,7 @@ static void otg_timer(unsigned long _musb) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); break; } - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); break; @@ -251,7 +251,7 @@ static void otg_timer(unsigned long _musb) if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; break; default: break; @@ -325,20 +325,20 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) * to stop registering in devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; portstate(musb->port1_status |= USB_PORT_STAT_POWER); del_timer(&otg_workaround); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } @@ -348,7 +348,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) davinci_musb_source_power(musb, drvvbus, 0); dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), err ? " ERROR" : "", devctl); retval = IRQ_HANDLED; @@ -361,7 +361,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) musb_writel(tibase, DAVINCI_USB_EOI_REG, 0); /* poll for ID change */ - if (musb->xceiv->state == OTG_STATE_B_IDLE) + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index e46e295..df9c5fa 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -360,23 +360,23 @@ static void musb_otg_timer_func(unsigned long data) unsigned long flags; spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_B_WAIT_ACON: dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n"); musb_g_disconnect(musb); - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb->is_active = 0; break; case OTG_STATE_A_SUSPEND: case OTG_STATE_A_WAIT_BCON: dev_dbg(musb->controller, "HNP: %s timeout\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); musb_platform_set_vbus(musb, 0); - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; break; default: dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } spin_unlock_irqrestore(&musb->lock, flags); } @@ -391,19 +391,19 @@ void musb_hnp_stop(struct musb *musb) u8 reg; dev_dbg(musb->controller, "HNP: stop from %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_PERIPHERAL: musb_g_disconnect(musb); dev_dbg(musb->controller, "HNP: back to %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); break; case OTG_STATE_B_HOST: dev_dbg(musb->controller, "HNP: Disabling HR\n"); if (hcd) hcd->self.is_b_host = 0; - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; MUSB_DEV_MODE(musb); reg = musb_readb(mbase, MUSB_POWER); reg |= MUSB_POWER_SUSPENDM; @@ -412,7 +412,7 @@ void musb_hnp_stop(struct musb *musb) break; default: dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } /* @@ -449,13 +449,13 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, */ if (int_usb & MUSB_INTR_RESUME) { handled = IRQ_HANDLED; - dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state)); + dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->otg->state)); if (devctl & MUSB_DEVCTL_HM) { void __iomem *mbase = musb->mregs; u8 power; - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: /* remote wakeup? later, GetPortStatus * will stop RESUME signaling @@ -482,25 +482,25 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, &musb->finish_resume_work, msecs_to_jiffies(20)); - musb->xceiv->state = OTG_STATE_A_HOST; + musb->xceiv->otg->state = OTG_STATE_A_HOST; musb->is_active = 1; musb_host_resume_root_hub(musb); break; case OTG_STATE_B_WAIT_ACON: - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb->is_active = 1; MUSB_DEV_MODE(musb); break; default: WARNING("bogus %s RESUME (%s)\n", "host", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } } else { - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: /* possibly DISCONNECT is upcoming */ - musb->xceiv->state = OTG_STATE_A_HOST; + musb->xceiv->otg->state = OTG_STATE_A_HOST; musb_host_resume_root_hub(musb); break; case OTG_STATE_B_WAIT_ACON: @@ -523,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, default: WARNING("bogus %s RESUME (%s)\n", "peripheral", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } } } @@ -539,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); /* IRQ arrives from ID pin sense or (later, if VBUS power * is removed) SRP. responses are time critical: @@ -550,7 +550,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, */ musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); musb->ep0_stage = MUSB_EP0_START; - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); musb_platform_set_vbus(musb, 1); @@ -576,7 +576,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, * REVISIT: do delays from lots of DEBUG_KERNEL checks * make trouble here, keeping VBUS < 4.4V ? */ - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_HOST: /* recovery is dicey once we've gotten past the * initial stages of enumeration, but if VBUS @@ -605,7 +605,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), devctl, ({ char *s; switch (devctl & MUSB_DEVCTL_VBUS) { @@ -630,10 +630,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (int_usb & MUSB_INTR_SUSPEND) { dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", - usb_otg_state_string(musb->xceiv->state), devctl); + usb_otg_state_string(musb->xceiv->otg->state), devctl); handled = IRQ_HANDLED; - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_PERIPHERAL: /* We also come here if the cable is removed, since * this silicon doesn't report ID-no-longer-grounded. @@ -657,7 +657,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb_g_suspend(musb); musb->is_active = musb->g.b_hnp_enable; if (musb->is_active) { - musb->xceiv->state = OTG_STATE_B_WAIT_ACON; + musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON; dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies( @@ -670,7 +670,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, + msecs_to_jiffies(musb->a_wait_bcon)); break; case OTG_STATE_A_HOST: - musb->xceiv->state = OTG_STATE_A_SUSPEND; + musb->xceiv->otg->state = OTG_STATE_A_SUSPEND; musb->is_active = musb->hcd->self.b_hnp_enable; break; case OTG_STATE_B_HOST: @@ -713,7 +713,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->port1_status |= USB_PORT_STAT_LOW_SPEED; /* indicate new connection to OTG machine */ - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_B_PERIPHERAL: if (int_usb & MUSB_INTR_SUSPEND) { dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n"); @@ -725,7 +725,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, case OTG_STATE_B_WAIT_ACON: dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n"); b_host: - musb->xceiv->state = OTG_STATE_B_HOST; + musb->xceiv->otg->state = OTG_STATE_B_HOST; if (musb->hcd) musb->hcd->self.is_b_host = 1; del_timer(&musb->otg_timer); @@ -733,7 +733,7 @@ b_host: default: if ((devctl & MUSB_DEVCTL_VBUS) == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { - musb->xceiv->state = OTG_STATE_A_HOST; + musb->xceiv->otg->state = OTG_STATE_A_HOST; if (hcd) hcd->self.is_b_host = 0; } @@ -743,16 +743,16 @@ b_host: musb_host_poke_root_hub(musb); dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", - usb_otg_state_string(musb->xceiv->state), devctl); + usb_otg_state_string(musb->xceiv->otg->state), devctl); } if (int_usb & MUSB_INTR_DISCONNECT) { dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), MUSB_MODE(musb), devctl); handled = IRQ_HANDLED; - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_HOST: case OTG_STATE_A_SUSPEND: musb_host_resume_root_hub(musb); @@ -770,7 +770,7 @@ b_host: musb_root_disconnect(musb); if (musb->hcd) musb->hcd->self.is_b_host = 0; - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; MUSB_DEV_MODE(musb); musb_g_disconnect(musb); break; @@ -786,7 +786,7 @@ b_host: break; default: WARNING("unhandled DISCONNECT transition (%s)\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); break; } } @@ -812,15 +812,15 @@ b_host: } } else { dev_dbg(musb->controller, "BUS RESET as %s\n", - usb_otg_state_string(musb->xceiv->state)); - switch (musb->xceiv->state) { + usb_otg_state_string(musb->xceiv->otg->state)); + switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: musb_g_reset(musb); /* FALLTHROUGH */ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ /* never use invalid T(a_wait_bcon) */ dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), TA_WAIT_BCON(musb)); mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies(TA_WAIT_BCON(musb))); @@ -831,19 +831,19 @@ b_host: break; case OTG_STATE_B_WAIT_ACON: dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", - usb_otg_state_string(musb->xceiv->state)); - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + usb_otg_state_string(musb->xceiv->otg->state)); + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb_g_reset(musb); break; case OTG_STATE_B_IDLE: - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; /* FALLTHROUGH */ case OTG_STATE_B_PERIPHERAL: musb_g_reset(musb); break; default: dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } } } @@ -1630,7 +1630,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) int ret = -EINVAL; spin_lock_irqsave(&musb->lock, flags); - ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state)); + ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->otg->state)); spin_unlock_irqrestore(&musb->lock, flags); return ret; @@ -1675,7 +1675,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr, spin_lock_irqsave(&musb->lock, flags); /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */ musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ; - if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON) + if (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON) musb->is_active = 0; musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val)); spin_unlock_irqrestore(&musb->lock, flags); @@ -1743,8 +1743,8 @@ static void musb_irq_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, irq_work); - if (musb->xceiv->state != musb->xceiv_old_state) { - musb->xceiv_old_state = musb->xceiv->state; + if (musb->xceiv->otg->state != musb->xceiv_old_state) { + musb->xceiv_old_state = musb->xceiv->otg->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); } } @@ -1983,10 +1983,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (musb->xceiv->otg->default_a) { MUSB_HST_MODE(musb); - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; } else { MUSB_DEV_MODE(musb); - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; } switch (musb->port_mode) { diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 759ef1d..440333f 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -179,9 +179,9 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || (musb->a_wait_bcon == 0 && - musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); del_timer(&glue->timer); glue->last_timer = jiffies; return; @@ -201,7 +201,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) glue->last_timer = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), jiffies_to_msecs(timeout - jiffies)); mod_timer(&glue->timer, timeout); } @@ -265,10 +265,10 @@ static void otg_timer(unsigned long _musb) */ devctl = dsps_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_BCON: dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); skip_session = 1; @@ -277,10 +277,10 @@ static void otg_timer(unsigned long _musb) case OTG_STATE_A_IDLE: case OTG_STATE_B_IDLE: if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) @@ -288,7 +288,7 @@ static void otg_timer(unsigned long _musb) mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); break; case OTG_STATE_A_WAIT_VFALL: - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; dsps_writel(musb->ctrl_base, wrp->coreintr_set, MUSB_INTR_VBUSERROR << wrp->usb_shift); break; @@ -373,26 +373,26 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; del_timer(&glue->timer); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; } /* NOTE: this must complete power-on within 100 ms. */ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; @@ -402,7 +402,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) ret |= musb_interrupt(musb); /* Poll for ID change in OTG port mode */ - if (musb->xceiv->state == OTG_STATE_B_IDLE && + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); out: @@ -900,7 +900,7 @@ static int dsps_resume(struct device *dev) dsps_writel(mbase, wrp->mode, glue->context.mode); dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); - if (musb->xceiv->state == OTG_STATE_B_IDLE && + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 4ab1896..56c31b7 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1546,7 +1546,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_B_PERIPHERAL: /* NOTE: OTG state machine doesn't include B_SUSPENDED; * that's part of the standard usb 1.1 state machine, and @@ -1587,7 +1587,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) goto done; default: dev_dbg(musb->controller, "Unhandled wake: %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); goto done; } @@ -1791,7 +1791,7 @@ int musb_gadget_setup(struct musb *musb) MUSB_DEV_MODE(musb); musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; /* this "gadget" abstracts/virtualizes the controller */ musb->g.name = musb_driver_name; @@ -1857,7 +1857,7 @@ static int musb_gadget_start(struct usb_gadget *g, musb->is_active = 1; otg_set_peripheral(otg, &musb->g); - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; spin_unlock_irqrestore(&musb->lock, flags); musb_start(musb); @@ -1941,7 +1941,7 @@ static int musb_gadget_stop(struct usb_gadget *g) (void) musb_gadget_vbus_draw(&musb->g, 0); - musb->xceiv->state = OTG_STATE_UNDEFINED; + musb->xceiv->otg->state = OTG_STATE_UNDEFINED; stop_activity(musb, NULL); otg_set_peripheral(musb->xceiv->otg, NULL); @@ -1968,7 +1968,7 @@ static int musb_gadget_stop(struct usb_gadget *g) void musb_g_resume(struct musb *musb) { musb->is_suspended = 0; - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_B_IDLE: break; case OTG_STATE_B_WAIT_ACON: @@ -1982,7 +1982,7 @@ void musb_g_resume(struct musb *musb) break; default: WARNING("unhandled RESUME transition (%s)\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } } @@ -1994,10 +1994,10 @@ void musb_g_suspend(struct musb *musb) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "devctl %02x\n", devctl); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_B_IDLE: if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; break; case OTG_STATE_B_PERIPHERAL: musb->is_suspended = 1; @@ -2012,7 +2012,7 @@ void musb_g_suspend(struct musb *musb) * A_PERIPHERAL may need care too */ WARNING("unhandled SUSPEND transition (%s)\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } } @@ -2043,22 +2043,22 @@ void musb_g_disconnect(struct musb *musb) spin_lock(&musb->lock); } - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { default: dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", - usb_otg_state_string(musb->xceiv->state)); - musb->xceiv->state = OTG_STATE_A_IDLE; + usb_otg_state_string(musb->xceiv->otg->state)); + musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); break; case OTG_STATE_A_PERIPHERAL: - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; MUSB_HST_MODE(musb); break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_HOST: case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; break; case OTG_STATE_B_SRP_INIT: break; @@ -2118,13 +2118,13 @@ __acquires(musb->lock) * In that case, do not rely on devctl for setting * peripheral mode. */ - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb->g.is_a_peripheral = 0; } else if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb->g.is_a_peripheral = 0; } else { - musb->xceiv->state = OTG_STATE_A_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL; musb->g.is_a_peripheral = 1; } diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 855793d..23d474d 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2463,7 +2463,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd) if (!is_host_active(musb)) return 0; - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: return 0; case OTG_STATE_A_WAIT_VRISE: @@ -2473,7 +2473,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd) */ devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; break; default: break; @@ -2481,7 +2481,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd) if (musb->is_active) { WARNING("trying to suspend as %s while active\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); return -EBUSY; } else return 0; @@ -2678,7 +2678,7 @@ int musb_host_setup(struct musb *musb, int power_budget) MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; otg_set_host(musb->xceiv->otg, &hcd->self); hcd->self.otg_port = 1; diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index e2d2d8c..a133bd8c 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -69,7 +69,7 @@ void musb_host_finish_resume(struct work_struct *work) musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; usb_hcd_poll_rh_status(musb->hcd); /* NOTE: it might really be A_WAIT_BCON ... */ - musb->xceiv->state = OTG_STATE_A_HOST; + musb->xceiv->otg->state = OTG_STATE_A_HOST; spin_unlock_irqrestore(&musb->lock, flags); } @@ -107,9 +107,9 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) dev_dbg(musb->controller, "Root port suspended, power %02x\n", power); musb->port1_status |= USB_PORT_STAT_SUSPEND; - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_HOST: - musb->xceiv->state = OTG_STATE_A_SUSPEND; + musb->xceiv->otg->state = OTG_STATE_A_SUSPEND; musb->is_active = otg->host->b_hnp_enable; if (musb->is_active) mod_timer(&musb->otg_timer, jiffies @@ -118,13 +118,13 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) musb_platform_try_idle(musb, 0); break; case OTG_STATE_B_HOST: - musb->xceiv->state = OTG_STATE_B_WAIT_ACON; + musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON; musb->is_active = otg->host->b_hnp_enable; musb_platform_try_idle(musb, 0); break; default: dev_dbg(musb->controller, "bogus rh suspend? %s\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } } else if (power & MUSB_POWER_SUSPENDM) { power &= ~MUSB_POWER_SUSPENDM; @@ -145,7 +145,7 @@ void musb_port_reset(struct musb *musb, bool do_reset) u8 power; void __iomem *mbase = musb->mregs; - if (musb->xceiv->state == OTG_STATE_B_IDLE) { + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) { dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n"); musb->port1_status &= ~USB_PORT_STAT_RESET; return; @@ -224,24 +224,24 @@ void musb_root_disconnect(struct musb *musb) usb_hcd_poll_rh_status(musb->hcd); musb->is_active = 0; - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: if (otg->host->b_hnp_enable) { - musb->xceiv->state = OTG_STATE_A_PERIPHERAL; + musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL; musb->g.is_a_peripheral = 1; break; } /* FALLTHROUGH */ case OTG_STATE_A_HOST: - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; musb->is_active = 0; break; case OTG_STATE_A_WAIT_VFALL: - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; break; default: dev_dbg(musb->controller, "host disconnect (%s)\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } } diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 20fc2a5..763649e 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -65,15 +65,15 @@ static void musb_do_idle(unsigned long _musb) spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_BCON: devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } break; @@ -90,15 +90,15 @@ static void musb_do_idle(unsigned long _musb) musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; usb_hcd_poll_rh_status(musb->hcd); /* NOTE: it might really be A_WAIT_BCON ... */ - musb->xceiv->state = OTG_STATE_A_HOST; + musb->xceiv->otg->state = OTG_STATE_A_HOST; } break; case OTG_STATE_A_HOST: devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; else - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; default: break; } @@ -116,9 +116,9 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || ((musb->a_wait_bcon == 0) - && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { + && (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) { dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); del_timer(&musb_idle_timer); last_timer = jiffies; return; @@ -135,7 +135,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), (unsigned long)jiffies_to_msecs(timeout - jiffies)); mod_timer(&musb_idle_timer, timeout); } @@ -153,7 +153,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { - if (musb->xceiv->state == OTG_STATE_A_IDLE) { + if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) { int loops = 100; /* start the session */ devctl |= MUSB_DEVCTL_SESSION; @@ -180,7 +180,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) } else { musb->is_active = 1; otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; MUSB_HST_MODE(musb); } @@ -192,7 +192,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) */ otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; devctl &= ~MUSB_DEVCTL_SESSION; MUSB_DEV_MODE(musb); @@ -201,7 +201,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) dev_dbg(musb->controller, "VBUS %s, devctl %02x " /* otg %3x conf %08x prcm %08x */ "\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), musb_readb(musb->mregs, MUSB_DEVCTL)); } @@ -266,7 +266,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) dev_dbg(dev, "ID GND\n"); otg->default_a = true; - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; musb->xceiv->last_event = USB_EVENT_ID; if (musb->gadget_driver) { pm_runtime_get_sync(dev); @@ -280,7 +280,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) dev_dbg(dev, "VBUS Connect\n"); otg->default_a = false; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; musb->xceiv->last_event = USB_EVENT_VBUS; if (musb->gadget_driver) pm_runtime_get_sync(dev); diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 25f02df..69ca92d6 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -415,13 +415,13 @@ static void musb_do_idle(unsigned long _musb) spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_BCON: if ((musb->a_wait_bcon != 0) && (musb->idle_timeout == 0 || time_after(jiffies, musb->idle_timeout))) { dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); } /* FALLTHROUGH */ case OTG_STATE_A_IDLE: @@ -474,9 +474,9 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || ((musb->a_wait_bcon == 0) - && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { + && (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) { dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->otg->state)); del_timer(&musb_idle_timer); last_timer = jiffies; return; @@ -493,7 +493,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), (unsigned long)jiffies_to_msecs(timeout - jiffies)); mod_timer(&musb_idle_timer, timeout); } @@ -524,7 +524,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on) if (is_on) { timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE); otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; conf |= TUSB_DEV_CONF_USB_HOST_MODE; @@ -537,16 +537,16 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on) /* If ID pin is grounded, we want to be a_idle */ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) { - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_VRISE: case OTG_STATE_A_WAIT_BCON: - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; break; case OTG_STATE_A_WAIT_VFALL: - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; break; default: - musb->xceiv->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; } musb->is_active = 0; otg->default_a = 1; @@ -554,7 +554,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on) } else { musb->is_active = 0; otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } @@ -569,7 +569,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on) musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), musb_readb(musb->mregs, MUSB_DEVCTL), musb_readl(tbase, TUSB_DEV_OTG_STAT), conf, prcm); @@ -668,23 +668,23 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) { dev_dbg(musb->controller, "Forcing disconnect (no interrupt)\n"); - if (musb->xceiv->state != OTG_STATE_B_IDLE) { + if (musb->xceiv->otg->state != OTG_STATE_B_IDLE) { /* INTR_DISCONNECT can hide... */ - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; musb->int_usb |= MUSB_INTR_DISCONNECT; } musb->is_active = 0; } dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", - usb_otg_state_string(musb->xceiv->state), otg_stat); + usb_otg_state_string(musb->xceiv->otg->state), otg_stat); idle_timeout = jiffies + (1 * HZ); schedule_work(&musb->irq_work); } else /* A-dev state machine */ { dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", - usb_otg_state_string(musb->xceiv->state), otg_stat); + usb_otg_state_string(musb->xceiv->otg->state), otg_stat); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_IDLE: dev_dbg(musb->controller, "Got SRP, turning on VBUS\n"); musb_platform_set_vbus(musb, 1); @@ -731,9 +731,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) u8 devctl; dev_dbg(musb->controller, "%s timer, %03x\n", - usb_otg_state_string(musb->xceiv->state), otg_stat); + usb_otg_state_string(musb->xceiv->otg->state), otg_stat); - switch (musb->xceiv->state) { + switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_VRISE: /* VBUS has probably been valid for a while now, * but may well have bounced out of range a bit @@ -745,7 +745,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) dev_dbg(musb->controller, "devctl %02x\n", devctl); break; } - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; musb->is_active = 0; idle_timeout = jiffies + msecs_to_jiffies(musb->a_wait_bcon); diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index d0180a7..1d631d5 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -56,7 +56,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { - if (musb->xceiv->state == OTG_STATE_A_IDLE) { + if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) { /* start the session */ devctl |= MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); @@ -76,7 +76,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) } else { musb->is_active = 1; musb->xceiv->otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; MUSB_HST_MODE(musb); } @@ -102,7 +102,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) mdelay(200); dev_dbg(musb->controller, "VBUS %s, devctl %02x\n", - usb_otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->otg->state), musb_readb(musb->mregs, MUSB_DEVCTL)); } @@ -112,7 +112,7 @@ static int musb_otg_notifications(struct notifier_block *nb, struct musb *musb = container_of(nb, struct musb, nb); dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n", - event, usb_otg_state_string(musb->xceiv->state)); + event, usb_otg_state_string(musb->xceiv->otg->state)); switch (event) { case UX500_MUSB_ID: @@ -127,7 +127,7 @@ static int musb_otg_notifications(struct notifier_block *nb, if (is_host_active(musb)) ux500_musb_set_vbus(musb, 0); else - musb->xceiv->state = OTG_STATE_B_IDLE; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; break; default: dev_dbg(musb->controller, "ID float\n"); diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 11ab2c4..2d52501 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -446,7 +446,7 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab, if (event != UX500_MUSB_RIDB) event = UX500_MUSB_NONE; /* Fallback to default B_IDLE as nothing is connected. */ - ab->phy.state = OTG_STATE_B_IDLE; + ab->phy.otg->state = OTG_STATE_B_IDLE; break; case USB_LINK_ACA_RID_C_NM_9540: @@ -584,7 +584,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab, * Fallback to default B_IDLE as nothing * is connected */ - ab->phy.state = OTG_STATE_B_IDLE; + ab->phy.otg->state = OTG_STATE_B_IDLE; break; case USB_LINK_ACA_RID_C_NM_8540: @@ -693,7 +693,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab, * Fallback to default B_IDLE as nothing * is connected */ - ab->phy.state = OTG_STATE_B_IDLE; + ab->phy.otg->state = OTG_STATE_B_IDLE; break; case USB_LINK_ACA_RID_C_NM_8505: @@ -776,7 +776,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, if (event != UX500_MUSB_RIDB) event = UX500_MUSB_NONE; /* Fallback to default B_IDLE as nothing is connected */ - ab->phy.state = OTG_STATE_B_IDLE; + ab->phy.otg->state = OTG_STATE_B_IDLE; break; case USB_LINK_ACA_RID_C_NM_8500: @@ -1380,7 +1380,7 @@ static int ab8500_usb_probe(struct platform_device *pdev) ab->phy.label = "ab8500"; ab->phy.set_suspend = ab8500_usb_set_suspend; ab->phy.set_power = ab8500_usb_set_power; - ab->phy.state = OTG_STATE_UNDEFINED; + ab->phy.otg->state = OTG_STATE_UNDEFINED; otg->phy = &ab->phy; otg->set_host = ab8500_usb_set_host; diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index f1ea599..15d7a81 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -623,7 +623,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host) /* Mini-A cable connected */ struct otg_fsm *fsm = &otg_dev->fsm; - otg->phy->state = OTG_STATE_UNDEFINED; + otg.state = OTG_STATE_UNDEFINED; fsm->protocol = PROTO_UNDEF; } } @@ -681,7 +681,7 @@ static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA) { if (!fsl_otg_dev) return -ENODEV; - if (phy->state == OTG_STATE_B_PERIPHERAL) + if (phy->otg.state == OTG_STATE_B_PERIPHERAL) pr_info("FSL OTG: Draw %d mA\n", mA); return 0; @@ -714,7 +714,7 @@ static int fsl_otg_start_srp(struct usb_otg *otg) { struct fsl_otg *otg_dev; - if (!otg || otg->phy->state != OTG_STATE_B_IDLE) + if (!otg || otg.state != OTG_STATE_B_IDLE) return -ENODEV; otg_dev = container_of(otg->phy, struct fsl_otg, phy); @@ -989,10 +989,10 @@ int usb_otg_start(struct platform_device *pdev) * Also: record initial state of ID pin */ if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) { - p_otg->phy.state = OTG_STATE_UNDEFINED; + p_otg->phy->otg.state = OTG_STATE_UNDEFINED; p_otg->fsm.id = 1; } else { - p_otg->phy.state = OTG_STATE_A_IDLE; + p_otg->phy->otg.state = OTG_STATE_A_IDLE; p_otg->fsm.id = 0; } diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 7594e50..280a345 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -123,7 +123,7 @@ static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) } otg->gadget = gadget; - otg->phy->state = OTG_STATE_B_IDLE; + otg->state = OTG_STATE_B_IDLE; return 0; } @@ -225,9 +225,9 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, nop->phy.dev = nop->dev; nop->phy.label = "nop-xceiv"; nop->phy.set_suspend = nop_set_suspend; - nop->phy.state = OTG_STATE_UNDEFINED; nop->phy.type = type; + nop->phy.otg->state = OTG_STATE_UNDEFINED; nop->phy.otg->phy = &nop->phy; nop->phy.otg->set_host = nop_set_host; nop->phy.otg->set_peripheral = nop_set_peripheral; diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index f4b14bd..7a6be3e 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -121,7 +121,7 @@ static void gpio_vbus_work(struct work_struct *work) if (vbus) { status = USB_EVENT_VBUS; - gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL; + gpio_vbus->phy.otg->state = OTG_STATE_B_PERIPHERAL; gpio_vbus->phy.last_event = status; usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget); @@ -143,7 +143,7 @@ static void gpio_vbus_work(struct work_struct *work) usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget); status = USB_EVENT_NONE; - gpio_vbus->phy.state = OTG_STATE_B_IDLE; + gpio_vbus->phy.otg->state = OTG_STATE_B_IDLE; gpio_vbus->phy.last_event = status; atomic_notifier_call_chain(&gpio_vbus->phy.notifier, @@ -196,7 +196,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, set_vbus_draw(gpio_vbus, 0); usb_gadget_vbus_disconnect(otg->gadget); - otg->phy->state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; otg->gadget = NULL; return 0; @@ -218,7 +218,7 @@ static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA) gpio_vbus = container_of(phy, struct gpio_vbus_data, phy); - if (phy->state == OTG_STATE_B_PERIPHERAL) + if (phy->otg->state == OTG_STATE_B_PERIPHERAL) set_vbus_draw(gpio_vbus, mA); return 0; } @@ -269,8 +269,8 @@ static int gpio_vbus_probe(struct platform_device *pdev) gpio_vbus->phy.dev = gpio_vbus->dev; gpio_vbus->phy.set_power = gpio_vbus_set_power; gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend; - gpio_vbus->phy.state = OTG_STATE_UNDEFINED; + gpio_vbus->phy.otg->state = OTG_STATE_UNDEFINED; gpio_vbus->phy.otg->phy = &gpio_vbus->phy; gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral; diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 8eea56d..24f84cb 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -234,7 +234,7 @@ isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) static inline const char *state_name(struct isp1301 *isp) { - return usb_otg_state_string(isp->phy.state); + return usb_otg_state_string(isp->phy.otg->state); } /*-------------------------------------------------------------------------*/ @@ -249,7 +249,7 @@ static inline const char *state_name(struct isp1301 *isp) static void power_down(struct isp1301 *isp) { - isp->phy.state = OTG_STATE_UNDEFINED; + isp->phy.otg->state = OTG_STATE_UNDEFINED; // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND); @@ -339,7 +339,7 @@ static void a_idle(struct isp1301 *isp, const char *tag) { u32 l; - if (isp->phy.state == OTG_STATE_A_IDLE) + if (isp->phy.otg->state == OTG_STATE_A_IDLE) return; isp->phy.otg->default_a = 1; @@ -351,7 +351,7 @@ static void a_idle(struct isp1301 *isp, const char *tag) isp->phy.otg->gadget->is_a_peripheral = 1; gadget_suspend(isp); } - isp->phy.state = OTG_STATE_A_IDLE; + isp->phy.otg->state = OTG_STATE_A_IDLE; l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; omap_writel(l, OTG_CTRL); isp->last_otg_ctrl = l; @@ -363,7 +363,7 @@ static void b_idle(struct isp1301 *isp, const char *tag) { u32 l; - if (isp->phy.state == OTG_STATE_B_IDLE) + if (isp->phy.otg->state == OTG_STATE_B_IDLE) return; isp->phy.otg->default_a = 0; @@ -375,7 +375,7 @@ static void b_idle(struct isp1301 *isp, const char *tag) isp->phy.otg->gadget->is_a_peripheral = 0; gadget_suspend(isp); } - isp->phy.state = OTG_STATE_B_IDLE; + isp->phy.otg->state = OTG_STATE_B_IDLE; l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; omap_writel(l, OTG_CTRL); isp->last_otg_ctrl = l; @@ -474,7 +474,7 @@ static void check_state(struct isp1301 *isp, const char *tag) default: break; } - if (isp->phy.state == state && !extra) + if (isp->phy.otg->state == state && !extra) return; pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, usb_otg_state_string(state), fsm, state_name(isp), @@ -498,23 +498,23 @@ static void update_otg1(struct isp1301 *isp, u8 int_src) if (int_src & INTR_SESS_VLD) otg_ctrl |= OTG_ASESSVLD; - else if (isp->phy.state == OTG_STATE_A_WAIT_VFALL) { + else if (isp->phy.otg->state == OTG_STATE_A_WAIT_VFALL) { a_idle(isp, "vfall"); otg_ctrl &= ~OTG_CTRL_BITS; } if (int_src & INTR_VBUS_VLD) otg_ctrl |= OTG_VBUSVLD; if (int_src & INTR_ID_GND) { /* default-A */ - if (isp->phy.state == OTG_STATE_B_IDLE - || isp->phy.state + if (isp->phy.otg->state == OTG_STATE_B_IDLE + || isp->phy.otg->state == OTG_STATE_UNDEFINED) { a_idle(isp, "init"); return; } } else { /* default-B */ otg_ctrl |= OTG_ID; - if (isp->phy.state == OTG_STATE_A_IDLE - || isp->phy.state == OTG_STATE_UNDEFINED) { + if (isp->phy.otg->state == OTG_STATE_A_IDLE + || isp->phy.otg->state == OTG_STATE_UNDEFINED) { b_idle(isp, "init"); return; } @@ -548,14 +548,14 @@ static void otg_update_isp(struct isp1301 *isp) isp->last_otg_ctrl = otg_ctrl; otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS; - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_B_IDLE: case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_SRP_INIT: if (!(otg_ctrl & OTG_PULLUP)) { // if (otg_ctrl & OTG_B_HNPEN) { if (isp->phy.otg->gadget->b_hnp_enable) { - isp->phy.state = OTG_STATE_B_WAIT_ACON; + isp->phy.otg->state = OTG_STATE_B_WAIT_ACON; pr_debug(" --> b_wait_acon\n"); } goto pulldown; @@ -585,7 +585,7 @@ pulldown: if (!(isp->phy.otg->host)) otg_ctrl &= ~OTG_DRV_VBUS; - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_A_SUSPEND: if (otg_ctrl & OTG_DRV_VBUS) { set |= OTG1_VBUS_DRV; @@ -596,7 +596,7 @@ pulldown: /* FALLTHROUGH */ case OTG_STATE_A_VBUS_ERR: - isp->phy.state = OTG_STATE_A_WAIT_VFALL; + isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL; pr_debug(" --> a_wait_vfall\n"); /* FALLTHROUGH */ case OTG_STATE_A_WAIT_VFALL: @@ -605,7 +605,7 @@ pulldown: break; case OTG_STATE_A_IDLE: if (otg_ctrl & OTG_DRV_VBUS) { - isp->phy.state = OTG_STATE_A_WAIT_VRISE; + isp->phy.otg->state = OTG_STATE_A_WAIT_VRISE; pr_debug(" --> a_wait_vrise\n"); } /* FALLTHROUGH */ @@ -625,17 +625,17 @@ pulldown: if (otg_change & OTG_PULLUP) { u32 l; - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_B_IDLE: if (clr & OTG1_DP_PULLUP) break; - isp->phy.state = OTG_STATE_B_PERIPHERAL; + isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; pr_debug(" --> b_peripheral\n"); break; case OTG_STATE_A_SUSPEND: if (clr & OTG1_DP_PULLUP) break; - isp->phy.state = OTG_STATE_A_PERIPHERAL; + isp->phy.otg->state = OTG_STATE_A_PERIPHERAL; pr_debug(" --> a_peripheral\n"); break; default: @@ -673,7 +673,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) * remote wakeup (SRP, normal) using their own timer * to give "check cable and A-device" messages. */ - if (isp->phy.state == OTG_STATE_B_SRP_INIT) + if (isp->phy.otg->state == OTG_STATE_B_SRP_INIT) b_idle(isp, "srp_timeout"); omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC); @@ -691,7 +691,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) omap_writel(otg_ctrl, OTG_CTRL); /* subset of b_peripheral()... */ - isp->phy.state = OTG_STATE_B_PERIPHERAL; + isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; pr_debug(" --> b_peripheral\n"); omap_writew(B_HNP_FAIL, OTG_IRQ_SRC); @@ -703,7 +703,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) state_name(isp), omap_readl(OTG_CTRL)); isp1301_defer_work(isp, WORK_UPDATE_OTG); - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_A_IDLE: if (!otg->host) break; @@ -734,7 +734,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) otg_ctrl |= OTG_BUSDROP; otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.state = OTG_STATE_A_WAIT_VFALL; + isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL; omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC); ret = IRQ_HANDLED; @@ -748,7 +748,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) otg_ctrl |= OTG_BUSDROP; otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.state = OTG_STATE_A_VBUS_ERR; + isp->phy.otg->state = OTG_STATE_A_VBUS_ERR; omap_writew(A_VBUS_ERR, OTG_IRQ_SRC); ret = IRQ_HANDLED; @@ -769,7 +769,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) /* role is peripheral */ if (otg_ctrl & OTG_DRIVER_SEL) { - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_A_IDLE: b_idle(isp, __func__); break; @@ -786,18 +786,18 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) } if (otg->host) { - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_B_WAIT_ACON: - isp->phy.state = OTG_STATE_B_HOST; + isp->phy.otg->state = OTG_STATE_B_HOST; pr_debug(" --> b_host\n"); kick = 1; break; case OTG_STATE_A_WAIT_BCON: - isp->phy.state = OTG_STATE_A_HOST; + isp->phy.otg->state = OTG_STATE_A_HOST; pr_debug(" --> a_host\n"); break; case OTG_STATE_A_PERIPHERAL: - isp->phy.state = OTG_STATE_A_WAIT_BCON; + isp->phy.otg->state = OTG_STATE_A_WAIT_BCON; pr_debug(" --> a_wait_bcon\n"); break; default: @@ -937,7 +937,7 @@ static void b_peripheral(struct isp1301 *isp) /* UDC driver just set OTG_BSESSVLD */ isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); - isp->phy.state = OTG_STATE_B_PERIPHERAL; + isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; pr_debug(" --> b_peripheral\n"); dump_regs(isp, "2periph"); #endif @@ -947,7 +947,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) { struct usb_otg *otg = isp->phy.otg; u8 isp_stat, isp_bstat; - enum usb_otg_state state = isp->phy.state; + enum usb_otg_state state = isp->phy.otg->state; if (stat & INTR_BDIS_ACON) pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp)); @@ -970,7 +970,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) * when HNP is used. */ if (isp_stat & INTR_VBUS_VLD) - isp->phy.state = OTG_STATE_A_HOST; + isp->phy.otg->state = OTG_STATE_A_HOST; break; case OTG_STATE_A_WAIT_VFALL: if (!(isp_stat & INTR_SESS_VLD)) @@ -978,7 +978,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) break; default: if (!(isp_stat & INTR_VBUS_VLD)) - isp->phy.state = OTG_STATE_A_VBUS_ERR; + isp->phy.otg->state = OTG_STATE_A_VBUS_ERR; break; } isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); @@ -1007,7 +1007,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) if (otg->default_a) { switch (state) { default: - isp->phy.state = OTG_STATE_A_WAIT_VFALL; + isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL; break; case OTG_STATE_A_WAIT_VFALL: state = OTG_STATE_A_IDLE; @@ -1020,7 +1020,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) host_suspend(isp); isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_BDIS_ACON_EN); - isp->phy.state = OTG_STATE_B_IDLE; + isp->phy.otg->state = OTG_STATE_B_IDLE; l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; l &= ~OTG_CTRL_BITS; omap_writel(l, OTG_CTRL); @@ -1031,7 +1031,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) } isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_HOST: @@ -1071,7 +1071,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) } } - if (state != isp->phy.state) + if (state != isp->phy.otg->state) pr_debug(" isp, %s -> %s\n", usb_otg_state_string(state), state_name(isp)); @@ -1129,10 +1129,10 @@ isp1301_work(struct work_struct *work) * skip A_WAIT_VRISE; hc transitions invisibly * skip A_WAIT_BCON; same. */ - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_A_WAIT_BCON: case OTG_STATE_A_WAIT_VRISE: - isp->phy.state = OTG_STATE_A_HOST; + isp->phy.otg->state = OTG_STATE_A_HOST; pr_debug(" --> a_host\n"); otg_ctrl = omap_readl(OTG_CTRL); otg_ctrl |= OTG_A_BUSREQ; @@ -1141,7 +1141,7 @@ isp1301_work(struct work_struct *work) omap_writel(otg_ctrl, OTG_CTRL); break; case OTG_STATE_B_WAIT_ACON: - isp->phy.state = OTG_STATE_B_HOST; + isp->phy.otg->state = OTG_STATE_B_HOST; pr_debug(" --> b_host (acon)\n"); break; case OTG_STATE_B_HOST: @@ -1368,7 +1368,7 @@ isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) } power_up(isp); - isp->phy.state = OTG_STATE_B_IDLE; + isp->phy.otg->state = OTG_STATE_B_IDLE; if (machine_is_omap_h2() || machine_is_omap_h3()) isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); @@ -1403,7 +1403,7 @@ isp1301_set_power(struct usb_phy *dev, unsigned mA) { if (!the_transceiver) return -ENODEV; - if (dev->state == OTG_STATE_B_PERIPHERAL) + if (dev->otg->state == OTG_STATE_B_PERIPHERAL) enable_vbus_draw(the_transceiver, mA); return 0; } @@ -1414,7 +1414,7 @@ isp1301_start_srp(struct usb_otg *otg) struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); u32 otg_ctrl; - if (isp != the_transceiver || isp->phy.state != OTG_STATE_B_IDLE) + if (isp != the_transceiver || isp->phy.otg->state != OTG_STATE_B_IDLE) return -ENODEV; otg_ctrl = omap_readl(OTG_CTRL); @@ -1424,7 +1424,7 @@ isp1301_start_srp(struct usb_otg *otg) otg_ctrl |= OTG_B_BUSREQ; otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.state = OTG_STATE_B_SRP_INIT; + isp->phy.otg->state = OTG_STATE_B_SRP_INIT; pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), omap_readl(OTG_CTRL)); @@ -1452,9 +1452,9 @@ isp1301_start_hnp(struct usb_otg *otg) /* We want hardware to manage most HNP protocol timings. * So do this part as early as possible... */ - switch (isp->phy.state) { + switch (isp->phy.otg->state) { case OTG_STATE_B_HOST: - isp->phy.state = OTG_STATE_B_PERIPHERAL; + isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; /* caller will suspend next */ break; case OTG_STATE_A_HOST: diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 471e69d..18015b7 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -721,11 +721,11 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) } if (!host) { - if (otg->phy->state == OTG_STATE_A_HOST) { + if (otg->state == OTG_STATE_A_HOST) { pm_runtime_get_sync(otg->phy->dev); msm_otg_start_host(otg->phy, 0); otg->host = NULL; - otg->phy->state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; schedule_work(&motg->sm_work); } else { otg->host = NULL; @@ -794,11 +794,11 @@ static int msm_otg_set_peripheral(struct usb_otg *otg, } if (!gadget) { - if (otg->phy->state == OTG_STATE_B_PERIPHERAL) { + if (otg->state == OTG_STATE_B_PERIPHERAL) { pm_runtime_get_sync(otg->phy->dev); msm_otg_start_peripheral(otg->phy, 0); otg->gadget = NULL; - otg->phy->state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; schedule_work(&motg->sm_work); } else { otg->gadget = NULL; @@ -1170,12 +1170,12 @@ static void msm_otg_sm_work(struct work_struct *w) struct msm_otg *motg = container_of(w, struct msm_otg, sm_work); struct usb_otg *otg = motg->phy.otg; - switch (otg->phy->state) { + switch (otg->state) { case OTG_STATE_UNDEFINED: dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n"); msm_otg_reset(otg->phy); msm_otg_init_sm(motg); - otg->phy->state = OTG_STATE_B_IDLE; + otg->state = OTG_STATE_B_IDLE; /* FALL THROUGH */ case OTG_STATE_B_IDLE: dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n"); @@ -1183,7 +1183,7 @@ static void msm_otg_sm_work(struct work_struct *w) /* disable BSV bit */ writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); msm_otg_start_host(otg->phy, 1); - otg->phy->state = OTG_STATE_A_HOST; + otg->state = OTG_STATE_A_HOST; } else if (test_bit(B_SESS_VLD, &motg->inputs)) { switch (motg->chg_state) { case USB_CHG_STATE_UNDEFINED: @@ -1199,13 +1199,13 @@ static void msm_otg_sm_work(struct work_struct *w) msm_otg_notify_charger(motg, IDEV_CHG_MAX); msm_otg_start_peripheral(otg->phy, 1); - otg->phy->state + otg->state = OTG_STATE_B_PERIPHERAL; break; case USB_SDP_CHARGER: msm_otg_notify_charger(motg, IUNIT); msm_otg_start_peripheral(otg->phy, 1); - otg->phy->state + otg->state = OTG_STATE_B_PERIPHERAL; break; default: @@ -1230,7 +1230,7 @@ static void msm_otg_sm_work(struct work_struct *w) motg->chg_type = USB_INVALID_CHARGER; } - if (otg->phy->state == OTG_STATE_B_IDLE) + if (otg->state == OTG_STATE_B_IDLE) pm_runtime_put_sync(otg->phy->dev); break; case OTG_STATE_B_PERIPHERAL: @@ -1241,7 +1241,7 @@ static void msm_otg_sm_work(struct work_struct *w) msm_otg_start_peripheral(otg->phy, 0); motg->chg_state = USB_CHG_STATE_UNDEFINED; motg->chg_type = USB_INVALID_CHARGER; - otg->phy->state = OTG_STATE_B_IDLE; + otg->state = OTG_STATE_B_IDLE; msm_otg_reset(otg->phy); schedule_work(w); } @@ -1250,7 +1250,7 @@ static void msm_otg_sm_work(struct work_struct *w) dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n"); if (test_bit(ID, &motg->inputs)) { msm_otg_start_host(otg->phy, 0); - otg->phy->state = OTG_STATE_B_IDLE; + otg->state = OTG_STATE_B_IDLE; msm_otg_reset(otg->phy); schedule_work(w); } @@ -1303,7 +1303,7 @@ static int msm_otg_mode_show(struct seq_file *s, void *unused) struct msm_otg *motg = s->private; struct usb_otg *otg = motg->phy.otg; - switch (otg->phy->state) { + switch (otg->state) { case OTG_STATE_A_HOST: seq_puts(s, "host\n"); break; @@ -1353,7 +1353,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, switch (req_mode) { case USB_DR_MODE_UNKNOWN: - switch (otg->phy->state) { + switch (otg->state) { case OTG_STATE_A_HOST: case OTG_STATE_B_PERIPHERAL: set_bit(ID, &motg->inputs); @@ -1364,7 +1364,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, } break; case USB_DR_MODE_PERIPHERAL: - switch (otg->phy->state) { + switch (otg->state) { case OTG_STATE_B_IDLE: case OTG_STATE_A_HOST: set_bit(ID, &motg->inputs); @@ -1375,7 +1375,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, } break; case USB_DR_MODE_HOST: - switch (otg->phy->state) { + switch (otg->state) { case OTG_STATE_B_IDLE: case OTG_STATE_B_PERIPHERAL: clear_bit(ID, &motg->inputs); @@ -1769,7 +1769,7 @@ static int msm_otg_runtime_idle(struct device *dev) * This 1 sec delay also prevents entering into LPM immediately * after asynchronous interrupt. */ - if (otg->phy->state != OTG_STATE_UNDEFINED) + if (otg->state != OTG_STATE_UNDEFINED) pm_schedule_suspend(dev, 1000); return -EAGAIN; diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index c9517d8..ee87aa7 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -339,68 +339,68 @@ static void mv_otg_update_state(struct mv_otg *mvotg) { struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; struct usb_phy *phy = &mvotg->phy; - int old_state = phy->state; + int old_state = mvotg->phy.otg->state; switch (old_state) { case OTG_STATE_UNDEFINED: - phy->state = OTG_STATE_B_IDLE; + mvotg->phy.otg->state = OTG_STATE_B_IDLE; /* FALL THROUGH */ case OTG_STATE_B_IDLE: if (otg_ctrl->id == 0) - phy->state = OTG_STATE_A_IDLE; + mvotg->phy.otg->state = OTG_STATE_A_IDLE; else if (otg_ctrl->b_sess_vld) - phy->state = OTG_STATE_B_PERIPHERAL; + mvotg->phy.otg->state = OTG_STATE_B_PERIPHERAL; break; case OTG_STATE_B_PERIPHERAL: if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0) - phy->state = OTG_STATE_B_IDLE; + mvotg->phy.otg->state = OTG_STATE_B_IDLE; break; case OTG_STATE_A_IDLE: if (otg_ctrl->id) - phy->state = OTG_STATE_B_IDLE; + mvotg->phy.otg->state = OTG_STATE_B_IDLE; else if (!(otg_ctrl->a_bus_drop) && (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det)) - phy->state = OTG_STATE_A_WAIT_VRISE; + mvotg->phy.otg->state = OTG_STATE_A_WAIT_VRISE; break; case OTG_STATE_A_WAIT_VRISE: if (otg_ctrl->a_vbus_vld) - phy->state = OTG_STATE_A_WAIT_BCON; + mvotg->phy.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; - phy->state = OTG_STATE_A_WAIT_VFALL; + mvotg->phy.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; - phy->state = OTG_STATE_A_VBUS_ERR; + mvotg->phy.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; - phy->state = OTG_STATE_A_HOST; + mvotg->phy.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) - phy->state = OTG_STATE_A_WAIT_BCON; + mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON; else if (!otg_ctrl->a_vbus_vld) - phy->state = OTG_STATE_A_VBUS_ERR; + mvotg->phy.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) - phy->state = OTG_STATE_A_IDLE; + mvotg->phy.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; - phy->state = OTG_STATE_A_WAIT_VFALL; + mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL; } break; default: @@ -420,8 +420,8 @@ static void mv_otg_work(struct work_struct *work) run: /* work queue is single thread, or we need spin_lock to protect */ phy = &mvotg->phy; - otg = phy->otg; - old_state = phy->state; + otg = mvotg->phy.otg; + old_state = otg->state; if (!mvotg->active) return; @@ -429,12 +429,12 @@ run: mv_otg_update_inputs(mvotg); mv_otg_update_state(mvotg); - if (old_state != phy->state) { + if (old_state != mvotg->phy.otg->state) { dev_info(&mvotg->pdev->dev, "change from state %s to %s\n", state_string[old_state], - state_string[phy->state]); + state_string[mvotg->phy.otg->state]); - switch (phy->state) { + switch (mvotg->phy.otg->state) { case OTG_STATE_B_IDLE: otg->default_a = 0; if (old_state == OTG_STATE_B_PERIPHERAL) @@ -545,8 +545,8 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr, return -1; /* We will use this interface to change to A device */ - if (mvotg->phy.state != OTG_STATE_B_IDLE - && mvotg->phy.state != OTG_STATE_A_IDLE) + if (mvotg->phy.otg->state != OTG_STATE_B_IDLE + && mvotg->phy.otg->state != OTG_STATE_A_IDLE) return -1; /* The clock may disabled and we need to set irq for ID detected */ @@ -715,9 +715,9 @@ static int mv_otg_probe(struct platform_device *pdev) mvotg->phy.dev = &pdev->dev; mvotg->phy.otg = otg; mvotg->phy.label = driver_name; - mvotg->phy.state = OTG_STATE_UNDEFINED; otg->phy = &mvotg->phy; + otg->state = OTG_STATE_UNDEFINED; otg->set_host = mv_otg_set_host; otg->set_peripheral = mv_otg_set_peripheral; otg->set_vbus = mv_otg_set_vbus; diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index cc61ee4..04ece53 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -81,33 +81,33 @@ static void check_vbus_state(struct tahvo_usb *tu) reg = retu_read(rdev, TAHVO_REG_IDSR); if (reg & TAHVO_STAT_VBUS) { - switch (tu->phy.state) { + switch (tu->phy.otg->state) { case OTG_STATE_B_IDLE: /* Enable the gadget driver */ if (tu->phy.otg->gadget) usb_gadget_vbus_connect(tu->phy.otg->gadget); - tu->phy.state = OTG_STATE_B_PERIPHERAL; + tu->phy.otg->state = OTG_STATE_B_PERIPHERAL; break; case OTG_STATE_A_IDLE: /* * Session is now valid assuming the USB hub is driving * Vbus. */ - tu->phy.state = OTG_STATE_A_HOST; + tu->phy.otg->state = OTG_STATE_A_HOST; break; default: break; } dev_info(&tu->pt_dev->dev, "USB cable connected\n"); } else { - switch (tu->phy.state) { + switch (tu->phy.otg->state) { case OTG_STATE_B_PERIPHERAL: if (tu->phy.otg->gadget) usb_gadget_vbus_disconnect(tu->phy.otg->gadget); - tu->phy.state = OTG_STATE_B_IDLE; + tu->phy.otg->state = OTG_STATE_B_IDLE; break; case OTG_STATE_A_HOST: - tu->phy.state = OTG_STATE_A_IDLE; + tu->phy.otg->state = OTG_STATE_A_IDLE; break; default: break; @@ -132,14 +132,14 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu) /* Power up the transceiver in USB host mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | USBR_MASTER_SW2 | USBR_MASTER_SW1); - tu->phy.state = OTG_STATE_A_IDLE; + tu->phy.otg->state = OTG_STATE_A_IDLE; check_vbus_state(tu); } static void tahvo_usb_stop_host(struct tahvo_usb *tu) { - tu->phy.state = OTG_STATE_A_IDLE; + tu->phy.otg->state = OTG_STATE_A_IDLE; } static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) @@ -151,7 +151,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) /* Power up transceiver and set it in USB peripheral mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | USBR_NSUSPEND | USBR_SLAVE_SW); - tu->phy.state = OTG_STATE_B_IDLE; + tu->phy.otg->state = OTG_STATE_B_IDLE; check_vbus_state(tu); } @@ -160,7 +160,7 @@ static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu) { if (tu->phy.otg->gadget) usb_gadget_vbus_disconnect(tu->phy.otg->gadget); - tu->phy.state = OTG_STATE_B_IDLE; + tu->phy.otg->state = OTG_STATE_B_IDLE; } static void tahvo_usb_power_off(struct tahvo_usb *tu) @@ -173,7 +173,7 @@ static void tahvo_usb_power_off(struct tahvo_usb *tu) /* Power off transceiver */ retu_write(rdev, TAHVO_REG_USBR, 0); - tu->phy.state = OTG_STATE_UNDEFINED; + tu->phy.otg->state = OTG_STATE_UNDEFINED; } static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend) @@ -379,7 +379,7 @@ static int tahvo_usb_probe(struct platform_device *pdev) /* Create OTG interface */ tahvo_usb_power_off(tu); tu->phy.dev = &pdev->dev; - tu->phy.state = OTG_STATE_UNDEFINED; + tu->phy.otg->state = OTG_STATE_UNDEFINED; tu->phy.label = DRIVER_NAME; tu->phy.set_suspend = tahvo_usb_set_suspend; diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 154332b..33d3480 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -18,6 +18,8 @@ struct usb_otg { struct usb_bus *host; struct usb_gadget *gadget; + enum usb_otg_state state; + /* bind/unbind the host controller */ int (*set_host)(struct usb_otg *otg, struct usb_bus *host); diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 353053a..ac7d791 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -77,7 +77,6 @@ struct usb_phy { unsigned int flags; enum usb_phy_type type; - enum usb_otg_state state; enum usb_phy_events last_event; struct usb_otg *otg; -- cgit v0.10.2 From 19c1eac2685b62640ca2386a0a885ac2152668c8 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 30 Oct 2014 18:41:14 +0100 Subject: usb: rename phy to usb_phy in OTG This patch prepares the introduction of the generic PHY support in the USB OTG common functions. The USB PHY member of the OTG structure is renamed to 'usb_phy' and modifications are done in all drivers accessing it. Renaming this pointer will allow to keep the compatibility for USB PHY drivers. Signed-off-by: Antoine Tenart Signed-off-by: Felipe Balbi diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index 9f409359..32c3e86 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -60,7 +60,7 @@ EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) { - struct omap_usb *phy = phy_to_omapusb(otg->phy); + struct omap_usb *phy = phy_to_omapusb(otg->usb_phy); if (!phy->comparator) return -ENODEV; @@ -70,7 +70,7 @@ static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) static int omap_usb_start_srp(struct usb_otg *otg) { - struct omap_usb *phy = phy_to_omapusb(otg->phy); + struct omap_usb *phy = phy_to_omapusb(otg->usb_phy); if (!phy->comparator) return -ENODEV; @@ -251,7 +251,7 @@ static int omap_usb2_probe(struct platform_device *pdev) otg->set_vbus = omap_usb_set_vbus; if (phy_data->flags & OMAP_USB2_HAS_START_SRP) otg->start_srp = omap_usb_start_srp; - otg->phy = &phy->phy; + otg->usb_phy = &phy->phy; platform_set_drvdata(pdev, phy); diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 8cb2508..d8490e7 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -788,7 +788,7 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) return -ENOMEM; } - otg->phy = ci->transceiver; + otg->usb_phy = ci->transceiver; otg->gadget = &ci->gadget; ci->fsm.otg = otg; ci->transceiver->otg = ci->fsm.otg; diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 2d52501..3a802fa 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -1056,7 +1056,7 @@ static int ab8500_usb_set_peripheral(struct usb_otg *otg, if (!otg) return -ENODEV; - ab = phy_to_ab(otg->phy); + ab = phy_to_ab(otg->usb_phy); ab->phy.otg->gadget = gadget; @@ -1080,7 +1080,7 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) if (!otg) return -ENODEV; - ab = phy_to_ab(otg->phy); + ab = phy_to_ab(otg->usb_phy); ab->phy.otg->host = host; @@ -1382,7 +1382,7 @@ static int ab8500_usb_probe(struct platform_device *pdev) ab->phy.set_power = ab8500_usb_set_power; ab->phy.otg->state = OTG_STATE_UNDEFINED; - otg->phy = &ab->phy; + otg->usb_phy = &ab->phy; otg->set_host = ab8500_usb_set_host; otg->set_peripheral = ab8500_usb_set_peripheral; diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 15d7a81..b7f36b2 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -499,7 +499,8 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on) { struct usb_otg *otg = fsm->otg; struct device *dev; - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); + struct fsl_otg *otg_dev = + container_of(otg->usb_phy, struct fsl_otg, phy); u32 retval = 0; if (!otg->host) @@ -594,7 +595,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host) if (!otg) return -ENODEV; - otg_dev = container_of(otg->phy, struct fsl_otg, phy); + otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy); if (otg_dev != fsl_otg_dev) return -ENODEV; @@ -644,7 +645,7 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg, if (!otg) return -ENODEV; - otg_dev = container_of(otg->phy, struct fsl_otg, phy); + otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy); VDBG("otg_dev 0x%x\n", (int)otg_dev); VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev); if (otg_dev != fsl_otg_dev) @@ -717,7 +718,7 @@ static int fsl_otg_start_srp(struct usb_otg *otg) if (!otg || otg.state != OTG_STATE_B_IDLE) return -ENODEV; - otg_dev = container_of(otg->phy, struct fsl_otg, phy); + otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy); if (otg_dev != fsl_otg_dev) return -ENODEV; @@ -735,7 +736,7 @@ static int fsl_otg_start_hnp(struct usb_otg *otg) if (!otg) return -ENODEV; - otg_dev = container_of(otg->phy, struct fsl_otg, phy); + otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy); if (otg_dev != fsl_otg_dev) return -ENODEV; @@ -857,7 +858,7 @@ static int fsl_otg_conf(struct platform_device *pdev) fsl_otg_tc->phy.dev = &pdev->dev; fsl_otg_tc->phy.set_power = fsl_otg_set_power; - fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy; + fsl_otg_tc->phy.otg->usb_phy = &fsl_otg_tc->phy; fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host; fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral; fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp; diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 280a345..0c01bd1 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -228,7 +228,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, nop->phy.type = type; nop->phy.otg->state = OTG_STATE_UNDEFINED; - nop->phy.otg->phy = &nop->phy; + nop->phy.otg->usb_phy = &nop->phy; nop->phy.otg->set_host = nop_set_host; nop->phy.otg->set_peripheral = nop_set_peripheral; diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 7a6be3e..9fcf19b 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -180,7 +180,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, struct platform_device *pdev; int gpio; - gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy); + gpio_vbus = container_of(otg->usb_phy, struct gpio_vbus_data, phy); pdev = to_platform_device(gpio_vbus->dev); pdata = dev_get_platdata(gpio_vbus->dev); gpio = pdata->gpio_pullup; @@ -271,7 +271,7 @@ static int gpio_vbus_probe(struct platform_device *pdev) gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend; gpio_vbus->phy.otg->state = OTG_STATE_UNDEFINED; - gpio_vbus->phy.otg->phy = &gpio_vbus->phy; + gpio_vbus->phy.otg->usb_phy = &gpio_vbus->phy; gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral; err = devm_gpio_request(&pdev->dev, gpio, "vbus_detect"); diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 24f84cb..a2dfb2a 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -1275,7 +1275,7 @@ static int isp1301_otg_enable(struct isp1301 *isp) static int isp1301_set_host(struct usb_otg *otg, struct usb_bus *host) { - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); + struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); if (isp != the_transceiver) return -ENODEV; @@ -1331,7 +1331,7 @@ isp1301_set_host(struct usb_otg *otg, struct usb_bus *host) static int isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); + struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); if (isp != the_transceiver) return -ENODEV; @@ -1411,7 +1411,7 @@ isp1301_set_power(struct usb_phy *dev, unsigned mA) static int isp1301_start_srp(struct usb_otg *otg) { - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); + struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); u32 otg_ctrl; if (isp != the_transceiver || isp->phy.otg->state != OTG_STATE_B_IDLE) @@ -1438,7 +1438,7 @@ static int isp1301_start_hnp(struct usb_otg *otg) { #ifdef CONFIG_USB_OTG - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); + struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); u32 l; if (isp != the_transceiver) @@ -1583,7 +1583,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id) isp->phy.label = DRIVER_NAME; isp->phy.set_power = isp1301_set_power, - isp->phy.otg->phy = &isp->phy; + isp->phy.otg->usb_phy = &isp->phy; isp->phy.otg->set_host = isp1301_set_host, isp->phy.otg->set_peripheral = isp1301_set_peripheral, isp->phy.otg->start_srp = isp1301_start_srp, diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 18015b7..e120d87 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -708,7 +708,7 @@ static void msm_otg_start_host(struct usb_phy *phy, int on) static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) { - struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy); + struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy); struct usb_hcd *hcd; /* @@ -716,14 +716,14 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) * only peripheral configuration. */ if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) { - dev_info(otg->phy->dev, "Host mode is not supported\n"); + dev_info(otg->usb_phy->dev, "Host mode is not supported\n"); return -ENODEV; } if (!host) { if (otg->state == OTG_STATE_A_HOST) { - pm_runtime_get_sync(otg->phy->dev); - msm_otg_start_host(otg->phy, 0); + pm_runtime_get_sync(otg->usb_phy->dev); + msm_otg_start_host(otg->usb_phy, 0); otg->host = NULL; otg->state = OTG_STATE_UNDEFINED; schedule_work(&motg->sm_work); @@ -738,14 +738,14 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) hcd->power_budget = motg->pdata->power_budget; otg->host = host; - dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n"); + dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n"); /* * Kick the state machine work, if peripheral is not supported * or peripheral is already registered with us. */ if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) { - pm_runtime_get_sync(otg->phy->dev); + pm_runtime_get_sync(otg->usb_phy->dev); schedule_work(&motg->sm_work); } @@ -782,21 +782,21 @@ static void msm_otg_start_peripheral(struct usb_phy *phy, int on) static int msm_otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { - struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy); + struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy); /* * Fail peripheral registration if this board can support * only host configuration. */ if (motg->pdata->mode == USB_DR_MODE_HOST) { - dev_info(otg->phy->dev, "Peripheral mode is not supported\n"); + dev_info(otg->usb_phy->dev, "Peripheral mode is not supported\n"); return -ENODEV; } if (!gadget) { if (otg->state == OTG_STATE_B_PERIPHERAL) { - pm_runtime_get_sync(otg->phy->dev); - msm_otg_start_peripheral(otg->phy, 0); + pm_runtime_get_sync(otg->usb_phy->dev); + msm_otg_start_peripheral(otg->usb_phy, 0); otg->gadget = NULL; otg->state = OTG_STATE_UNDEFINED; schedule_work(&motg->sm_work); @@ -807,14 +807,15 @@ static int msm_otg_set_peripheral(struct usb_otg *otg, return 0; } otg->gadget = gadget; - dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n"); + dev_dbg(otg->usb_phy->dev, + "peripheral driver registered w/ tranceiver\n"); /* * Kick the state machine work, if host is not supported * or host is already registered with us. */ if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) { - pm_runtime_get_sync(otg->phy->dev); + pm_runtime_get_sync(otg->usb_phy->dev); schedule_work(&motg->sm_work); } @@ -1172,17 +1173,17 @@ static void msm_otg_sm_work(struct work_struct *w) switch (otg->state) { case OTG_STATE_UNDEFINED: - dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n"); - msm_otg_reset(otg->phy); + dev_dbg(otg->usb_phy->dev, "OTG_STATE_UNDEFINED state\n"); + msm_otg_reset(otg->usb_phy); msm_otg_init_sm(motg); otg->state = OTG_STATE_B_IDLE; /* FALL THROUGH */ case OTG_STATE_B_IDLE: - dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n"); + dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_IDLE state\n"); if (!test_bit(ID, &motg->inputs) && otg->host) { /* disable BSV bit */ writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); - msm_otg_start_host(otg->phy, 1); + msm_otg_start_host(otg->usb_phy, 1); otg->state = OTG_STATE_A_HOST; } else if (test_bit(B_SESS_VLD, &motg->inputs)) { switch (motg->chg_state) { @@ -1198,13 +1199,15 @@ static void msm_otg_sm_work(struct work_struct *w) case USB_CDP_CHARGER: msm_otg_notify_charger(motg, IDEV_CHG_MAX); - msm_otg_start_peripheral(otg->phy, 1); + msm_otg_start_peripheral(otg->usb_phy, + 1); otg->state = OTG_STATE_B_PERIPHERAL; break; case USB_SDP_CHARGER: msm_otg_notify_charger(motg, IUNIT); - msm_otg_start_peripheral(otg->phy, 1); + msm_otg_start_peripheral(otg->usb_phy, + 1); otg->state = OTG_STATE_B_PERIPHERAL; break; @@ -1222,8 +1225,8 @@ static void msm_otg_sm_work(struct work_struct *w) * is incremented in charger detection work. */ if (cancel_delayed_work_sync(&motg->chg_work)) { - pm_runtime_put_sync(otg->phy->dev); - msm_otg_reset(otg->phy); + pm_runtime_put_sync(otg->usb_phy->dev); + msm_otg_reset(otg->usb_phy); } msm_otg_notify_charger(motg, 0); motg->chg_state = USB_CHG_STATE_UNDEFINED; @@ -1231,27 +1234,27 @@ static void msm_otg_sm_work(struct work_struct *w) } if (otg->state == OTG_STATE_B_IDLE) - pm_runtime_put_sync(otg->phy->dev); + pm_runtime_put_sync(otg->usb_phy->dev); break; case OTG_STATE_B_PERIPHERAL: - dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n"); + dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_PERIPHERAL state\n"); if (!test_bit(B_SESS_VLD, &motg->inputs) || !test_bit(ID, &motg->inputs)) { msm_otg_notify_charger(motg, 0); - msm_otg_start_peripheral(otg->phy, 0); + msm_otg_start_peripheral(otg->usb_phy, 0); motg->chg_state = USB_CHG_STATE_UNDEFINED; motg->chg_type = USB_INVALID_CHARGER; otg->state = OTG_STATE_B_IDLE; - msm_otg_reset(otg->phy); + msm_otg_reset(otg->usb_phy); schedule_work(w); } break; case OTG_STATE_A_HOST: - dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n"); + dev_dbg(otg->usb_phy->dev, "OTG_STATE_A_HOST state\n"); if (test_bit(ID, &motg->inputs)) { - msm_otg_start_host(otg->phy, 0); + msm_otg_start_host(otg->usb_phy, 0); otg->state = OTG_STATE_B_IDLE; - msm_otg_reset(otg->phy); + msm_otg_reset(otg->usb_phy); schedule_work(w); } break; @@ -1388,7 +1391,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, goto out; } - pm_runtime_get_sync(otg->phy->dev); + pm_runtime_get_sync(otg->usb_phy->dev); schedule_work(&motg->sm_work); out: return status; @@ -1668,7 +1671,7 @@ static int msm_otg_probe(struct platform_device *pdev) phy->io_ops = &msm_otg_io_ops; - phy->otg->phy = &motg->phy; + phy->otg->usb_phy = &motg->phy; phy->otg->set_host = msm_otg_set_host; phy->otg->set_peripheral = msm_otg_set_peripheral; diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index ee87aa7..81d934f 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -56,7 +56,7 @@ static char *state_string[] = { static int mv_otg_set_vbus(struct usb_otg *otg, bool on) { - struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy); + struct mv_otg *mvotg = container_of(otg->usb_phy, struct mv_otg, phy); if (mvotg->pdata->set_vbus == NULL) return -ENODEV; @@ -716,8 +716,8 @@ static int mv_otg_probe(struct platform_device *pdev) mvotg->phy.otg = otg; mvotg->phy.label = driver_name; - otg->phy = &mvotg->phy; otg->state = OTG_STATE_UNDEFINED; + otg->usb_phy = &mvotg->phy; otg->set_host = mv_otg_set_host; otg->set_peripheral = mv_otg_set_peripheral; otg->set_vbus = mv_otg_set_vbus; diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index 04ece53..9cabc1a 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -196,7 +196,8 @@ static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend) static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host) { - struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy); + struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb, + phy); dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, host); @@ -225,7 +226,8 @@ static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host) static int tahvo_usb_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { - struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy); + struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb, + phy); dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, gadget); @@ -383,7 +385,7 @@ static int tahvo_usb_probe(struct platform_device *pdev) tu->phy.label = DRIVER_NAME; tu->phy.set_suspend = tahvo_usb_set_suspend; - tu->phy.otg->phy = &tu->phy; + tu->phy.otg->usb_phy = &tu->phy; tu->phy.otg->set_host = tahvo_usb_set_host; tu->phy.otg->set_peripheral = tahvo_usb_set_peripheral; diff --git a/drivers/usb/phy/phy-ulpi.c b/drivers/usb/phy/phy-ulpi.c index 4e3877c..f48a7a2 100644 --- a/drivers/usb/phy/phy-ulpi.c +++ b/drivers/usb/phy/phy-ulpi.c @@ -211,7 +211,7 @@ static int ulpi_init(struct usb_phy *phy) static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host) { - struct usb_phy *phy = otg->phy; + struct usb_phy *phy = otg->usb_phy; unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL); if (!host) { @@ -237,7 +237,7 @@ static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host) static int ulpi_set_vbus(struct usb_otg *otg, bool on) { - struct usb_phy *phy = otg->phy; + struct usb_phy *phy = otg->usb_phy; unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL); flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT); @@ -276,7 +276,7 @@ otg_ulpi_create(struct usb_phy_io_ops *ops, phy->otg = otg; phy->init = ulpi_init; - otg->phy = phy; + otg->usb_phy = phy; otg->set_host = ulpi_set_host; otg->set_vbus = ulpi_set_vbus; diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 33d3480..978fbbb 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -14,7 +14,7 @@ struct usb_otg { u8 default_a; - struct usb_phy *phy; + struct usb_phy *usb_phy; struct usb_bus *host; struct usb_gadget *gadget; -- cgit v0.10.2 From 48bcc18076df4e07ef86226ac6ce795f64c84f7f Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 30 Oct 2014 18:41:15 +0100 Subject: usb: add support to the generic PHY framework in OTG This patch adds support of the PHY framework in OTG and keeps the USB PHY compatibility. Here the only modification is to add PHY member in the OTG structure, along with the USB PHY one. Signed-off-by: Antoine Tenart Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 978fbbb..52661c5 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -9,11 +9,14 @@ #ifndef __LINUX_USB_OTG_H #define __LINUX_USB_OTG_H +#include #include struct usb_otg { u8 default_a; + struct phy *phy; + /* old usb_phy interface */ struct usb_phy *usb_phy; struct usb_bus *host; struct usb_gadget *gadget; -- cgit v0.10.2 From ef44cb4226d132146e44f8ea562a16b27ff61126 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 30 Oct 2014 18:41:16 +0100 Subject: usb: allow to supply the PHY in the drivers when using HCD This patch modify the generic code handling PHYs to allow them to be supplied from the drivers. This adds checks to ensure no PHY was already there when looking for one in the generic code. This also makes sure we do not modify its state in the generic HCD functions, it was provided by the driver. Signed-off-by: Antoine Tenart Acked-by: Alan Stern Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index ea40626..9015139 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -161,7 +161,7 @@ struct hw_bank { * @test_mode: the selected test mode * @platdata: platform specific information supplied by parent device * @vbus_active: is VBUS active - * @transceiver: pointer to USB PHY, if any + * @usb_phy: pointer to USB PHY, if any * @hcd: pointer to usb_hcd for ehci host driver * @debugfs: root dentry for this controller in debugfs * @id_event: indicates there is an id event, and handled at ci_otg_work @@ -177,6 +177,7 @@ struct ci_hdrc { struct ci_role_driver *roles[CI_ROLE_END]; enum ci_role role; bool is_otg; + struct usb_otg otg; struct otg_fsm fsm; struct ci_otg_fsm_timer_list *fsm_timer; struct work_struct work; @@ -201,7 +202,7 @@ struct ci_hdrc { struct ci_hdrc_platform_data *platdata; int vbus_active; - struct usb_phy *transceiver; + struct usb_phy *usb_phy; struct usb_hcd *hcd; struct dentry *debugfs; bool id_event; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index a7ab0f1..6f8b1b1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -147,7 +147,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - pdata.phy = data->phy; + pdata.usb_phy = data->phy; if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX) pdata.flags |= CI_HDRC_IMX28_WRITE_FIX; diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 4935ac3..3edf969 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -26,15 +26,15 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n"); writel(0, USB_AHBBURST); writel(0, USB_AHBMODE); - usb_phy_init(ci->transceiver); + usb_phy_init(ci->usb_phy); break; case CI_HDRC_CONTROLLER_STOPPED_EVENT: dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n"); /* - * Put the transceiver in non-driving mode. Otherwise host + * Put the phy in non-driving mode. Otherwise host * may not detect soft-disconnection. */ - usb_phy_notify_disconnect(ci->transceiver, USB_SPEED_UNKNOWN); + usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN); break; default: dev_dbg(dev, "unknown ci_hdrc event\n"); @@ -68,7 +68,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev) if (IS_ERR(phy)) return PTR_ERR(phy); - ci_hdrc_msm_platdata.phy = phy; + ci_hdrc_msm_platdata.usb_phy = phy; plat_ci = ci_hdrc_add_device(&pdev->dev, pdev->resource, pdev->num_resources, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 9bdc6bd..30f8942 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -312,7 +312,7 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) case USBPHY_INTERFACE_MODE_UTMI: case USBPHY_INTERFACE_MODE_UTMIW: case USBPHY_INTERFACE_MODE_HSIC: - ret = usb_phy_init(ci->transceiver); + ret = usb_phy_init(ci->usb_phy); if (ret) return ret; hw_phymode_configure(ci); @@ -320,12 +320,12 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) case USBPHY_INTERFACE_MODE_ULPI: case USBPHY_INTERFACE_MODE_SERIAL: hw_phymode_configure(ci); - ret = usb_phy_init(ci->transceiver); + ret = usb_phy_init(ci->usb_phy); if (ret) return ret; break; default: - ret = usb_phy_init(ci->transceiver); + ret = usb_phy_init(ci->usb_phy); } return ret; @@ -605,13 +605,13 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - if (ci->platdata->phy) - ci->transceiver = ci->platdata->phy; + if (ci->platdata->usb_phy) + ci->usb_phy = ci->platdata->usb_phy; else - ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + ci->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - if (IS_ERR(ci->transceiver)) { - ret = PTR_ERR(ci->transceiver); + if (IS_ERR(ci->usb_phy)) { + ret = PTR_ERR(ci->usb_phy); /* * if -ENXIO is returned, it means PHY layer wasn't * enabled, so it makes no sense to return -EPROBE_DEFER @@ -728,7 +728,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) stop: ci_role_destroy(ci); deinit_phy: - usb_phy_shutdown(ci->transceiver); + usb_phy_shutdown(ci->usb_phy); return ret; } @@ -741,7 +741,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) free_irq(ci->irq, ci); ci_role_destroy(ci); ci_hdrc_enter_lpm(ci, true); - usb_phy_shutdown(ci->transceiver); + usb_phy_shutdown(ci->usb_phy); return 0; } diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index f038804..268e423 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -220,7 +220,7 @@ static int ci_otg_show(struct seq_file *s, void *unused) /* ------ State ----- */ seq_printf(s, "OTG state: %s\n\n", - usb_otg_state_string(ci->transceiver->otg->state)); + usb_otg_state_string(ci->otg.state)); /* ------ State Machine Variables ----- */ seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop); diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index ebde7b6..789809f 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -59,7 +59,7 @@ static int host_start(struct ci_hdrc *ci) hcd->has_tt = 1; hcd->power_budget = ci->platdata->power_budget; - hcd->usb_phy = ci->transceiver; + hcd->usb_phy = ci->usb_phy; hcd->tpl_support = ci->platdata->tpl_support; ehci = hcd_to_ehci(hcd); @@ -86,10 +86,11 @@ static int host_start(struct ci_hdrc *ci) if (ret) { goto disable_reg; } else { - struct usb_otg *otg = ci->transceiver->otg; + struct usb_otg *otg = &ci->otg; ci->hcd = hcd; - if (otg) { + + if (ci_otg_is_fsm_mode(ci)) { otg->host = &hcd->self; hcd->self.otg_port = 1; } diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index d8490e7..862d7cb 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -778,20 +778,10 @@ void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) { int retval = 0; - struct usb_otg *otg; - otg = devm_kzalloc(ci->dev, - sizeof(struct usb_otg), GFP_KERNEL); - if (!otg) { - dev_err(ci->dev, - "Failed to allocate usb_otg structure for ci hdrc otg!\n"); - return -ENOMEM; - } - - otg->usb_phy = ci->transceiver; - otg->gadget = &ci->gadget; - ci->fsm.otg = otg; - ci->transceiver->otg = ci->fsm.otg; + ci->otg.usb_phy = ci->usb_phy; + ci->otg.gadget = &ci->gadget; + ci->fsm.otg = &ci->otg; ci->fsm.power_up = 1; ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; ci->fsm.otg->state = OTG_STATE_UNDEFINED; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index f4397b2..a2d80ab 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1519,8 +1519,8 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma) { struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); - if (ci->transceiver) - return usb_phy_set_power(ci->transceiver, ma); + if (ci->usb_phy) + return usb_phy_set_power(ci->usb_phy, ma); return -ENOTSUPP; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index b84fb14..6a2a2fd 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2648,7 +2648,7 @@ int usb_add_hcd(struct usb_hcd *hcd, } } - if (IS_ENABLED(CONFIG_GENERIC_PHY)) { + if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) { struct phy *phy = phy_get(hcd->self.controller, "usb"); if (IS_ERR(phy)) { @@ -2668,6 +2668,7 @@ int usb_add_hcd(struct usb_hcd *hcd, goto err_phy; } hcd->phy = phy; + hcd->remove_phy = 1; } } @@ -2814,7 +2815,7 @@ err_allocate_root_hub: err_register_bus: hcd_buffer_destroy(hcd); err_create_buf: - if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) { + if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) { phy_power_off(hcd->phy); phy_exit(hcd->phy); phy_put(hcd->phy); @@ -2898,7 +2899,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); - if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) { + if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) { phy_power_off(hcd->phy); phy_exit(hcd->phy); phy_put(hcd->phy); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index e14c09a..4fe161a 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -13,7 +13,7 @@ struct ci_hdrc_platform_data { /* offset of the capability registers */ uintptr_t capoffset; unsigned power_budget; - struct usb_phy *phy; + struct usb_phy *usb_phy; enum usb_phy_interface phy_mode; unsigned long flags; #define CI_HDRC_REGS_SHARED BIT(0) -- cgit v0.10.2 From 1e5e2d3d055436c114e2f16145b83339aed024ff Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 30 Oct 2014 18:41:19 +0100 Subject: usb: chipidea: add support to the generic PHY framework This patch adds support of the PHY framework for ChipIdea drivers. Changes are done in both the ChipIdea common code and in the drivers accessing the PHY. This is done by adding a new PHY member in ChipIdea's structures and by taking care of it in the code. Signed-off-by: Antoine Tenart Acked-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 9015139..5bbfcc7 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -161,7 +161,8 @@ struct hw_bank { * @test_mode: the selected test mode * @platdata: platform specific information supplied by parent device * @vbus_active: is VBUS active - * @usb_phy: pointer to USB PHY, if any + * @phy: pointer to PHY, if any + * @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework * @hcd: pointer to usb_hcd for ehci host driver * @debugfs: root dentry for this controller in debugfs * @id_event: indicates there is an id event, and handled at ci_otg_work @@ -202,6 +203,8 @@ struct ci_hdrc { struct ci_hdrc_platform_data *platdata; int vbus_active; + struct phy *phy; + /* old usb_phy interface */ struct usb_phy *usb_phy; struct usb_hcd *hcd; struct dentry *debugfs; diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 30f8942..60578d9 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -299,6 +300,49 @@ static void hw_phymode_configure(struct ci_hdrc *ci) } /** + * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy + * interfaces + * @ci: the controller + * + * This function returns an error code if the phy failed to init + */ +static int _ci_usb_phy_init(struct ci_hdrc *ci) +{ + int ret; + + if (ci->phy) { + ret = phy_init(ci->phy); + if (ret) + return ret; + + ret = phy_power_on(ci->phy); + if (ret) { + phy_exit(ci->phy); + return ret; + } + } else { + ret = usb_phy_init(ci->usb_phy); + } + + return ret; +} + +/** + * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy + * interfaces + * @ci: the controller + */ +static void ci_usb_phy_exit(struct ci_hdrc *ci) +{ + if (ci->phy) { + phy_power_off(ci->phy); + phy_exit(ci->phy); + } else { + usb_phy_shutdown(ci->usb_phy); + } +} + +/** * ci_usb_phy_init: initialize phy according to different phy type * @ci: the controller * @@ -312,7 +356,7 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) case USBPHY_INTERFACE_MODE_UTMI: case USBPHY_INTERFACE_MODE_UTMIW: case USBPHY_INTERFACE_MODE_HSIC: - ret = usb_phy_init(ci->usb_phy); + ret = _ci_usb_phy_init(ci); if (ret) return ret; hw_phymode_configure(ci); @@ -320,12 +364,12 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) case USBPHY_INTERFACE_MODE_ULPI: case USBPHY_INTERFACE_MODE_SERIAL: hw_phymode_configure(ci); - ret = usb_phy_init(ci->usb_phy); + ret = _ci_usb_phy_init(ci); if (ret) return ret; break; default: - ret = usb_phy_init(ci->usb_phy); + ret = _ci_usb_phy_init(ci); } return ret; @@ -605,23 +649,26 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - if (ci->platdata->usb_phy) + if (ci->platdata->phy) { + ci->phy = ci->platdata->phy; + } else if (ci->platdata->usb_phy) { ci->usb_phy = ci->platdata->usb_phy; - else + } else { + ci->phy = devm_phy_get(dev, "usb-phy"); ci->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - if (IS_ERR(ci->usb_phy)) { - ret = PTR_ERR(ci->usb_phy); - /* - * if -ENXIO is returned, it means PHY layer wasn't - * enabled, so it makes no sense to return -EPROBE_DEFER - * in that case, since no PHY driver will ever probe. - */ - if (ret == -ENXIO) - return ret; + /* if both generic PHY and USB PHY layers aren't enabled */ + if (PTR_ERR(ci->phy) == -ENOSYS && + PTR_ERR(ci->usb_phy) == -ENXIO) + return -ENXIO; + + if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) + return -EPROBE_DEFER; - dev_err(dev, "no usb2 phy configured\n"); - return -EPROBE_DEFER; + if (IS_ERR(ci->phy)) + ci->phy = NULL; + else if (IS_ERR(ci->usb_phy)) + ci->usb_phy = NULL; } ret = ci_usb_phy_init(ci); @@ -728,7 +775,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) stop: ci_role_destroy(ci); deinit_phy: - usb_phy_shutdown(ci->usb_phy); + ci_usb_phy_exit(ci); return ret; } @@ -741,7 +788,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) free_irq(ci->irq, ci); ci_role_destroy(ci); ci_hdrc_enter_lpm(ci, true); - usb_phy_shutdown(ci->usb_phy); + ci_usb_phy_exit(ci); return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 789809f..4f8eb40 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -59,8 +59,11 @@ static int host_start(struct ci_hdrc *ci) hcd->has_tt = 1; hcd->power_budget = ci->platdata->power_budget; - hcd->usb_phy = ci->usb_phy; hcd->tpl_support = ci->platdata->tpl_support; + if (ci->phy) + hcd->phy = ci->phy; + else + hcd->usb_phy = ci->usb_phy; ehci = hcd_to_ehci(hcd); ehci->caps = ci->hw_bank.cap; diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 862d7cb..3c2ab1a 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -779,7 +779,11 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) { int retval = 0; - ci->otg.usb_phy = ci->usb_phy; + if (ci->phy) + ci->otg.phy = ci->phy; + else + ci->otg.usb_phy = ci->usb_phy; + ci->otg.gadget = &ci->gadget; ci->fsm.otg = &ci->otg; ci->fsm.power_up = 1; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 4fe161a..c01bf4e 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -13,6 +13,8 @@ struct ci_hdrc_platform_data { /* offset of the capability registers */ uintptr_t capoffset; unsigned power_budget; + struct phy *phy; + /* old usb_phy interface */ struct usb_phy *usb_phy; enum usb_phy_interface phy_mode; unsigned long flags; -- cgit v0.10.2 From 2eac3992897e3e1be40e518032dbfd6aeca1932b Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:22 +0800 Subject: usb: dwc3: enable hibernation if to be supported It enables hibernation if the function is set in coreConsultant. Suggested-by: Felipe Balbi Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index fa396fc..2f7aecc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -449,6 +449,12 @@ static int dwc3_core_init(struct dwc3 *dwc) case DWC3_GHWPARAMS1_EN_PWROPT_HIB: /* enable hibernation here */ dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); + + /* + * REVISIT Enabling this bit so that host-mode hibernation + * will work. Device-mode hibernation is not yet implemented. + */ + reg |= DWC3_GCTL_GBLHIBERNATIONEN; break; default: dev_dbg(dwc->dev, "No power optimization available\n"); -- cgit v0.10.2 From 946bd579a6385508bd93c9d453916c1a06c548ae Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:23 +0800 Subject: usb: dwc3: add a flag to check if it is fpga board Some chip vendor is on pre-silicon phase, which needs to use the simulation board. It should have the same product and vendor id with the true soc, but might have some minor different configurations. Below thread discussion proposes to find a method to distinguish between simulation board and soc. http://marc.info/?l=linux-usb&m=141194772206369&w=2 In Andvanced Configuration of coreConsultant, there is the parameter of DWC_USB_EN_FPGA. This bit has the function we need. And it would response as 7 bit of GHWPARAMS6 register. So it's able to check this functional bit to confirm if works on FPGA board. Reported-by: Felipe Balbi Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 2f7aecc..9830f87 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -460,6 +460,12 @@ static int dwc3_core_init(struct dwc3 *dwc) dev_dbg(dwc->dev, "No power optimization available\n"); } + /* check if current dwc3 is on simulation board */ + if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { + dev_dbg(dwc->dev, "it is on FPGA board\n"); + dwc->is_fpga = true; + } + /* * WORKAROUND: DWC3 revisions <1.90a have a bug * where the device can fail to connect at SuperSpeed diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a715ee1..f6ee623 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -210,6 +210,9 @@ #define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13) #define DWC3_MAX_HIBER_SCRATCHBUFS 15 +/* Global HWPARAMS6 Register */ +#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7) + /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -662,6 +665,7 @@ struct dwc3_scratchpad_array { * @ep0_expect_in: true when we expect a DATA IN transfer * @has_hibernation: true when dwc3 was configured with Hibernation * @is_selfpowered: true when we are selfpowered + * @is_fpga: true when we are using the FPGA board * @needs_fifo_resize: not all users might want fifo resizing, flag it * @pullups_connected: true when Run/Stop bit is set * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. @@ -765,6 +769,7 @@ struct dwc3 { unsigned ep0_expect_in:1; unsigned has_hibernation:1; unsigned is_selfpowered:1; + unsigned is_fpga:1; unsigned needs_fifo_resize:1; unsigned pullups_connected:1; unsigned resize_fifos:1; -- cgit v0.10.2 From 8f317b47140ddbce831176db9669d2100030d18a Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:24 +0800 Subject: usb: dwc3: initialize platform data at pci glue layer This patch initializes platform data at pci glue layer, and SoCs x86-based platform vendor is able to define their flags in platform data at bus glue layer. Then do some independent behaviors at dwc3 core level. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index a36cf66..ada975f 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -25,6 +25,8 @@ #include #include +#include "platform_data.h" + /* FIXME define these in */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd @@ -102,6 +104,9 @@ static int dwc3_pci_probe(struct pci_dev *pci, struct dwc3_pci *glue; int ret; struct device *dev = &pci->dev; + struct dwc3_platform_data dwc3_pdata; + + memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata)); glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); if (!glue) @@ -148,6 +153,10 @@ static int dwc3_pci_probe(struct pci_dev *pci, pci_set_drvdata(pci, glue); + ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata)); + if (ret) + goto err3; + dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); dwc3->dev.dma_mask = dev->dma_mask; -- cgit v0.10.2 From 3b81221a529c087171557d7c4aec02b0ba029bb1 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:25 +0800 Subject: usb: dwc3: add disscramble quirk This patch adds disscramble quirk, and it only needs to be enabled at fpga board on some vendor platforms. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 471366d..8ec2256 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -14,6 +14,8 @@ Optional properties: - phys: from the *Generic PHY* bindings - phy-names: from the *Generic PHY* bindings - tx-fifo-resize: determines if the FIFO *has* to be reallocated. + - snps,disable_scramble_quirk: true when SW should disable data scrambling. + Only really useful for FPGA builds. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 9830f87..a0ae132 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -422,7 +422,6 @@ static int dwc3_core_init(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_SCALEDOWN_MASK; - reg &= ~DWC3_GCTL_DISSCRAMBLE; switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { case DWC3_GHWPARAMS1_EN_PWROPT_CLK: @@ -466,6 +465,14 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc->is_fpga = true; } + WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga, + "disable_scramble cannot be used on non-FPGA builds\n"); + + if (dwc->disable_scramble_quirk && dwc->is_fpga) + reg |= DWC3_GCTL_DISSCRAMBLE; + else + reg &= ~DWC3_GCTL_DISSCRAMBLE; + /* * WORKAROUND: DWC3 revisions <1.90a have a bug * where the device can fail to connect at SuperSpeed @@ -710,11 +717,16 @@ static int dwc3_probe(struct platform_device *pdev) dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); dwc->dr_mode = of_usb_get_dr_mode(node); + + dwc->disable_scramble_quirk = of_property_read_bool(node, + "snps,disable_scramble_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->dr_mode = pdata->dr_mode; + + dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f6ee623..56bada6 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -672,6 +672,7 @@ struct dwc3_scratchpad_array { * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @start_config_issued: true when StartConfig command has been issued * @three_stage_setup: set if we perform a three phase setup + * @disable_scramble_quirk: set if we enable the disable scramble quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -776,6 +777,8 @@ struct dwc3 { unsigned setup_packet_pending:1; unsigned start_config_issued:1; unsigned three_stage_setup:1; + + unsigned disable_scramble_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 7db34f0..9209d02 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -24,4 +24,6 @@ struct dwc3_platform_data { enum usb_device_speed maximum_speed; enum usb_dr_mode dr_mode; bool tx_fifo_resize; + + unsigned disable_scramble_quirk:1; }; -- cgit v0.10.2 From 80caf7d21adca10c4621d511f6eb01f7ed2b342c Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:26 +0800 Subject: usb: dwc3: add lpm erratum support When parameter DWC_USB3_LPM_ERRATA_ENABLE is enabled in Andvanced Configuration of coreConsultant, it supports of xHCI BESL Errata Dated 10/19/2011 is enabled in host mode. In device mode it adds the capability to send NYET response threshold based on the BESL value received in the LPM token, and the threhold is configurable for each soc platform. This patch adds an entry that soc platform is able to define the lpm capacity with their own device tree or bus glue layer. [ balbi@ti.com : added devicetree documentation, spelled threshold completely, made sure threshold is only applied to proper core revisions. ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 8ec2256..2b0c1f2 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -16,6 +16,8 @@ Optional properties: - tx-fifo-resize: determines if the FIFO *has* to be reallocated. - snps,disable_scramble_quirk: true when SW should disable data scrambling. Only really useful for FPGA builds. + - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled + - snps,lpm-nyet-threshold: LPM NYET threshold This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a0ae132..6f9e5b8 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -657,6 +657,7 @@ static int dwc3_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct resource *res; struct dwc3 *dwc; + u8 lpm_nyet_threshold; int ret; @@ -712,16 +713,27 @@ static int dwc3_probe(struct platform_device *pdev) */ res->start -= DWC3_GLOBALS_REGS_START; + /* default to highest possible threshold */ + lpm_nyet_threshold = 0xff; + if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); + dwc->has_lpm_erratum = of_property_read_bool(node, + "snps,has-lpm-erratum"); + of_property_read_u8(node, "snps,lpm-nyet-threshold", + &lpm_nyet_threshold); - dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); + dwc->needs_fifo_resize = of_property_read_bool(node, + "tx-fifo-resize"); dwc->dr_mode = of_usb_get_dr_mode(node); dwc->disable_scramble_quirk = of_property_read_bool(node, "snps,disable_scramble_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; + dwc->has_lpm_erratum = pdata->has_lpm_erratum; + if (pdata->lpm_nyet_threshold) + lpm_nyet_threshold = pdata->lpm_nyet_threshold; dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->dr_mode = pdata->dr_mode; @@ -733,6 +745,8 @@ static int dwc3_probe(struct platform_device *pdev) if (dwc->maximum_speed == USB_SPEED_UNKNOWN) dwc->maximum_speed = USB_SPEED_SUPER; + dwc->lpm_nyet_threshold = lpm_nyet_threshold; + ret = dwc3_core_get_phy(dwc); if (ret) return ret; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 56bada6..34f1e08 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -246,16 +246,19 @@ #define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) /* These apply for core versions 1.94a and later */ -#define DWC3_DCTL_KEEP_CONNECT (1 << 19) -#define DWC3_DCTL_L1_HIBER_EN (1 << 18) -#define DWC3_DCTL_CRS (1 << 17) -#define DWC3_DCTL_CSS (1 << 16) +#define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf) +#define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20) -#define DWC3_DCTL_INITU2ENA (1 << 12) -#define DWC3_DCTL_ACCEPTU2ENA (1 << 11) -#define DWC3_DCTL_INITU1ENA (1 << 10) -#define DWC3_DCTL_ACCEPTU1ENA (1 << 9) -#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1) +#define DWC3_DCTL_KEEP_CONNECT (1 << 19) +#define DWC3_DCTL_L1_HIBER_EN (1 << 18) +#define DWC3_DCTL_CRS (1 << 17) +#define DWC3_DCTL_CSS (1 << 16) + +#define DWC3_DCTL_INITU2ENA (1 << 12) +#define DWC3_DCTL_ACCEPTU2ENA (1 << 11) +#define DWC3_DCTL_INITU1ENA (1 << 10) +#define DWC3_DCTL_ACCEPTU1ENA (1 << 9) +#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1) #define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5) #define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK) @@ -660,10 +663,13 @@ struct dwc3_scratchpad_array { * @regset: debugfs pointer to regdump file * @test_mode: true when we're entering a USB test mode * @test_mode_nr: test feature selector + * @lpm_nyet_threshold: LPM NYET response threshold * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer * @has_hibernation: true when dwc3 was configured with Hibernation + * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that + * there's now way for software to detect this in runtime. * @is_selfpowered: true when we are selfpowered * @is_fpga: true when we are using the FPGA board * @needs_fifo_resize: not all users might want fifo resizing, flag it @@ -764,11 +770,13 @@ struct dwc3 { u8 test_mode; u8 test_mode_nr; + u8 lpm_nyet_threshold; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; unsigned has_hibernation:1; + unsigned has_lpm_erratum:1; unsigned is_selfpowered:1; unsigned is_fpga:1; unsigned needs_fifo_resize:1; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 20dda60..88a065f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2301,6 +2301,19 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) */ reg |= DWC3_DCTL_HIRD_THRES(12); + /* + * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and + * DCFG.LPMCap is set, core responses with an ACK and the + * BESL value in the LPM token is less than or equal to LPM + * NYET threshold. + */ + WARN_ONCE(dwc->revision < DWC3_REVISION_240A + && dwc->has_lpm_erratum, + "LPM Erratum not available on dwc3 revisisions < 2.40a\n"); + + if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) + reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold); + dwc3_writel(dwc->regs, DWC3_DCTL, reg); } else { reg = dwc3_readl(dwc->regs, DWC3_DCTL); diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 9209d02..e128308 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -25,5 +25,8 @@ struct dwc3_platform_data { enum usb_dr_mode dr_mode; bool tx_fifo_resize; + u8 lpm_nyet_threshold; + unsigned disable_scramble_quirk:1; + unsigned has_lpm_erratum:1; }; -- cgit v0.10.2 From 9a5b2f3167c1f98b879d6a800ab138f04e34f9d5 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:27 +0800 Subject: usb: dwc3: add u2exit lfps quirk This patch adds u2exit lfps quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 2b0c1f2..5fcd680 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -18,6 +18,7 @@ Optional properties: Only really useful for FPGA builds. - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled - snps,lpm-nyet-threshold: LPM NYET threshold + - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6f9e5b8..33cbea5 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -473,6 +473,9 @@ static int dwc3_core_init(struct dwc3 *dwc) else reg &= ~DWC3_GCTL_DISSCRAMBLE; + if (dwc->u2exit_lfps_quirk) + reg |= DWC3_GCTL_U2EXIT_LFPS; + /* * WORKAROUND: DWC3 revisions <1.90a have a bug * where the device can fail to connect at SuperSpeed @@ -729,6 +732,8 @@ static int dwc3_probe(struct platform_device *pdev) dwc->disable_scramble_quirk = of_property_read_bool(node, "snps,disable_scramble_quirk"); + dwc->u2exit_lfps_quirk = of_property_read_bool(node, + "snps,u2exit_lfps_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -739,6 +744,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->dr_mode = pdata->dr_mode; dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; + dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 34f1e08..f93145c 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -166,6 +166,7 @@ #define DWC3_GCTL_SCALEDOWN(n) ((n) << 4) #define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) #define DWC3_GCTL_DISSCRAMBLE (1 << 3) +#define DWC3_GCTL_U2EXIT_LFPS (1 << 2) #define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1) #define DWC3_GCTL_DSBLCLKGTNG (1 << 0) @@ -679,6 +680,7 @@ struct dwc3_scratchpad_array { * @start_config_issued: true when StartConfig command has been issued * @three_stage_setup: set if we perform a three phase setup * @disable_scramble_quirk: set if we enable the disable scramble quirk + * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -787,6 +789,7 @@ struct dwc3 { unsigned three_stage_setup:1; unsigned disable_scramble_quirk:1; + unsigned u2exit_lfps_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index e128308..3f21591 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -29,4 +29,5 @@ struct dwc3_platform_data { unsigned disable_scramble_quirk:1; unsigned has_lpm_erratum:1; + unsigned u2exit_lfps_quirk:1; }; -- cgit v0.10.2 From b5a65c406367e3e79ece6f687c83d4ffce4c174c Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:28 +0800 Subject: usb: dwc3: add P3 in U2 SS inactive quirk This patch adds P3 in U2 SS inactive quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 5fcd680..36e4287 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -19,6 +19,7 @@ Optional properties: - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled - snps,lpm-nyet-threshold: LPM NYET threshold - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk + - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 33cbea5..7c54da1 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -365,6 +365,24 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) } /** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure + */ +static void dwc3_phy_setup(struct dwc3 *dwc) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + + if (dwc->u2ss_inp3_quirk) + reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; + + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + mdelay(100); +} + +/** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure * @@ -489,6 +507,8 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GCTL, reg); + dwc3_phy_setup(dwc); + ret = dwc3_alloc_scratch_buffers(dwc); if (ret) goto err1; @@ -734,6 +754,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,disable_scramble_quirk"); dwc->u2exit_lfps_quirk = of_property_read_bool(node, "snps,u2exit_lfps_quirk"); + dwc->u2ss_inp3_quirk = of_property_read_bool(node, + "snps,u2ss_inp3_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -745,6 +767,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; + dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f93145c..66fd26b 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -176,6 +176,7 @@ /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) +#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -681,6 +682,7 @@ struct dwc3_scratchpad_array { * @three_stage_setup: set if we perform a three phase setup * @disable_scramble_quirk: set if we enable the disable scramble quirk * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk + * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -790,6 +792,7 @@ struct dwc3 { unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; + unsigned u2ss_inp3_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 3f21591..cf92c81 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -30,4 +30,5 @@ struct dwc3_platform_data { unsigned disable_scramble_quirk:1; unsigned has_lpm_erratum:1; unsigned u2exit_lfps_quirk:1; + unsigned u2ss_inp3_quirk:1; }; -- cgit v0.10.2 From df31f5b3a6d3ef0bb692edff13167e9a1c5aa25e Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:29 +0800 Subject: usb: dwc3: add request p1p2p3 quirk This patch adds request P1/P2/P3 quirk for U2/U2/U3, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 36e4287..40edc78 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -20,6 +20,8 @@ Optional properties: - snps,lpm-nyet-threshold: LPM NYET threshold - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk + - snps,req_p1p2p3_quirk: when set, the core will always request for + P1/P2/P3 transition sequence. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7c54da1..600d3bc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -377,6 +377,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; + if (dwc->req_p1p2p3_quirk) + reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -756,6 +759,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,u2exit_lfps_quirk"); dwc->u2ss_inp3_quirk = of_property_read_bool(node, "snps,u2ss_inp3_quirk"); + dwc->req_p1p2p3_quirk = of_property_read_bool(node, + "snps,req_p1p2p3_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -768,6 +773,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; + dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 66fd26b..ce33163 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -177,6 +177,7 @@ /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) +#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -683,6 +684,7 @@ struct dwc3_scratchpad_array { * @disable_scramble_quirk: set if we enable the disable scramble quirk * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk + * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -793,6 +795,7 @@ struct dwc3 { unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; + unsigned req_p1p2p3_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index cf92c81..d3e6ec2 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -31,4 +31,5 @@ struct dwc3_platform_data { unsigned has_lpm_erratum:1; unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; + unsigned req_p1p2p3_quirk:1; }; -- cgit v0.10.2 From a2a1d0f5838d6aa0d1306ef9bb1011f501faa695 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:30 +0800 Subject: usb: dwc3: add delay p1p2p3 quirk This patch adds delay P0 to P1/P2/P3 quirk for U2/U2/U3, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 40edc78..4c77ed6 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -22,6 +22,8 @@ Optional properties: - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk - snps,req_p1p2p3_quirk: when set, the core will always request for P1/P2/P3 transition sequence. + - snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain + amount of 8B10B errors occur. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 600d3bc..c076514 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -380,6 +380,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->req_p1p2p3_quirk) reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; + if (dwc->del_p1p2p3_quirk) + reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -761,6 +764,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,u2ss_inp3_quirk"); dwc->req_p1p2p3_quirk = of_property_read_bool(node, "snps,req_p1p2p3_quirk"); + dwc->del_p1p2p3_quirk = of_property_read_bool(node, + "snps,del_p1p2p3_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -774,6 +779,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; + dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index ce33163..b8fbc4a 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -178,6 +178,9 @@ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) #define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) +#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) +#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) +#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -685,6 +688,7 @@ struct dwc3_scratchpad_array { * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk + * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -796,6 +800,7 @@ struct dwc3 { unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; + unsigned del_p1p2p3_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index d3e6ec2..a421cec 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -32,4 +32,5 @@ struct dwc3_platform_data { unsigned u2exit_lfps_quirk:1; unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; + unsigned del_p1p2p3_quirk:1; }; -- cgit v0.10.2 From 41c06ffdf9cc63edd875cc8ff8ae002cd9b14f96 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:31 +0800 Subject: usb: dwc3: add delay phy power change quirk This patch adds delay PHY power change from P0 to P1/P2/P3 when link state changing from U0 to U1/U2/U3 respectively, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 4c77ed6..a2598d3 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -24,6 +24,8 @@ Optional properties: P1/P2/P3 transition sequence. - snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain amount of 8B10B errors occur. + - snps,del_phy_power_chg_quirk: when set core will delay PHY power change + from P0 to P1/P2/P3. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c076514..de6a009 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -383,6 +383,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->del_p1p2p3_quirk) reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; + if (dwc->del_phy_power_chg_quirk) + reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -766,6 +769,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,req_p1p2p3_quirk"); dwc->del_p1p2p3_quirk = of_property_read_bool(node, "snps,del_p1p2p3_quirk"); + dwc->del_phy_power_chg_quirk = of_property_read_bool(node, + "snps,del_phy_power_chg_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -780,6 +785,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; + dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index b8fbc4a..5e8a75c 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -181,6 +181,7 @@ #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) +#define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) /* Global TX Fifo Size Register */ @@ -689,6 +690,7 @@ struct dwc3_scratchpad_array { * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk + * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -801,6 +803,7 @@ struct dwc3 { unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; + unsigned del_phy_power_chg_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index a421cec..ae67151 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -33,4 +33,5 @@ struct dwc3_platform_data { unsigned u2ss_inp3_quirk:1; unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; + unsigned del_phy_power_chg_quirk:1; }; -- cgit v0.10.2 From fb67afca177a215684d6124137f61e639c5483d4 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:32 +0800 Subject: usb: dwc3: add lfps filter quirk This patch adds LFPS filter quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index a2598d3..4edd29a 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -26,6 +26,7 @@ Optional properties: amount of 8B10B errors occur. - snps,del_phy_power_chg_quirk: when set core will delay PHY power change from P0 to P1/P2/P3. + - snps,lfps_filter_quirk: when set core will filter LFPS reception. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index de6a009..29a7da0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -386,6 +386,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->del_phy_power_chg_quirk) reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; + if (dwc->lfps_filter_quirk) + reg |= DWC3_GUSB3PIPECTL_LFPSFILT; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -771,6 +774,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,del_p1p2p3_quirk"); dwc->del_phy_power_chg_quirk = of_property_read_bool(node, "snps,del_phy_power_chg_quirk"); + dwc->lfps_filter_quirk = of_property_read_bool(node, + "snps,lfps_filter_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -786,6 +791,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; + dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5e8a75c..368d329 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -183,6 +183,7 @@ #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) #define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) +#define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) @@ -691,6 +692,7 @@ struct dwc3_scratchpad_array { * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk + * @lfps_filter_quirk: set if we enable LFPS filter quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -804,6 +806,7 @@ struct dwc3 { unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; + unsigned lfps_filter_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index ae67151..dad0211 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -34,4 +34,5 @@ struct dwc3_platform_data { unsigned req_p1p2p3_quirk:1; unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; + unsigned lfps_filter_quirk:1; }; -- cgit v0.10.2 From 14f4ac53dfb2321b07a0e690df797fba61102fa6 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:33 +0800 Subject: usb: dwc3: add rx_detect to polling lfps quirk This patch adds RX_DETECT to Polling.LFPS control quirk, and some special platforms can configure that if it is needed. [ balbi@ti.com : added DeviceTree binding documentation ] Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 4edd29a..1ecc333 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -27,6 +27,8 @@ Optional properties: - snps,del_phy_power_chg_quirk: when set core will delay PHY power change from P0 to P1/P2/P3. - snps,lfps_filter_quirk: when set core will filter LFPS reception. + - snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start + Polling LFPS after RX.Detect. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 29a7da0..b440b2b 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -389,6 +389,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->lfps_filter_quirk) reg |= DWC3_GUSB3PIPECTL_LFPSFILT; + if (dwc->rx_detect_poll_quirk) + reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -776,6 +779,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,del_phy_power_chg_quirk"); dwc->lfps_filter_quirk = of_property_read_bool(node, "snps,lfps_filter_quirk"); + dwc->rx_detect_poll_quirk = of_property_read_bool(node, + "snps,rx_detect_poll_quirk"); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -792,6 +797,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; + dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; } /* default to superspeed if no maximum_speed passed */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 368d329..8953d73 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -184,6 +184,7 @@ #define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) #define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9) +#define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) @@ -693,6 +694,7 @@ struct dwc3_scratchpad_array { * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk * @lfps_filter_quirk: set if we enable LFPS filter quirk + * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -807,6 +809,7 @@ struct dwc3 { unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; + unsigned rx_detect_poll_quirk:1; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index dad0211..4a0f06b 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -35,4 +35,5 @@ struct dwc3_platform_data { unsigned del_p1p2p3_quirk:1; unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; + unsigned rx_detect_poll_quirk:1; }; -- cgit v0.10.2 From 2164a476205ccc62c5874f95f3504b657fff5c04 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 28 Oct 2014 19:54:35 +0800 Subject: usb: dwc3: set SUSPHY bit for all cores It is recommended to set USB3 and USB2 SUSPHY bits to '1' after the core initialization is completed above the dwc3 revision 1.94a. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b440b2b..aefb59d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -374,6 +374,15 @@ static void dwc3_phy_setup(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + /* + * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY + * to '0' during coreConsultant configuration. So default value + * will be '0' when the core is reset. Application needs to set it + * to '1' after the core initialization is completed. + */ + if (dwc->revision > DWC3_REVISION_194A) + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; @@ -395,6 +404,21 @@ static void dwc3_phy_setup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); + + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + + /* + * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to + * '0' during coreConsultant configuration. So default value will + * be '0' when the core is reset. Application needs to set it to + * '1' after the core initialization is completed. + */ + if (dwc->revision > DWC3_REVISION_194A) + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + + mdelay(100); } /** -- cgit v0.10.2 From 6b6a0c9a3ffa3107994d92d5758cbe274c5a97b6 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:12 +0800 Subject: usb: dwc3: add Tx de-emphasis quirk This patch adds Tx de-emphasis quirk, and the Tx de-emphasis value is configurable according to PIPE3 specification. Value Description 0 -6dB de-emphasis 1 -3.5dB de-emphasis 2 No de-emphasis 3 Reserved It can be configured on DT or platform data. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 1ecc333..b724b2e 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -29,6 +29,9 @@ Optional properties: - snps,lfps_filter_quirk: when set core will filter LFPS reception. - snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start Polling LFPS after RX.Detect. + - snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value. + - snps,tx_de_emphasis: the value driven to the PHY is controlled by the + LTSSM during USB3 Compliance mode. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index aefb59d..c3dfb19 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -401,6 +401,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->rx_detect_poll_quirk) reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; + if (dwc->tx_de_emphasis_quirk) + reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -720,6 +723,7 @@ static int dwc3_probe(struct platform_device *pdev) struct resource *res; struct dwc3 *dwc; u8 lpm_nyet_threshold; + u8 tx_de_emphasis; int ret; @@ -778,6 +782,9 @@ static int dwc3_probe(struct platform_device *pdev) /* default to highest possible threshold */ lpm_nyet_threshold = 0xff; + /* default to -3.5dB de-emphasis */ + tx_de_emphasis = 1; + if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); dwc->has_lpm_erratum = of_property_read_bool(node, @@ -805,6 +812,11 @@ static int dwc3_probe(struct platform_device *pdev) "snps,lfps_filter_quirk"); dwc->rx_detect_poll_quirk = of_property_read_bool(node, "snps,rx_detect_poll_quirk"); + + dwc->tx_de_emphasis_quirk = of_property_read_bool(node, + "snps,tx_de_emphasis_quirk"); + of_property_read_u8(node, "snps,tx_de_emphasis", + &tx_de_emphasis); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; @@ -822,6 +834,10 @@ static int dwc3_probe(struct platform_device *pdev) dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; + + dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; + if (pdata->tx_de_emphasis) + tx_de_emphasis = pdata->tx_de_emphasis; } /* default to superspeed if no maximum_speed passed */ @@ -829,6 +845,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->maximum_speed = USB_SPEED_SUPER; dwc->lpm_nyet_threshold = lpm_nyet_threshold; + dwc->tx_de_emphasis = tx_de_emphasis; ret = dwc3_core_get_phy(dwc); if (ret) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 8953d73..cf9aaca 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -185,6 +185,8 @@ #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) #define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9) #define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8) +#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) +#define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) @@ -695,6 +697,12 @@ struct dwc3_scratchpad_array { * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk * @lfps_filter_quirk: set if we enable LFPS filter quirk * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk + * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk + * @tx_de_emphasis: Tx de-emphasis value + * 0 - -6dB de-emphasis + * 1 - -3.5dB de-emphasis + * 2 - No de-emphasis + * 3 - Reserved */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -810,6 +818,9 @@ struct dwc3 { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + + unsigned tx_de_emphasis_quirk:1; + unsigned tx_de_emphasis:2; }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 4a0f06b..e1ab900 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -36,4 +36,7 @@ struct dwc3_platform_data { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + + unsigned tx_de_emphasis_quirk:1; + unsigned tx_de_emphasis:2; }; -- cgit v0.10.2 From 59acfa208164205f94a11f454d08cd88f06b9908 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:13 +0800 Subject: usb: dwc3: add disable usb3 suspend phy quirk This patch adds disable usb3 suspend phy quirk, and some special platforms can configure that if it is needed. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index b724b2e..08b394e 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -32,6 +32,7 @@ Optional properties: - snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value. - snps,tx_de_emphasis: the value driven to the PHY is controlled by the LTSSM during USB3 Compliance mode. + - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c3dfb19..87ffb86 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -404,6 +404,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->tx_de_emphasis_quirk) reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); + if (dwc->dis_u3_susphy_quirk && dwc->is_fpga) + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); mdelay(100); @@ -812,6 +815,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,lfps_filter_quirk"); dwc->rx_detect_poll_quirk = of_property_read_bool(node, "snps,rx_detect_poll_quirk"); + dwc->dis_u3_susphy_quirk = of_property_read_bool(node, + "snps,dis_u3_susphy_quirk"); dwc->tx_de_emphasis_quirk = of_property_read_bool(node, "snps,tx_de_emphasis_quirk"); @@ -834,6 +839,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; + dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; if (pdata->tx_de_emphasis) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cf9aaca..fa778b0 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -697,6 +697,7 @@ struct dwc3_scratchpad_array { * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk * @lfps_filter_quirk: set if we enable LFPS filter quirk * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk + * @dis_u3_susphy_quirk: set if we disable usb3 suspend phy * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -818,6 +819,7 @@ struct dwc3 { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + unsigned dis_u3_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index e1ab900..0f1d5ad 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -36,6 +36,7 @@ struct dwc3_platform_data { unsigned del_phy_power_chg_quirk:1; unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; + unsigned dis_u3_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; -- cgit v0.10.2 From 0effe0a3e741c0e2318f541ce207c9bd6cfe985c Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:14 +0800 Subject: usb: dwc3: add disable usb2 suspend phy quirk This patch adds disable usb2 suspend phy quirk, and some special platforms can configure that if it is needed. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 08b394e..f200ecc 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -33,6 +33,7 @@ Optional properties: - snps,tx_de_emphasis: the value driven to the PHY is controlled by the LTSSM during USB3 Compliance mode. - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. + - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 87ffb86..3ea55f2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -422,6 +422,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->revision > DWC3_REVISION_194A) reg |= DWC3_GUSB2PHYCFG_SUSPHY; + if (dwc->dis_u2_susphy_quirk && dwc->is_fpga) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(100); @@ -817,6 +820,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,rx_detect_poll_quirk"); dwc->dis_u3_susphy_quirk = of_property_read_bool(node, "snps,dis_u3_susphy_quirk"); + dwc->dis_u2_susphy_quirk = of_property_read_bool(node, + "snps,dis_u2_susphy_quirk"); dwc->tx_de_emphasis_quirk = of_property_read_bool(node, "snps,tx_de_emphasis_quirk"); @@ -840,6 +845,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; + dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; if (pdata->tx_de_emphasis) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index fa778b0..cf86d30 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -698,6 +698,7 @@ struct dwc3_scratchpad_array { * @lfps_filter_quirk: set if we enable LFPS filter quirk * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk * @dis_u3_susphy_quirk: set if we disable usb3 suspend phy + * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -820,6 +821,7 @@ struct dwc3 { unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; unsigned dis_u3_susphy_quirk:1; + unsigned dis_u2_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 0f1d5ad..245300b 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -37,6 +37,7 @@ struct dwc3_platform_data { unsigned lfps_filter_quirk:1; unsigned rx_detect_poll_quirk:1; unsigned dis_u3_susphy_quirk:1; + unsigned dis_u2_susphy_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; -- cgit v0.10.2 From c53a2b512b6f2b9b1b6353c1587b8b069997852f Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:15 +0800 Subject: PCI: Add support for AMD Nolan USB3 DRD This patch adds PCI id for USB3 Dual-Role Device of AMD Nolan (NL) SoC. It will be used for PCI quirks and DWC3 device driver. Signed-off-by: Jason Chang Signed-off-by: Huang Rui Acked-by: Bjorn Helgaas Signed-off-by: Felipe Balbi diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 1fa99a3..5decad7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -562,6 +562,7 @@ #define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 #define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 #define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458 +#define PCI_DEVICE_ID_AMD_NL_USB 0x7912 #define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F #define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 #define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 -- cgit v0.10.2 From be6646bfbaec7af72ddf3fc98050ca6f19dc2b79 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:16 +0800 Subject: PCI: Prevent xHCI driver from claiming AMD Nolan USB3 DRD device The AMD Nolan (NL) SoC contains a DesignWare USB3 Dual-Role Device that can be operated either as a USB Host or a USB Device. In the AMD NL platform, this device ([1022:7912]) has a class code of PCI_CLASS_SERIAL_USB_XHCI (0x0c0330), which means the xhci driver will claim it. But the dwc3 driver is a more specific driver for this device, and we'd prefer to use it instead of xhci. To prevent xhci from claiming the device, change the class code to 0x0c03fe, which the PCI r3.0 spec defines as "USB device (not host controller)". The dwc3 driver can then claim it based on its Vendor and Device ID. Suggested-by: Heikki Krogerus Acked-by: Bjorn Helgaas Cc: Jason Chang Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 90acb32..ed6f89b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -379,6 +379,26 @@ static void quirk_ati_exploding_mce(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce); /* + * In the AMD NL platform, this device ([1022:7912]) has a class code of + * PCI_CLASS_SERIAL_USB_XHCI (0x0c0330), which means the xhci driver will + * claim it. + * But the dwc3 driver is a more specific driver for this device, and we'd + * prefer to use it instead of xhci. To prevent xhci from claiming the + * device, change the class code to 0x0c03fe, which the PCI r3.0 spec + * defines as "USB device (not host controller)". The dwc3 driver can then + * claim it based on its Vendor and Device ID. + */ +static void quirk_amd_nl_class(struct pci_dev *pdev) +{ + /* + * Use 'USB Device' (0x0c03fe) instead of PCI header provided + */ + pdev->class = 0x0c03fe; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB, + quirk_amd_nl_class); + +/* * Let's make the southbridge information explicit instead * of having to worry about people probing the ACPI areas, * for example.. (Yes, it happens, and if you read the wrong -- cgit v0.10.2 From 9755449d568b3c2745fc9c7075a7d7833c4528bd Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:17 +0800 Subject: usb: dwc3: add support for AMD Nolan platform This patch adds support for AMD Nolan (NL) FPGA and SoC platform. Cc: Jason Chang Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index ada975f..7c4faf7 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -145,6 +145,31 @@ static int dwc3_pci_probe(struct pci_dev *pci, res[1].name = "dwc_usb3"; res[1].flags = IORESOURCE_IRQ; + if (pci->vendor == PCI_VENDOR_ID_AMD && + pci->device == PCI_DEVICE_ID_AMD_NL_USB) { + dwc3_pdata.has_lpm_erratum = true; + dwc3_pdata.lpm_nyet_threshold = 0xf; + + dwc3_pdata.u2exit_lfps_quirk = true; + dwc3_pdata.u2ss_inp3_quirk = true; + dwc3_pdata.req_p1p2p3_quirk = true; + dwc3_pdata.del_p1p2p3_quirk = true; + dwc3_pdata.del_phy_power_chg_quirk = true; + dwc3_pdata.lfps_filter_quirk = true; + dwc3_pdata.rx_detect_poll_quirk = true; + + dwc3_pdata.tx_de_emphasis_quirk = true; + dwc3_pdata.tx_de_emphasis = 1; + + /* + * FIXME these quirks should be removed when AMD NL + * taps out + */ + dwc3_pdata.disable_scramble_quirk = true; + dwc3_pdata.dis_u3_susphy_quirk = true; + dwc3_pdata.dis_u2_susphy_quirk = true; + } + ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); if (ret) { dev_err(dev, "couldn't add resources to dwc3 device\n"); @@ -194,6 +219,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); -- cgit v0.10.2 From 460d098cb6728134e0e4ba3d58e10bb43032daa5 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 31 Oct 2014 11:11:18 +0800 Subject: usb: dwc3: make HIRD threshold configurable HIRD threshold should be configurable by different platforms. From DesignWare databook: When HIRD_Threshold[4] is set to 1b1 and HIRD value is greater than or equal to the value in HIRD_Threshold[3:0], dwc3 asserts output signals utmi_l1_suspend_n to put PHY into Deep Low-Power mode in L1. When HIRD_Threshold[4] is set to 1b0 or the HIRD value is less than HIRD_Threshold[3:0], dwc3 asserts output signals utmi_sleep_n on L1. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index f200ecc..cd7f045 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -34,6 +34,9 @@ Optional properties: LTSSM during USB3 Compliance mode. - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. + - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal + utmi_l1_suspend_n, false when asserts utmi_sleep_n + - snps,hird-threshold: HIRD threshold This is usually a subnode to DWC3 glue to which it is connected. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 3ea55f2..8ae42b8 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -730,6 +730,7 @@ static int dwc3_probe(struct platform_device *pdev) struct dwc3 *dwc; u8 lpm_nyet_threshold; u8 tx_de_emphasis; + u8 hird_threshold; int ret; @@ -791,12 +792,22 @@ static int dwc3_probe(struct platform_device *pdev) /* default to -3.5dB de-emphasis */ tx_de_emphasis = 1; + /* + * default to assert utmi_sleep_n and use maximum allowed HIRD + * threshold value of 0b1100 + */ + hird_threshold = 12; + if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); dwc->has_lpm_erratum = of_property_read_bool(node, "snps,has-lpm-erratum"); of_property_read_u8(node, "snps,lpm-nyet-threshold", &lpm_nyet_threshold); + dwc->is_utmi_l1_suspend = of_property_read_bool(node, + "snps,is-utmi-l1-suspend"); + of_property_read_u8(node, "snps,hird-threshold", + &hird_threshold); dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); @@ -832,6 +843,9 @@ static int dwc3_probe(struct platform_device *pdev) dwc->has_lpm_erratum = pdata->has_lpm_erratum; if (pdata->lpm_nyet_threshold) lpm_nyet_threshold = pdata->lpm_nyet_threshold; + dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend; + if (pdata->hird_threshold) + hird_threshold = pdata->hird_threshold; dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->dr_mode = pdata->dr_mode; @@ -859,6 +873,9 @@ static int dwc3_probe(struct platform_device *pdev) dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; + dwc->hird_threshold = hird_threshold + | (dwc->is_utmi_l1_suspend << 4); + ret = dwc3_core_get_phy(dwc); if (ret) return ret; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cf86d30..4bb9aa6 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -675,12 +675,16 @@ struct dwc3_scratchpad_array { * @test_mode: true when we're entering a USB test mode * @test_mode_nr: test feature selector * @lpm_nyet_threshold: LPM NYET response threshold + * @hird_threshold: HIRD threshold * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer * @has_hibernation: true when dwc3 was configured with Hibernation * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that * there's now way for software to detect this in runtime. + * @is_utmi_l1_suspend: the core asserts output signal + * 0 - utmi_sleep_n + * 1 - utmi_l1_suspend_n * @is_selfpowered: true when we are selfpowered * @is_fpga: true when we are using the FPGA board * @needs_fifo_resize: not all users might want fifo resizing, flag it @@ -797,12 +801,14 @@ struct dwc3 { u8 test_mode; u8 test_mode_nr; u8 lpm_nyet_threshold; + u8 hird_threshold; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; unsigned has_hibernation:1; unsigned has_lpm_erratum:1; + unsigned is_utmi_l1_suspend:1; unsigned is_selfpowered:1; unsigned is_fpga:1; unsigned needs_fifo_resize:1; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 88a065f..398c12f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2295,11 +2295,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); - /* - * TODO: This should be configurable. For now using - * maximum allowed HIRD threshold value of 0b1100 - */ - reg |= DWC3_DCTL_HIRD_THRES(12); + reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold); /* * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 245300b..a3a3b6d 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -25,6 +25,9 @@ struct dwc3_platform_data { enum usb_dr_mode dr_mode; bool tx_fifo_resize; + unsigned is_utmi_l1_suspend:1; + u8 hird_threshold; + u8 lpm_nyet_threshold; unsigned disable_scramble_quirk:1; -- cgit v0.10.2 From c3761a79c14da73edfaaffb6bf24a87535bf20a8 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 21 Oct 2014 15:31:42 -0500 Subject: usb: dwc2: allow dwc2 to get built when USB_GADGET=m This patch allows the gadget portion of the DWC2 driver to get built when (!USB && USB_GADGET) condition is encountered. Acked-by: Paul Zimmerman Signed-off-by: Dinh Nguyen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index f93807b..4d02718 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,6 +1,6 @@ config USB_DWC2 bool "DesignWare USB2 DRD Core Support" - depends on USB + depends on USB || USB_GADGET help Say Y here if your system has a Dual Role Hi-Speed USB controller based on the DesignWare HSOTG IP Core. -- cgit v0.10.2 From 61fbe96c8b131dcf246030c72dfe97a2cbfb247b Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 28 Oct 2014 10:20:29 +0100 Subject: cdc-acm: Drop the warning for unusual capabilities Let's drop the warning for modems with unusual capabilities, the associated quirk and blacklist. They made little sense. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e934e19..a78a7a4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1144,8 +1144,6 @@ static int acm_probe(struct usb_interface *intf, case USB_CDC_CALL_MANAGEMENT_TYPE: call_management_function = buffer[3]; call_interface_num = buffer[4]; - if ((quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) - dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); break; default: /* there are LOTS more CDC descriptors that @@ -1796,11 +1794,6 @@ static const struct usb_device_id acm_ids[] = { /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ - /* Support Lego NXT using pbLua firmware */ - { USB_DEVICE(0x0694, 0xff00), - .driver_info = NOT_A_MODEM, - }, - /* Support for Droids MuIn LCD */ { USB_DEVICE(0x04d8, 0x000b), .driver_info = NO_DATA_INTERFACE, diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index fc75651..8cd2c4b 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -129,6 +129,5 @@ struct acm { #define NO_UNION_NORMAL BIT(0) #define SINGLE_RX_URB BIT(1) #define NO_CAP_LINE BIT(2) -#define NOT_A_MODEM BIT(3) #define NO_DATA_INTERFACE BIT(4) #define IGNORE_DEVICE BIT(5) -- cgit v0.10.2 From 6d40500ac9b69b78dace3a498bc1690200682789 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Mon, 6 Oct 2014 11:51:10 +0530 Subject: usb: ehci/ohci-exynos: Fix of_node_put() for child when getting PHYs On enabling CONFIG_OF_SELFTEST which enables CONFIG_OF_DYNAMIC, we found out that while getting PHYs for the controller we were doing an extra of_node_put on the child node in our routines - exynos_e/ohci_get_phy(). This child is however already put by of_get_next_available_child() which does a of_node_put() on the "prev" node. So there's no point in putting the same node again in our routine. Reported-by: Daniel Drake Signed-off-by: Vivek Gautam Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 7189f2e..1b726bf 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -74,7 +74,6 @@ static int exynos_ehci_get_phy(struct device *dev, phy = devm_of_phy_get(dev, child, NULL); exynos_ehci->phy[phy_number] = phy; - of_node_put(child); if (IS_ERR(phy)) { ret = PTR_ERR(phy); if (ret == -EPROBE_DEFER) { diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index d28b658..39f366b 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -63,7 +63,6 @@ static int exynos_ohci_get_phy(struct device *dev, phy = devm_of_phy_get(dev, child, NULL); exynos_ohci->phy[phy_number] = phy; - of_node_put(child); if (IS_ERR(phy)) { ret = PTR_ERR(phy); if (ret == -EPROBE_DEFER) { -- cgit v0.10.2 From dd3cf17488b102092014e517b4f18f24e5e3d4aa Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 6 Oct 2014 11:10:46 +0200 Subject: usb: host: Remove optional dependencies on PLAT_S5P Commit d78c16ccde96 ("ARM: SAMSUNG: Remove remaining legacy code") removed the Kconfig symbol PLAT_S5P. Remove two optional dependencies on that symbol from this Kconfig file too. Signed-off-by: Paul Bolle Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index a8a30b1..ef04474 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -234,7 +234,7 @@ config USB_EHCI_SH config USB_EHCI_EXYNOS tristate "EHCI support for Samsung S5P/EXYNOS SoC Series" - depends on PLAT_S5P || ARCH_EXYNOS + depends on ARCH_EXYNOS help Enable support for the Samsung Exynos SOC's on-chip EHCI controller. @@ -550,7 +550,7 @@ config USB_OHCI_SH config USB_OHCI_EXYNOS tristate "OHCI support for Samsung S5P/EXYNOS SoC Series" - depends on PLAT_S5P || ARCH_EXYNOS + depends on ARCH_EXYNOS help Enable support for the Samsung Exynos SOC's on-chip OHCI controller. -- cgit v0.10.2 From e50a322e517731de5d1f6f3aad0a73f3b506c5ea Mon Sep 17 00:00:00 2001 From: Josef Gajdusek Date: Thu, 9 Oct 2014 15:47:54 +0200 Subject: usb: Do not re-read descriptors for wired devices in usb_authorize_device() This patch modifies the usb_authorize_device() function such as that it does not reload the device descriptor for wired devices. The reasons for this are as follows: * Some devices dislike the master requesting the descriptor from them twice, failing on the usb_get_device_descriptor() call with -ETIMEOUT. Observed this on my Pretec 16GB flash drive (4146:ba65). * Malicious device could send two different descriptors - one before authorization, used by userspace to determine whether to authorize it and second to be actually used by the kernel when determining which drivers to bind. Signed-off-by: Josef Gajdusek Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 11e80ac..c096a1a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2543,11 +2543,14 @@ int usb_authorize_device(struct usb_device *usb_dev) "can't autoresume for authorization: %d\n", result); goto error_autoresume; } - result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); - if (result < 0) { - dev_err(&usb_dev->dev, "can't re-read device descriptor for " - "authorization: %d\n", result); - goto error_device_descriptor; + + if (usb_dev->wusb) { + result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); + if (result < 0) { + dev_err(&usb_dev->dev, "can't re-read device descriptor for " + "authorization: %d\n", result); + goto error_device_descriptor; + } } usb_dev->authorized = 1; -- cgit v0.10.2 From 1cc373c654acde47d78da9cccb5732dab2cc584f Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 10 Oct 2014 18:19:45 +0530 Subject: usb: yurex: fixed sparse warning of incorrect type fixed sparse warning of 1) incorrect type (different address spaces) 2) incorrect type in initializer Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index c3a45da..343fa6f 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -410,7 +410,8 @@ static int yurex_release(struct inode *inode, struct file *file) return 0; } -static ssize_t yurex_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) { struct usb_yurex *dev; int retval = 0; @@ -444,7 +445,8 @@ exit: return retval; } -static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) +static ssize_t yurex_write(struct file *file, const char __user *user_buffer, + size_t count, loff_t *ppos) { struct usb_yurex *dev; int i, set = 0, retval = 0; -- cgit v0.10.2 From e28e2f2f7c42e5b9dd4c965a0245267e44a8a7ae Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 12 Oct 2014 12:19:40 +0200 Subject: uas: Make uas work with blk-mq With uas over usb-3 the tags inside the uas iu-s must match the usb-3 stream ids, and those go from 1 - qdepth. Before blk-mq calling scsi_activate_tcq(sdev, qdepth) guaranteed that we would only get cmnd->request->tag from 0 - (qdepth - 1), and we used those as uas-tags / stream-ids. With blk-mq however we are guaranteed to never get more then qdepth commands queued at the same time, but the cmnd->request->tag values may be much larger, which breaks uas. This commit fixes this by generating uas tags in the 1 - qdepth range ourselves instead of using cmnd->request->tag. While touching all involved code anyways also rename the uas_cmd_info stream field to uas_tag, because when using uas over usb-2 streams are not used. Cc: Christoph Hellwig Reported-by: Douglas Gilbert Signed-off-by: Hans de Goede Reviewed-by: Christoph Hellwig -- Changes in v2: -Remove ".disable_blk_mq = true" from uas_host_template Changes in v3: -Rebased on top of Linus' current master branch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 89b2434..004ebc1 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -66,7 +66,7 @@ enum { /* Overrides scsi_pointer */ struct uas_cmd_info { unsigned int state; - unsigned int stream; + unsigned int uas_tag; struct urb *cmd_urb; struct urb *data_in_urb; struct urb *data_out_urb; @@ -173,30 +173,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) cmnd->result = sense_iu->status; } -/* - * scsi-tags go from 0 - (nr_tags - 1), uas tags need to match stream-ids, - * which go from 1 - nr_streams. And we use 1 for untagged commands. - */ -static int uas_get_tag(struct scsi_cmnd *cmnd) -{ - int tag; - - if (blk_rq_tagged(cmnd->request)) - tag = cmnd->request->tag + 2; - else - tag = 1; - - return tag; -} - static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, int status) { struct uas_cmd_info *ci = (void *)&cmnd->SCp; + struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; scmd_printk(KERN_INFO, cmnd, - "%s %d tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", - prefix, status, uas_get_tag(cmnd), + "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", + prefix, status, cmdinfo->uas_tag, (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "", (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "", (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "", @@ -242,7 +227,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) DATA_OUT_URB_INFLIGHT | COMMAND_ABORTED)) return -EBUSY; - devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; + devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; uas_free_unsubmitted_urbs(cmnd); cmnd->scsi_done(cmnd); return 0; @@ -289,7 +274,7 @@ static void uas_stat_cmplt(struct urb *urb) idx = be16_to_cpup(&iu->tag) - 1; if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) { dev_err(&urb->dev->dev, - "stat urb: no pending cmd for tag %d\n", idx + 1); + "stat urb: no pending cmd for uas-tag %d\n", idx + 1); goto out; } @@ -427,7 +412,8 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto out; usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt, cmnd); - urb->stream_id = cmdinfo->stream; + if (devinfo->use_streams) + urb->stream_id = cmdinfo->uas_tag; urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; urb->sg = sdb->table.sgl; out: @@ -451,7 +437,8 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), uas_stat_cmplt, cmnd->device->host); - urb->stream_id = cmdinfo->stream; + if (devinfo->use_streams) + urb->stream_id = cmdinfo->uas_tag; urb->transfer_flags |= URB_FREE_BUFFER; out: return urb; @@ -465,6 +452,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, { struct usb_device *udev = devinfo->udev; struct scsi_device *sdev = cmnd->device; + struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct urb *urb = usb_alloc_urb(0, gfp); struct command_iu *iu; int len; @@ -481,7 +469,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto free; iu->iu_id = IU_ID_COMMAND; - iu->tag = cpu_to_be16(uas_get_tag(cmnd)); + iu->tag = cpu_to_be16(cmdinfo->uas_tag); iu->prio_attr = UAS_SIMPLE_TAG; iu->len = len; int_to_scsilun(sdev->lun, &iu->lun); @@ -608,8 +596,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, struct uas_dev_info *devinfo = sdev->hostdata; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; unsigned long flags; - unsigned int stream; - int err; + int idx, err; BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); @@ -635,8 +622,12 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, return 0; } - stream = uas_get_tag(cmnd); - if (devinfo->cmnd[stream - 1]) { + /* Find a free uas-tag */ + for (idx = 0; idx < devinfo->qdepth; idx++) { + if (!devinfo->cmnd[idx]) + break; + } + if (idx == devinfo->qdepth) { spin_unlock_irqrestore(&devinfo->lock, flags); return SCSI_MLQUEUE_DEVICE_BUSY; } @@ -644,7 +635,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, cmnd->scsi_done = done; memset(cmdinfo, 0, sizeof(*cmdinfo)); - cmdinfo->stream = stream; + cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */ cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB; switch (cmnd->sc_data_direction) { @@ -659,10 +650,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, break; } - if (!devinfo->use_streams) { + if (!devinfo->use_streams) cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); - cmdinfo->stream = 0; - } err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); if (err) { @@ -674,7 +663,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, uas_add_work(cmdinfo); } - devinfo->cmnd[stream - 1] = cmnd; + devinfo->cmnd[idx] = cmnd; spin_unlock_irqrestore(&devinfo->lock, flags); return 0; } @@ -702,7 +691,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) cmdinfo->state |= COMMAND_ABORTED; /* Drop all refs to this cmnd, kill data urbs to break their ref */ - devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; + devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; if (cmdinfo->state & DATA_IN_URB_INFLIGHT) data_in_urb = usb_get_urb(cmdinfo->data_in_urb); if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) @@ -818,13 +807,6 @@ static struct scsi_host_template uas_host_template = { .cmd_per_lun = 1, /* until we override it */ .skip_settle_delay = 1, .ordered_tag = 1, - - /* - * The uas drivers expects tags not to be bigger than the maximum - * per-device queue depth, which is not true with the blk-mq tag - * allocator. - */ - .disable_blk_mq = true, }; #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ -- cgit v0.10.2 From 11a7e59405148c855e0a9d13588930ccec02c150 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 13 Oct 2014 09:53:03 +0800 Subject: usb: ehci: add ehci_port_power interface The current EHCI implementation is prepared to toggle the PORT_POWER bit to enable or disable a USB-Port. In some cases this port power can not be just toggled by the PORT_POWER bit, and the gpio-regulator is needed to be toggled too. This patch defines a port power control interface ehci_port_power for ehci core use, it toggles PORT_POWER bit as well as calls platform defined .port_power if it is defined. Signed-off-by: Michael Grzeschik Signed-off-by: Peter Chen Acked-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 15feaf9..df75b8e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -311,6 +311,7 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci); static void ehci_work(struct ehci_hcd *ehci); static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); +static int ehci_port_power(struct ehci_hcd *ehci, int portnum, bool enable); #include "ehci-timer.c" #include "ehci-hub.c" @@ -329,9 +330,13 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci) { int port = HCS_N_PORTS(ehci->hcs_params); - while (port--) + while (port--) { ehci_writel(ehci, PORT_RWC_BITS, &ehci->regs->port_status[port]); + spin_unlock_irq(&ehci->lock); + ehci_port_power(ehci, port, false); + spin_lock_irq(&ehci->lock); + } } /* @@ -1233,6 +1238,8 @@ void ehci_init_driver(struct hc_driver *drv, drv->hcd_priv_size += over->extra_priv_size; if (over->reset) drv->reset = over->reset; + if (over->port_power) + drv->port_power = over->port_power; } } EXPORT_SYMBOL_GPL(ehci_init_driver); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 5728829..118edb7 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -69,10 +69,8 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) if (test_bit(port, &ehci->owned_ports)) { reg = &ehci->regs->port_status[port]; status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; - if (!(status & PORT_POWER)) { - status |= PORT_POWER; - ehci_writel(ehci, status, reg); - } + if (!(status & PORT_POWER)) + ehci_port_power(ehci, port, true); } } @@ -952,9 +950,11 @@ int ehci_hub_control( clear_bit(wIndex, &ehci->port_c_suspend); break; case USB_PORT_FEAT_POWER: - if (HCS_PPC (ehci->hcs_params)) - ehci_writel(ehci, temp & ~PORT_POWER, - status_reg); + if (HCS_PPC(ehci->hcs_params)) { + spin_unlock_irqrestore(&ehci->lock, flags); + ehci_port_power(ehci, wIndex, false); + spin_lock_irqsave(&ehci->lock, flags); + } break; case USB_PORT_FEAT_C_CONNECTION: ehci_writel(ehci, temp | PORT_CSC, status_reg); @@ -1004,9 +1004,9 @@ int ehci_hub_control( */ if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle)) && HCS_PPC(ehci->hcs_params)) { - ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_POWER), - status_reg); + spin_unlock_irqrestore(&ehci->lock, flags); + ehci_port_power(ehci, wIndex, false); + spin_lock_irqsave(&ehci->lock, flags); temp = ehci_readl(ehci, status_reg); } } @@ -1187,9 +1187,11 @@ int ehci_hub_control( set_bit(wIndex, &ehci->suspended_ports); break; case USB_PORT_FEAT_POWER: - if (HCS_PPC (ehci->hcs_params)) - ehci_writel(ehci, temp | PORT_POWER, - status_reg); + if (HCS_PPC(ehci->hcs_params)) { + spin_unlock_irqrestore(&ehci->lock, flags); + ehci_port_power(ehci, wIndex, true); + spin_lock_irqsave(&ehci->lock, flags); + } break; case USB_PORT_FEAT_RESET: if (temp & (PORT_SUSPEND|PORT_RESUME)) @@ -1297,3 +1299,20 @@ static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum) reg = &ehci->regs->port_status[portnum - 1]; return ehci_readl(ehci, reg) & PORT_OWNER; } + +static int ehci_port_power(struct ehci_hcd *ehci, int portnum, bool enable) +{ + struct usb_hcd *hcd = ehci_to_hcd(ehci); + u32 __iomem *status_reg = &ehci->regs->port_status[portnum]; + u32 temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS; + + if (enable) + ehci_writel(ehci, temp | PORT_POWER, status_reg); + else + ehci_writel(ehci, temp & ~PORT_POWER, status_reg); + + if (hcd->driver->port_power) + hcd->driver->port_power(hcd, portnum, enable); + + return 0; +} diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index eee228a..6f0577b 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -859,6 +859,8 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) struct ehci_driver_overrides { size_t extra_priv_size; int (*reset)(struct usb_hcd *hcd); + int (*port_power)(struct usb_hcd *hcd, + int portnum, bool enable); }; extern void ehci_init_driver(struct hc_driver *drv, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index cd96a2b..9cf7e35 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -379,6 +379,9 @@ struct hc_driver { int (*disable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state state); int (*find_raw_port_number)(struct usb_hcd *, int); + /* Call for power on/off the port if necessary */ + int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable); + }; static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) -- cgit v0.10.2 From c8679a2fb8decc949c848ca58f93ff7fb619931a Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 13 Oct 2014 09:53:04 +0800 Subject: usb: chipidea: host: add portpower override This patch adds an external portpower override callback, only single port regulator control is supported now. Signed-off-by: Michael Grzeschik Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index ebde7b6..33027ab 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -34,6 +34,44 @@ static struct hc_driver __read_mostly ci_ehci_hc_driver; +struct ehci_ci_priv { + struct regulator *reg_vbus; +}; + +static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv; + struct device *dev = hcd->self.controller; + struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret = 0; + int port = HCS_N_PORTS(ehci->hcs_params); + + if (priv->reg_vbus && !ci_otg_is_fsm_mode(ci)) { + if (port > 1) { + dev_warn(dev, + "Not support multi-port regulator control\n"); + return 0; + } + if (enable) + ret = regulator_enable(priv->reg_vbus); + else + ret = regulator_disable(priv->reg_vbus); + if (ret) { + dev_err(dev, + "Failed to %s vbus regulator, ret=%d\n", + enable ? "enable" : "disable", ret); + return ret; + } + } + return 0; +}; + +static const struct ehci_driver_overrides ehci_ci_overrides = { + .extra_priv_size = sizeof(struct ehci_ci_priv), + .port_power = ehci_ci_portpower, +}; + static irqreturn_t host_irq(struct ci_hdrc *ci) { return usb_hcd_irq(ci->irq, ci->hcd); @@ -43,6 +81,7 @@ static int host_start(struct ci_hdrc *ci) { struct usb_hcd *hcd; struct ehci_hcd *ehci; + struct ehci_ci_priv *priv; int ret; if (usb_disabled()) @@ -68,23 +107,15 @@ static int host_start(struct ci_hdrc *ci) ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; ehci->imx28_write_fix = ci->imx28_write_fix; - /* - * vbus is always on if host is not in OTG FSM mode, - * otherwise should be controlled by OTG FSM - */ - if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) { - ret = regulator_enable(ci->platdata->reg_vbus); - if (ret) { - dev_err(ci->dev, - "Failed to enable vbus regulator, ret=%d\n", - ret); - goto put_hcd; - } - } + priv = (struct ehci_ci_priv *)ehci->priv; + priv->reg_vbus = NULL; + + if (ci->platdata->reg_vbus) + priv->reg_vbus = ci->platdata->reg_vbus; ret = usb_add_hcd(hcd, 0, 0); if (ret) { - goto disable_reg; + goto put_hcd; } else { struct usb_otg *otg = ci->transceiver->otg; @@ -100,10 +131,6 @@ static int host_start(struct ci_hdrc *ci) return ret; -disable_reg: - if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) - regulator_disable(ci->platdata->reg_vbus); - put_hcd: usb_put_hcd(hcd); @@ -117,8 +144,6 @@ static void host_stop(struct ci_hdrc *ci) if (hcd) { usb_remove_hcd(hcd); usb_put_hcd(hcd); - if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) - regulator_disable(ci->platdata->reg_vbus); } } @@ -146,7 +171,7 @@ int ci_hdrc_host_init(struct ci_hdrc *ci) rdrv->name = "host"; ci->roles[CI_ROLE_HOST] = rdrv; - ehci_init_driver(&ci_ehci_hc_driver, NULL); + ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides); return 0; } -- cgit v0.10.2 From a4760b3413732bccac2795b6aed28e2ff99c8ef4 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 11 Oct 2014 11:10:47 -0700 Subject: USB: OHCI: Eliminate platform-specific test in ohci.h The bcm63xx and bcm3384 platforms need to set OHCI_QUIRK_FRAME_NO, but they are non-PPC platforms and don't enable CONFIG_PPC_MPC52xx. Therefore this patch changes the code that uses OHCI_QUIRK_FRAME_NO, making it not depend on CONFIG_PPC_MPC52xx. Also, rephrase the comments describing OHCI_QUIRK_FRAME_NO and the related PSW endian swap. Signed-off-by: Kevin Cernekee Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 59f4245..bc46228 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -647,23 +647,22 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /*-------------------------------------------------------------------------*/ -/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all - * hardware handles 16 bit reads. That creates a different confusion on - * some big-endian SOC implementations. Same thing happens with PSW access. +/* + * The HCCA frame number is 16 bits, but is accessed as 32 bits since not all + * hardware handles 16 bit reads. Depending on the SoC implementation, the + * frame number can wind up in either bits [31:16] (default) or + * [15:0] (OHCI_QUIRK_FRAME_NO) on big endian hosts. + * + * Somewhat similarly, the 16-bit PSW fields in a transfer descriptor are + * reordered on BE. */ -#ifdef CONFIG_PPC_MPC52xx -#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO) -#else -#define big_endian_frame_no_quirk(ohci) 0 -#endif - static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) { u32 tmp; if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); - if (!big_endian_frame_no_quirk(ohci)) + if (!(ohci->flags & OHCI_QUIRK_FRAME_NO)) tmp >>= 16; } else tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); -- cgit v0.10.2 From c4b8692a0520331a0ede604e20a0a52b96a98607 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 11 Oct 2014 11:10:48 -0700 Subject: USB: ohci-platform: Expose no_big_frame_no and num_ports in DT These quirks are currently set through platform_data; allow DT-based SoCs to use them too. Signed-off-by: Kevin Cernekee Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt index b968a1a..19233b7 100644 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt @@ -9,6 +9,8 @@ Optional properties: - big-endian-regs : boolean, set this for hcds with big-endian registers - big-endian-desc : boolean, set this for hcds with big-endian descriptors - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc +- no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA +- num-ports : u32, to override the detected port count - clocks : a list of phandle + clock specifier pairs - phys : phandle + phy specifier pair - phy-names : "usb" diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 4369299..6fb03f8 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -175,6 +175,12 @@ static int ohci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "big-endian")) ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + if (of_property_read_bool(dev->dev.of_node, "no-big-frame-no")) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + + of_property_read_u32(dev->dev.of_node, "num-ports", + &ohci->num_ports); + priv->phy = devm_phy_get(&dev->dev, "usb"); if (IS_ERR(priv->phy)) { err = PTR_ERR(priv->phy); -- cgit v0.10.2 From 46f21949eb77a9dfc14a00071539929d11bcf69b Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 11 Oct 2014 11:10:49 -0700 Subject: USB: ohci-platform: Move platform_data checks into the probe function This puts all of the platform_data checks in the same place, and removes the need for a custom drv->reset() callback. Signed-off-by: Kevin Cernekee Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 6fb03f8..7793c3c 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -43,20 +43,6 @@ struct ohci_platform_priv { static const char hcd_name[] = "ohci-platform"; -static int ohci_platform_reset(struct usb_hcd *hcd) -{ - struct platform_device *pdev = to_platform_device(hcd->self.controller); - struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (pdata->no_big_frame_no) - ohci->flags |= OHCI_QUIRK_FRAME_NO; - if (pdata->num_ports) - ohci->num_ports = pdata->num_ports; - - return ohci_setup(hcd); -} - static int ohci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); @@ -110,7 +96,6 @@ static struct hc_driver __read_mostly ohci_platform_hc_driver; static const struct ohci_driver_overrides platform_overrides __initconst = { .product_desc = "Generic Platform OHCI controller", - .reset = ohci_platform_reset, .extra_priv_size = sizeof(struct ohci_platform_priv), }; @@ -218,6 +203,10 @@ static int ohci_platform_probe(struct platform_device *dev) ohci->flags |= OHCI_QUIRK_BE_DESC; if (pdata->big_endian_mmio) ohci->flags |= OHCI_QUIRK_BE_MMIO; + if (pdata->no_big_frame_no) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + if (pdata->num_ports) + ohci->num_ports = pdata->num_ports; #ifndef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO if (ohci->flags & OHCI_QUIRK_BE_MMIO) { -- cgit v0.10.2 From 474fe70bcf04b4d99867bc214c70d45624ab6f6f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 16 Oct 2014 17:52:38 +0200 Subject: USB: OHCI: ohci-at91: remove unnecessary headers Remove unnecessary mach/* headers to be able to converge to a multiplatform kernel. Signed-off-by: Alexandre Belloni Reviewed-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index e49eb4f..6181549 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -24,12 +24,8 @@ #include #include -#include #include -#include - - #include "ohci.h" #define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) -- cgit v0.10.2 From e5283626f5d535c54cbcc3ec4a60a4746578a4c2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 20 Oct 2014 20:51:00 -0700 Subject: usb: storage: Convert usb_stor_dbg to return void No caller or macro uses the return value so make it void. Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c index e08f647..05bc379 100644 --- a/drivers/usb/storage/debug.c +++ b/drivers/usb/storage/debug.c @@ -179,17 +179,14 @@ void usb_stor_show_sense(const struct us_data *us, US_DEBUGPX("\n"); } -int usb_stor_dbg(const struct us_data *us, const char *fmt, ...) +void usb_stor_dbg(const struct us_data *us, const char *fmt, ...) { va_list args; - int r; va_start(args, fmt); - r = dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args); + dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args); va_end(args); - - return r; } EXPORT_SYMBOL_GPL(usb_stor_dbg); diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h index b1273f0..f525203 100644 --- a/drivers/usb/storage/debug.h +++ b/drivers/usb/storage/debug.h @@ -50,15 +50,17 @@ void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb); void usb_stor_show_sense(const struct us_data *us, unsigned char key, unsigned char asc, unsigned char ascq); -__printf(2, 3) int usb_stor_dbg(const struct us_data *us, - const char *fmt, ...); +__printf(2, 3) void usb_stor_dbg(const struct us_data *us, + const char *fmt, ...); #define US_DEBUGPX(fmt, ...) printk(fmt, ##__VA_ARGS__) #define US_DEBUG(x) x #else __printf(2, 3) -static inline int _usb_stor_dbg(const struct us_data *us, - const char *fmt, ...) {return 1;} +static inline void _usb_stor_dbg(const struct us_data *us, + const char *fmt, ...) +{ +} #define usb_stor_dbg(us, fmt, ...) \ do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0) #define US_DEBUGPX(fmt, ...) \ -- cgit v0.10.2 From 527307eacb014ba903b80694e6855fbdf20c89df Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Oct 2014 15:51:34 +0530 Subject: usb: hub: remove unused variable the integer variable 'feature' was not being used anywhere in the function. so it is safe to remove the variable. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c096a1a..89e9e2c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3910,14 +3910,9 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev, enum usb3_link_state state) { - int feature; - switch (state) { case USB3_LPM_U1: - feature = USB_PORT_FEAT_U1_TIMEOUT; - break; case USB3_LPM_U2: - feature = USB_PORT_FEAT_U2_TIMEOUT; break; default: dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n", -- cgit v0.10.2 From a57971bfa1e9aa9b42ed72df027d5b985b31b56b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 22 Oct 2014 11:52:01 +0900 Subject: USB: imx21-hcd: use %pad for dma_addr_t Use %pad for dma_addr_t, because a dma_addr_t type can vary based on build options. So, it prevents the following build warnings in printks. drivers/usb/host/imx21-hcd.c:1175:2: warning: format '%X' expects argument of type 'unsigned int', but argument 8 has type 'dma_addr_t' [-Wformat] drivers/usb/host/imx21-hcd.c:1175:2: warning: format '%X' expects argument of type 'unsigned int', but argument 10 has type 'dma_addr_t' [-Wformat] Signed-off-by: Jingoo Han Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 207bad9..eb4efba 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1174,11 +1174,11 @@ static int imx21_hc_urb_enqueue(struct usb_hcd *hcd, dev_vdbg(imx21->dev, "enqueue urb=%p ep=%p len=%d " - "buffer=%p dma=%08X setupBuf=%p setupDma=%08X\n", + "buffer=%p dma=%pad setupBuf=%p setupDma=%pad\n", urb, ep, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma, - urb->setup_packet, urb->setup_dma); + urb->transfer_buffer, &urb->transfer_dma, + urb->setup_packet, &urb->setup_dma); if (usb_pipeisoc(urb->pipe)) return imx21_hc_urb_enqueue_isoc(hcd, ep, urb, mem_flags); -- cgit v0.10.2 From 5e4ccd9ee2508d04a39fa27de9eb7bf65bad7594 Mon Sep 17 00:00:00 2001 From: Wonhong Kwon Date: Fri, 24 Oct 2014 13:45:47 +0900 Subject: usb: ehci/ohci-platform: use SIMPLE_DEV_PM_OPS to support hibernation ehci/ohci-platform just define .suspend/.resume functions for dev_pm_ops, but in order to support both STR(suspend-to-ram) and hibernation, other callbacks such as .freeze/.thaw are also required. Registering all required callbacks for both STR and hibernation can be done by SIMPLE_DEV_PM_OPS macro function. Signed-off-by: Wonhong Kwon Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 2f5b9ce..da056fe 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -311,8 +311,7 @@ static int ehci_platform_remove(struct platform_device *dev) return 0; } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP static int ehci_platform_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -348,11 +347,7 @@ static int ehci_platform_resume(struct device *dev) ehci_resume(hcd, false); return 0; } - -#else /* !CONFIG_PM */ -#define ehci_platform_suspend NULL -#define ehci_platform_resume NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static const struct of_device_id vt8500_ehci_ids[] = { { .compatible = "via,vt8500-ehci", }, @@ -368,10 +363,8 @@ static const struct platform_device_id ehci_platform_table[] = { }; MODULE_DEVICE_TABLE(platform, ehci_platform_table); -static const struct dev_pm_ops ehci_platform_pm_ops = { - .suspend = ehci_platform_suspend, - .resume = ehci_platform_resume, -}; +static SIMPLE_DEV_PM_OPS(ehci_platform_pm_ops, ehci_platform_suspend, + ehci_platform_resume); static struct platform_driver ehci_platform_driver = { .id_table = ehci_platform_table, diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 7793c3c..adb691d 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -293,8 +293,7 @@ static int ohci_platform_remove(struct platform_device *dev) return 0; } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP static int ohci_platform_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -330,11 +329,7 @@ static int ohci_platform_resume(struct device *dev) ohci_resume(hcd, false); return 0; } - -#else /* !CONFIG_PM */ -#define ohci_platform_suspend NULL -#define ohci_platform_resume NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static const struct of_device_id ohci_platform_ids[] = { { .compatible = "generic-ohci", }, @@ -348,10 +343,8 @@ static const struct platform_device_id ohci_platform_table[] = { }; MODULE_DEVICE_TABLE(platform, ohci_platform_table); -static const struct dev_pm_ops ohci_platform_pm_ops = { - .suspend = ohci_platform_suspend, - .resume = ohci_platform_resume, -}; +static SIMPLE_DEV_PM_OPS(ohci_platform_pm_ops, ohci_platform_suspend, + ohci_platform_resume); static struct platform_driver ohci_platform_driver = { .id_table = ohci_platform_table, -- cgit v0.10.2 From 51f1741fcc166dd93d38c7a3212f195d84aa67df Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:55:55 +0800 Subject: usb: chipidea: otg_fsm: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index caaabc5..e683595 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -782,11 +782,8 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) otg = devm_kzalloc(ci->dev, sizeof(struct usb_otg), GFP_KERNEL); - if (!otg) { - dev_err(ci->dev, - "Failed to allocate usb_otg structure for ci hdrc otg!\n"); + if (!otg) return -ENOMEM; - } otg->phy = ci->transceiver; otg->gadget = &ci->gadget; @@ -801,11 +798,8 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) ci->fsm_timer = devm_kzalloc(ci->dev, sizeof(struct ci_otg_fsm_timer_list), GFP_KERNEL); - if (!ci->fsm_timer) { - dev_err(ci->dev, - "Failed to allocate timer structure for ci hdrc otg!\n"); + if (!ci->fsm_timer) return -ENOMEM; - } INIT_LIST_HEAD(&ci->fsm_timer->active_timers); retval = ci_otg_init_timers(ci); -- cgit v0.10.2 From b8f2854b06fad0ff3bb3eb0fa76813f50e03da64 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:55:56 +0800 Subject: usb: class: usbtmc: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index ec97840..960bc08 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1104,10 +1104,8 @@ static int usbtmc_probe(struct usb_interface *intf, dev_dbg(&intf->dev, "%s called\n", __func__); data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&intf->dev, "Unable to allocate kernel memory\n"); + if (!data) return -ENOMEM; - } data->intf = intf; data->id = id; -- cgit v0.10.2 From 03cfba992ddaf92a026548f3b5ad565425253f27 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:01 +0800 Subject: usb: host: ehci-mv: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 08147c3..b1855c1 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -153,7 +153,6 @@ static int mv_ehci_probe(struct platform_device *pdev) ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL); if (ehci_mv == NULL) { - dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); retval = -ENOMEM; goto err_put_hcd; } -- cgit v0.10.2 From 25f852a5e142ae25bab81c084dc96e174355cc49 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:02 +0800 Subject: usb: host: ehci-sh: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index 9b9b9f5..f9ebf8a 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -126,7 +126,6 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv), GFP_KERNEL); if (!priv) { - dev_dbg(&pdev->dev, "error allocating priv data\n"); ret = -ENOMEM; goto fail_request_resource; } -- cgit v0.10.2 From a41e4db0aaac75ab5db15185947c166412066cd6 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:03 +0800 Subject: usb: host: ehci-tegra: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index aaa0197..3e6f685 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -484,7 +484,6 @@ static int tegra_ehci_probe(struct platform_device *pdev) u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), GFP_KERNEL); if (!u_phy->otg) { - dev_err(&pdev->dev, "Failed to alloc memory for otg\n"); err = -ENOMEM; goto cleanup_phy; } -- cgit v0.10.2 From 58f7e76f7ce37417bd30f427168f75a9d84991ee Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:04 +0800 Subject: usb: host: oxu210hp-hcd: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 4fe79a2..75811dd 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3846,7 +3846,6 @@ static int oxu_drv_probe(struct platform_device *pdev) */ info = devm_kzalloc(&pdev->dev, sizeof(struct oxu_info), GFP_KERNEL); if (!info) { - dev_dbg(&pdev->dev, "error allocating memory\n"); ret = -EFAULT; goto error; } -- cgit v0.10.2 From 39d98bdc108b0d00be4318735384e03aed4f0466 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:05 +0800 Subject: usb: misc: usb3503: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index ae7e120..b9af8cb 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -314,10 +314,8 @@ static int usb3503_i2c_probe(struct i2c_client *i2c, int err; hub = devm_kzalloc(&i2c->dev, sizeof(struct usb3503), GFP_KERNEL); - if (!hub) { - dev_err(&i2c->dev, "private data alloc fail\n"); + if (!hub) return -ENOMEM; - } i2c_set_clientdata(i2c, hub); hub->regmap = devm_regmap_init_i2c(i2c, &usb3503_regmap_config); @@ -336,10 +334,8 @@ static int usb3503_platform_probe(struct platform_device *pdev) struct usb3503 *hub; hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL); - if (!hub) { - dev_err(&pdev->dev, "private data alloc fail\n"); + if (!hub) return -ENOMEM; - } hub->dev = &pdev->dev; return usb3503_probe(hub); -- cgit v0.10.2 From 88538be35bc9d66bb425c431e30b3614482a840d Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Oct 2014 15:56:19 +0800 Subject: usb: renesas_usbhs: delete unnecessary 'out of memory' messages The memory subsystem has already had similar message for it. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index b3b6813..6dae115 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -505,10 +505,8 @@ static int usbhs_probe(struct platform_device *pdev) /* usb private data */ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "Could not allocate priv\n"); + if (!priv) return -ENOMEM; - } priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) -- cgit v0.10.2 From d9c3ae28bd6b72803e266eb384e0ba312f9ff837 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 11:52:57 +0200 Subject: uwb: Remove bogus colon after newline from debug message Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c index 0887ae9..536ad42 100644 --- a/drivers/uwb/rsv.c +++ b/drivers/uwb/rsv.c @@ -213,7 +213,7 @@ void uwb_rsv_backoff_win_timer(unsigned long arg) bow->total_expired = 0; bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1; } - dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n: ", bow->total_expired, bow->n); + dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n", bow->total_expired, bow->n); /* try to relocate all the "to be moved" relocations */ uwb_rsv_handle_drp_avail_change(rc); @@ -234,7 +234,7 @@ void uwb_rsv_backoff_win_increment(struct uwb_rc *rc) bow->window <<= 1; bow->n = prandom_u32() & (bow->window - 1); - dev_dbg(dev, "new_window=%d, n=%d\n: ", bow->window, bow->n); + dev_dbg(dev, "new_window=%d, n=%d\n", bow->window, bow->n); /* reset the timer associated variables */ timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US; -- cgit v0.10.2 From 679315e5fae1e4614eed0d9aa26999ddcb6a0f77 Mon Sep 17 00:00:00 2001 From: Anton Staaf Date: Mon, 3 Nov 2014 08:43:20 -0800 Subject: USB: serial: add Google simple serial SubClass support Add support for Google devices that export simple serial interfaces using the vendor specific SubClass/Protocol pair 0x50/0x01. Signed-off-by: Anton Staaf Reviewed-by: Benson Leung [johan: move id entries and update Kconfig] Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index d185613..b7cf198 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -60,6 +60,7 @@ config USB_SERIAL_SIMPLE - Suunto ANT+ USB device. - Medtronic CareLink USB device - Fundamental Software dongle. + - Google USB serial devices - HP4x calculators - a number of Motorola phones - Novatel Wireless GPS receivers diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 7064eb8..bc31011 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -56,6 +56,14 @@ DEVICE(funsoft, FUNSOFT_IDS); { USB_DEVICE(0x8087, 0x0716) } DEVICE(flashloader, FLASHLOADER_IDS); +/* Google Serial USB SubClass */ +#define GOOGLE_IDS() \ + { USB_VENDOR_AND_INTERFACE_INFO(0x18d1, \ + USB_CLASS_VENDOR_SPEC, \ + 0x50, \ + 0x01) } +DEVICE(google, GOOGLE_IDS); + /* ViVOpay USB Serial Driver */ #define VIVOPAY_IDS() \ { USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */ @@ -97,6 +105,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &zio_device, &funsoft_device, &flashloader_device, + &google_device, &vivopay_device, &moto_modem_device, &novatel_gps_device, @@ -111,6 +120,7 @@ static const struct usb_device_id id_table[] = { ZIO_IDS(), FUNSOFT_IDS(), FLASHLOADER_IDS(), + GOOGLE_IDS(), VIVOPAY_IDS(), MOTO_IDS(), NOVATEL_IDS(), -- cgit v0.10.2 From 11432050f070810ba139d0226344eef120c3a559 Mon Sep 17 00:00:00 2001 From: Kazuya Mizuguchi Date: Tue, 4 Nov 2014 10:05:42 +0900 Subject: usb: renesas_usbhs: gadget: fix NULL pointer dereference in ep_disable() This patch fixes an issue that the NULL pointer dereference happens when we uses g_audio driver. Since the g_audio driver will call usb_ep_disable() in afunc_set_alt() before it calls usb_ep_enable(), the uep->pipe of renesas usbhs driver will be NULL. So, this patch adds a condition to avoid the oops. Signed-off-by: Kazuya Mizuguchi Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Shimoda Fixes: 2f98382dc (usb: renesas_usbhs: Add Renesas USBHS Gadget) Cc: # v3.0+ Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 7a45210..ac51b59 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -602,6 +602,9 @@ static int usbhsg_ep_disable(struct usb_ep *ep) struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + if (!pipe) + return -EINVAL; + usbhsg_pipe_disable(uep); usbhs_pipe_free(pipe); -- cgit v0.10.2 From 04a5def3df1cea758662615e075f64677690c75f Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Tue, 4 Nov 2014 10:05:43 +0900 Subject: usb: renesas_usbhs: gadget: fix the behavior of pullup This patch fixes an issue that this driver always enable the D+ pullup after it detected the VBUS connection even though this usb controller can control the D+ pullup timing by software. So, this driver should enable the D+ pullup after a gadget driver called usb_gadget_connect(). Signed-off-by: Takeshi Kihara Signed-off-by: Kazuya Mizuguchi Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 169307b..3714787 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -126,13 +126,15 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) { u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; - u16 val = DPRPU | HSE | USBE; + u16 val = HSE | USBE; /* * if enable * * - select Function mode - * - D+ Line Pull-up + * - D+ Line Pull-up is disabled + * When D+ Line Pull-up is enabled, + * calling usbhs_sys_function_pullup(,1) */ usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); } diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index ac51b59..cb2d529 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -56,6 +56,7 @@ struct usbhsg_gpriv { #define USBHSG_STATUS_REGISTERD (1 << 1) #define USBHSG_STATUS_WEDGE (1 << 2) #define USBHSG_STATUS_SELF_POWERED (1 << 3) +#define USBHSG_STATUS_SOFT_CONNECT (1 << 4) }; struct usbhsg_recip_handle { @@ -726,6 +727,25 @@ static struct usb_ep_ops usbhsg_ep_ops = { }; /* + * pullup control + */ +static int usbhsg_can_pullup(struct usbhs_priv *priv) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + return gpriv->driver && + usbhsg_status_has(gpriv, USBHSG_STATUS_SOFT_CONNECT); +} + +static void usbhsg_update_pullup(struct usbhs_priv *priv) +{ + if (usbhsg_can_pullup(priv)) + usbhs_sys_function_pullup(priv, 1); + else + usbhs_sys_function_pullup(priv, 0); +} + +/* * usb module start/end */ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) @@ -775,6 +795,7 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) * - usb module */ usbhs_sys_function_ctrl(priv, 1); + usbhsg_update_pullup(priv); /* * enable irq callback @@ -880,8 +901,15 @@ static int usbhsg_pullup(struct usb_gadget *gadget, int is_on) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + unsigned long flags; - usbhs_sys_function_pullup(priv, is_on); + usbhs_lock(priv, flags); + if (is_on) + usbhsg_status_set(gpriv, USBHSG_STATUS_SOFT_CONNECT); + else + usbhsg_status_clr(gpriv, USBHSG_STATUS_SOFT_CONNECT); + usbhsg_update_pullup(priv); + usbhs_unlock(priv, flags); return 0; } -- cgit v0.10.2 From 4ef35b10bff24304a5cbbf78719ce5f24d311d1f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 4 Nov 2014 10:05:44 +0900 Subject: usb: renesas_usbhs: fix the timing of dcp_control_transfer_done According to the datasheet, this driver should clear the INTSTS0.CTRT bit before this controller detects the next stage transition. Otherwise, the driver may not be able to clear the bit after the controller went to the next stage transition. After that, the driver will not be able to clear the INTSTS0.VALID, and a usb control transfer will not finish finally. If we use the testusb tool, it is easy to reproduce this issue: # testusb -a -t 10 Since the previous code handled a data stage and a status stage in the usbhsf_pio_try_push(), it may not clear the INTSTS0.CTRT at the right timing. So, this patch change the timing of usbhs_dcp_control_transfer_done() to the usbhsg_irq_ctrl_stage(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index b0c97a3..0e07925 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -577,14 +577,6 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) usbhs_pipe_number(pipe), pkt->length, pkt->actual, *is_done, pkt->zero); - /* - * Transmission end - */ - if (*is_done) { - if (usbhs_pipe_is_dcp(pipe)) - usbhs_dcp_control_transfer_done(pipe); - } - usbhsf_fifo_unselect(pipe, fifo); return 0; @@ -722,14 +714,6 @@ usbhs_fifo_read_end: usbhs_pipe_number(pipe), pkt->length, pkt->actual, *is_done, pkt->zero); - /* - * Transmission end - */ - if (*is_done) { - if (usbhs_pipe_is_dcp(pipe)) - usbhs_dcp_control_transfer_done(pipe); - } - usbhs_fifo_read_busy: usbhsf_fifo_unselect(pipe, fifo); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index cb2d529..2457306e0 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -485,6 +485,9 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, case NODATA_STATUS_STAGE: pipe->handler = &usbhs_ctrl_stage_end_handler; break; + case READ_STATUS_STAGE: + case WRITE_STATUS_STAGE: + usbhs_dcp_control_transfer_done(pipe); default: return ret; } -- cgit v0.10.2 From cdeb79431331ff0eb5a8b6a31923497aa56d25a7 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 4 Nov 2014 10:05:45 +0900 Subject: usb: renesas_usbhs: fix usbhs_pipe_clear() for DCP PIPE Since the DCPCTR doesn't have the ACLRM bit, the usbus_pipe_clear() should not call the usbhsp_pipectrl_set() with ACLRM. So, this patch fixes this issue to add the usbhs_fifo_clear_dcp() in fifo.c because the controller needs the CFIFO to clear the the DCP PIPE. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 0e07925..9b48384 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -1160,6 +1160,24 @@ static void usbhsf_dma_complete(void *arg) usbhs_pipe_number(pipe), ret); } +void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ + + /* clear DCP FIFO of transmission */ + if (usbhsf_fifo_select(pipe, fifo, 1) < 0) + return; + usbhsf_fifo_clear(pipe, fifo); + usbhsf_fifo_unselect(pipe, fifo); + + /* clear DCP FIFO of reception */ + if (usbhsf_fifo_select(pipe, fifo, 0) < 0) + return; + usbhsf_fifo_clear(pipe, fifo); + usbhsf_fifo_unselect(pipe, fifo); +} + /* * fifo init */ diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index a168a17..79ad5f9 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -74,6 +74,7 @@ int usbhs_fifo_probe(struct usbhs_priv *priv); void usbhs_fifo_remove(struct usbhs_priv *priv); void usbhs_fifo_init(struct usbhs_priv *priv); void usbhs_fifo_quit(struct usbhs_priv *priv); +void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe); /* * packet info diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 2457306e0..8697e6e 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -782,9 +782,9 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) /* * pipe initialize and enable DCP */ + usbhs_fifo_init(priv); usbhs_pipe_init(priv, usbhsg_dma_map_ctrl); - usbhs_fifo_init(priv); /* dcp init instead of usbhsg_ep_enable() */ dcp->pipe = usbhs_dcp_malloc(priv); diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 10e1ded..f0d3231 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -1474,9 +1474,9 @@ static int usbhsh_start(struct usbhs_priv *priv) /* * pipe initialize and enable DCP */ + usbhs_fifo_init(priv); usbhs_pipe_init(priv, usbhsh_dma_map_ctrl); - usbhs_fifo_init(priv); usbhsh_pipe_init_for_host(priv); /* diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 040bcef..007f45a 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -618,8 +618,12 @@ void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) void usbhs_pipe_clear(struct usbhs_pipe *pipe) { - usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); - usbhsp_pipectrl_set(pipe, ACLRM, 0); + if (usbhs_pipe_is_dcp(pipe)) { + usbhs_fifo_clear_dcp(pipe); + } else { + usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); + usbhsp_pipectrl_set(pipe, ACLRM, 0); + } } static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) -- cgit v0.10.2 From b4c9f578cb9608f7de0c89aa637a6af4a48061ef Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 4 Nov 2014 11:01:47 +0900 Subject: usb: dwc3: exynos: remove non-DT support for Exynos Specific Glue layer DWC3 Exynos Specific Glue layer can be used only for Exynos SoCs. In addition, non-DT for EXYNOS SoCs is not supported from v3.11; thus, there is no need to support non-DT for DWC3 Exynos Specific Glue layer. The 'linux/platform_data/dwc3-exynos.h' file has been used for non-DT support. Thus, the 'dwc3-exynos.h' file is removed, because it is not used anymore. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index f4e5cc6..58b5b2c 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -55,7 +55,7 @@ config USB_DWC3_OMAP config USB_DWC3_EXYNOS tristate "Samsung Exynos Platform" - depends on ARCH_EXYNOS || COMPILE_TEST + depends on ARCH_EXYNOS && OF || COMPILE_TEST default USB_DWC3 help Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 3951a65..4369c66 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -205,13 +204,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF static const struct of_device_id exynos_dwc3_match[] = { { .compatible = "samsung,exynos5250-dwusb3" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_dwc3_match); -#endif #ifdef CONFIG_PM_SLEEP static int dwc3_exynos_suspend(struct device *dev) @@ -266,7 +263,7 @@ static struct platform_driver dwc3_exynos_driver = { .remove = dwc3_exynos_remove, .driver = { .name = "exynos-dwc3", - .of_match_table = of_match_ptr(exynos_dwc3_match), + .of_match_table = exynos_dwc3_match, .pm = DEV_PM_OPS, }, }; diff --git a/include/linux/platform_data/dwc3-exynos.h b/include/linux/platform_data/dwc3-exynos.h deleted file mode 100644 index 5eb7da9b..0000000 --- a/include/linux/platform_data/dwc3-exynos.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * dwc3-exynos.h - Samsung EXYNOS DWC3 Specific Glue layer, header. - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Author: Anton Tikhomirov - * - * 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 _DWC3_EXYNOS_H_ -#define _DWC3_EXYNOS_H_ - -struct dwc3_exynos_data { - int phy_type; - int (*phy_init)(struct platform_device *pdev, int type); - int (*phy_exit)(struct platform_device *pdev, int type); -}; - -#endif /* _DWC3_EXYNOS_H_ */ -- cgit v0.10.2 From b87fd2f7aa490a7f4bab44c41937aca0bc62fdc5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 27 Oct 2014 19:06:18 +0100 Subject: usb: musb: core: check link status on resume The am335x-evmsk support two kinds of suspend: - standby the USB device remains powered while the system goes into suspend - mem the USB device becomes powerless while the system goes into suspend. In the "standby" case the device resumes quickly. In the "mem" case the system hangs for a few seconds. It seems to me that the USB-device has no address (it was disconnected) and the USB stack thinks that it is fully operational and GetPortStatus returns the status from before the suspend so it is not a big help here. This adds a check in the resume path to see if the device mode (A or B) and the speed is the same. If the device went missing between suspend/resume (VBUS went down) then MUSB seems to go into B mode and HS/FS bits are cleared. In that case we clear the port1_status bits and assume a disconnect. Once the stack learns this it does a "logical disconnect" and removes the USB-device quickly. Should the device remain connected during the suspend then MUSB will receives a "CONNECT" interrupt. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index df9c5fa..4966a16 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2300,6 +2300,8 @@ static int musb_suspend(struct device *dev) static int musb_resume(struct device *dev) { struct musb *musb = dev_to_musb(dev); + u8 devctl; + u8 mask; /* * For static cmos like DaVinci, register values were preserved @@ -2313,6 +2315,10 @@ static int musb_resume(struct device *dev) musb_restore_context(musb); + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV; + if ((devctl & mask) != (musb->context.devctl & mask)) + musb->port1_status = 0; return 0; } -- cgit v0.10.2 From baadd52f0aa7a100192661132299f13e763932df Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 27 Oct 2014 19:06:19 +0100 Subject: usb: musb: try a race-free wakeup Attaching a keyboard, using it as a wakeup via |for f in $(find /sys/devices/ocp.3/47400000.usb -name wakeup) |do | echo enabled > $f |done going into standby | echo standby > /sys/power/state and now a wake up by a pressing a key. What happens is that the system wakes up but the USB device is dead. The USB stack tries to send a few control URBs but nothing comes back. Eventually it gaves up and the device remains dead: |[ 632.559678] PM: Wakeup source USB1_PHY |[ 632.581074] PM: noirq resume of devices complete after 21.261 msecs |[ 632.607521] PM: early resume of devices complete after 10.360 msecs |[ 632.616854] net eth2: initializing cpsw version 1.12 (0) |[ 632.704126] net eth2: phy found : id is : 0x4dd074 |[ 636.704048] libphy: 4a101000.mdio:00 - Link is Up - 1000/Full |[ 638.444620] usb 1-1: reset low-speed USB device number 2 using musb-hdrc |[ 653.713435] usb 1-1: device descriptor read/64, error -110 |[ 669.093435] usb 1-1: device descriptor read/64, error -110 |[ 669.473424] usb 1-1: reset low-speed USB device number 2 using musb-hdrc |[ 684.743436] usb 1-1: device descriptor read/64, error -110 |[ 690.065097] PM: resume of devices complete after 57450.744 msecs |[ 690.076601] PM: Finishing wakeup. |[ 690.076627] Restarting tasks ... It seems that since we got woken up via MUSB_INTR_RESUME the musb_host_finish_resume() callback is executed before the resume-callbacks of the PHY and glue layer are invoked. If I delay it until the glue layer resumed then I don't see this problem. I also move musb_host_resume_root_hub() into that callback since I don't see any reason in doing anything resume-link if there are still pieces not restored. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 4966a16..3345c94 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -478,13 +478,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, | MUSB_PORT_STAT_RESUME; musb->rh_timer = jiffies + msecs_to_jiffies(20); - schedule_delayed_work( - &musb->finish_resume_work, - msecs_to_jiffies(20)); + musb->need_finish_resume = 1; musb->xceiv->otg->state = OTG_STATE_A_HOST; musb->is_active = 1; - musb_host_resume_root_hub(musb); break; case OTG_STATE_B_WAIT_ACON: musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; @@ -2319,6 +2316,11 @@ static int musb_resume(struct device *dev) mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV; if ((devctl & mask) != (musb->context.devctl & mask)) musb->port1_status = 0; + if (musb->need_finish_resume) { + musb->need_finish_resume = 0; + schedule_delayed_work(&musb->finish_resume_work, + msecs_to_jiffies(20)); + } return 0; } diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 414e57a..803a997 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -390,6 +390,7 @@ struct musb { /* is_suspended means USB B_PERIPHERAL suspend */ unsigned is_suspended:1; + unsigned need_finish_resume :1; /* may_wakeup means remote wakeup is enabled */ unsigned may_wakeup:1; diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index a133bd8c..b072420 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -72,6 +72,7 @@ void musb_host_finish_resume(struct work_struct *work) musb->xceiv->otg->state = OTG_STATE_A_HOST; spin_unlock_irqrestore(&musb->lock, flags); + musb_host_resume_root_hub(musb); } void musb_port_suspend(struct musb *musb, bool do_suspend) -- cgit v0.10.2 From 5eb125b55c8cf6cf6fa1ed7b84a7eeefc7a993aa Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 4 Nov 2014 10:37:30 +0900 Subject: usb: dwc3: ep0: remove unnecessary break after return Fix the following checkpatch warning. WARNING: break is not useful after a goto or return Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 4c86772..baeedbd 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -443,7 +443,6 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, case USB_DEVICE_LTM_ENABLE: return -EINVAL; - break; case USB_DEVICE_TEST_MODE: if ((wIndex & 0xff) != 0) @@ -552,7 +551,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) switch (state) { case USB_STATE_DEFAULT: return -EINVAL; - break; case USB_STATE_ADDRESS: ret = dwc3_ep0_delegate_req(dwc, ctrl); -- cgit v0.10.2 From cb0a59f541337e646fcea15628eb46866fedb8a3 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:16:28 +0200 Subject: usb: gadget: Kconfig: enable separate compilation of uac1/uac2 functions uac1 and uac2 functions are available through the configfs interface and it should be possible to build them without building their legacy gadgets. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c4880fc..c8a0784 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -362,6 +362,37 @@ config USB_CONFIGFS_F_FS implemented in kernel space (for instance Ethernet, serial or mass storage) and other are implemented in user space. +config USB_CONFIGFS_F_UAC1 + boolean "Audio Class 1.0" + depends on USB_CONFIGFS + depends on SND + select USB_LIBCOMPOSITE + select SND_PCM + select USB_F_UAC1 + help + This Audio function implements 1 AudioControl interface, + 1 AudioStreaming Interface each for USB-OUT and USB-IN. + This driver requires a real Audio codec to be present + on the device. + +config USB_CONFIGFS_F_UAC2 + boolean "Audio Class 2.0" + depends on USB_CONFIGFS + depends on SND + select USB_LIBCOMPOSITE + select SND_PCM + select USB_F_UAC2 + help + This Audio function is compatible with USB Audio Class + specification 2.0. It implements 1 AudioControl interface, + 1 AudioStreaming Interface each for USB-OUT and USB-IN. + This driver doesn't expect any real Audio codec to be present + on the device - the audio streams are simply sinked to and + sourced from a virtual ALSA sound card created. The user-space + application may choose to do whatever it wants with the data + received from the USB Host and choose to provide whatever it + wants as audio data to the USB Host. + source "drivers/usb/gadget/legacy/Kconfig" endchoice -- cgit v0.10.2 From 6e58ed578e2c65442b7a02deecc96e482c701654 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:25 +0200 Subject: usb: gadget: f_midi: enable use of the index parameter The soundcard index to use for the ALSA device creation is passed as a parameter to f_midi_bind_config(), but is assigned to midi->index only after the call to f_midi_register_card(midi). So no matter what is passed to f_midi_bind_config(), the actual index for snd_card_new() is always 0. This probably works ok if at the moment of f_midi's bind there are no other snd_cards, but if there are, it is not possible to bind f_midi. This patch moves the assignment to a place before the call to f_midi_register_card(midi). Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 807b31c..bf32957 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -954,6 +954,7 @@ int __init f_midi_bind_config(struct usb_configuration *c, /* set up ALSA midi devices */ midi->in_ports = in_ports; midi->out_ports = out_ports; + midi->index = index; status = f_midi_register_card(midi); if (status < 0) goto setup_fail; @@ -966,7 +967,6 @@ int __init f_midi_bind_config(struct usb_configuration *c, midi->func.disable = f_midi_disable; midi->id = kstrdup(id, GFP_KERNEL); - midi->index = index; midi->buflen = buflen; midi->qlen = qlen; -- cgit v0.10.2 From d23b4c3ee2d5cbdeaec9f8e7d8a9bdcc73836fb9 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:26 +0200 Subject: usb: gadget: f_midi: check kstrdup() return value kstrdup() might fail, so check its return value and react appropriately. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index bf32957..a920eee 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -654,6 +654,14 @@ static struct snd_rawmidi_ops gmidi_out_ops = { .trigger = f_midi_out_trigger }; +static inline void f_midi_unregister_card(struct f_midi *midi) +{ + if (midi->card) { + snd_card_free(midi->card); + midi->card = NULL; + } +} + /* register as a sound "card" */ static int f_midi_register_card(struct f_midi *midi) { @@ -715,10 +723,7 @@ static int f_midi_register_card(struct f_midi *midi) return 0; fail: - if (midi->card) { - snd_card_free(midi->card); - midi->card = NULL; - } + f_midi_unregister_card(midi); return err; } @@ -967,15 +972,23 @@ int __init f_midi_bind_config(struct usb_configuration *c, midi->func.disable = f_midi_disable; midi->id = kstrdup(id, GFP_KERNEL); + if (id && !midi->id) { + status = -ENOMEM; + goto kstrdup_fail; + } midi->buflen = buflen; midi->qlen = qlen; status = usb_add_function(c, &midi->func); if (status) - goto setup_fail; + goto add_fail; return 0; +add_fail: + kfree(midi->id); +kstrdup_fail: + f_midi_unregister_card(midi); setup_fail: for (--i; i >= 0; i--) kfree(midi->in_port[i]); -- cgit v0.10.2 From b85e9de9e818de0dcbc50b7b4242192eb6194855 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:27 +0200 Subject: usb: gadget: f_midi: convert to new function interface with backward compatibility Converting midi to the new function interface requires converting the USB midi's function code and its users. This patch converts the f_midi.c to the new function interface. The file can now be compiled into a separate usb_f_midi.ko module. The old function interface is provided by means of a preprocessor conditional directives. After all users are converted, the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c8a0784..b513078 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -190,6 +190,9 @@ config USB_F_UAC2 config USB_F_UVC tristate +config USB_F_MIDI + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 90701aa..576eea5 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -38,3 +38,5 @@ usb_f_uac2-y := f_uac2.o obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o +usb_f_midi-y := f_midi.o +obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index a920eee..f3e7d95 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -33,6 +34,7 @@ #include #include "u_f.h" +#include "u_midi.h" MODULE_AUTHOR("Ben Williamson"); MODULE_LICENSE("GPL v2"); @@ -99,7 +101,7 @@ DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16); /* B.3.1 Standard AC Interface Descriptor */ -static struct usb_interface_descriptor ac_interface_desc __initdata = { +static struct usb_interface_descriptor ac_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, /* .bInterfaceNumber = DYNAMIC */ @@ -110,7 +112,7 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = { }; /* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = { +static struct uac1_ac_header_descriptor_1 ac_header_desc = { .bLength = UAC_DT_AC_HEADER_SIZE(1), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, @@ -121,7 +123,7 @@ static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = { }; /* B.4.1 Standard MS Interface Descriptor */ -static struct usb_interface_descriptor ms_interface_desc __initdata = { +static struct usb_interface_descriptor ms_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, /* .bInterfaceNumber = DYNAMIC */ @@ -132,7 +134,7 @@ static struct usb_interface_descriptor ms_interface_desc __initdata = { }; /* B.4.2 Class-Specific MS Interface Descriptor */ -static struct usb_ms_header_descriptor ms_header_desc __initdata = { +static struct usb_ms_header_descriptor ms_header_desc = { .bLength = USB_DT_MS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, @@ -387,6 +389,7 @@ static void f_midi_disable(struct usb_function *f) usb_ep_disable(midi->out_ep); } +#ifdef USBF_MIDI_INCLUDED static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = f->config->cdev; @@ -409,6 +412,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) usb_free_all_descriptors(f); kfree(midi); } +#endif static int f_midi_snd_free(struct snd_device *device) { @@ -729,8 +733,7 @@ fail: /* MIDI function driver setup/binding */ -static int __init -f_midi_bind(struct usb_configuration *c, struct usb_function *f) +static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_descriptor_header **midi_function; struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS]; @@ -741,6 +744,14 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) struct f_midi *midi = func_to_midi(f); int status, n, jack = 1, i = 0; +#ifndef USBF_MIDI_INCLUDED + midi->gadget = cdev->gadget; + tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); + status = f_midi_register_card(midi); + if (status < 0) + goto fail_register; + +#endif /* maybe allocate device-global string ID */ if (midi_string_defs[0].id == 0) { status = usb_string_id(c->cdev); @@ -897,6 +908,10 @@ fail_f_midi: kfree(midi_function); usb_free_descriptors(f->hs_descriptors); fail: +#ifndef USBF_MIDI_INCLUDED + f_midi_unregister_card(midi); +fail_register: +#endif /* we might as well release our claims on endpoints */ if (midi->out_ep) midi->out_ep->driver_data = NULL; @@ -908,6 +923,7 @@ fail: return status; } +#ifdef USBF_MIDI_INCLUDED /** * f_midi_bind_config - add USB MIDI function to a configuration * @c: the configuration to supcard the USB audio function @@ -997,3 +1013,122 @@ fail: return status; } +#else + +static void f_midi_free_inst(struct usb_function_instance *f) +{ + struct f_midi_opts *opts; + + opts = container_of(f, struct f_midi_opts, func_inst); + + kfree(opts); +} + +static struct usb_function_instance *f_midi_alloc_inst(void) +{ + struct f_midi_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + opts->func_inst.free_func_inst = f_midi_free_inst; + + return &opts->func_inst; +} + +static void f_midi_free(struct usb_function *f) +{ + struct f_midi *midi; + struct f_midi_opts *opts; + int i; + + midi = func_to_midi(f); + opts = container_of(f->fi, struct f_midi_opts, func_inst); + kfree(midi->id); + for (i = opts->in_ports - 1; i >= 0; --i) + kfree(midi->in_port[i]); + kfree(midi); +} + +static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = f->config->cdev; + struct f_midi *midi = func_to_midi(f); + struct snd_card *card; + + DBG(cdev, "unbind\n"); + + /* just to be sure */ + f_midi_disable(f); + + card = midi->card; + midi->card = NULL; + if (card) + snd_card_free(card); + + usb_free_all_descriptors(f); +} + +struct usb_function *f_midi_alloc(struct usb_function_instance *fi) +{ + struct f_midi *midi; + struct f_midi_opts *opts; + int status, i; + + opts = container_of(fi, struct f_midi_opts, func_inst); + /* sanity check */ + if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) + return ERR_PTR(-EINVAL); + + /* allocate and initialize one new instance */ + midi = kzalloc(sizeof(*midi), GFP_KERNEL); + if (!midi) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < opts->in_ports; i++) { + struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); + + if (!port) { + status = -ENOMEM; + goto setup_fail; + } + + port->midi = midi; + port->active = 0; + port->cable = i; + midi->in_port[i] = port; + } + + /* set up ALSA midi devices */ + midi->id = kstrdup(opts->id, GFP_KERNEL); + if (opts->id && !midi->id) { + status = -ENOMEM; + goto kstrdup_fail; + } + midi->in_ports = opts->in_ports; + midi->out_ports = opts->out_ports; + midi->index = opts->index; + midi->buflen = opts->buflen; + midi->qlen = opts->qlen; + + midi->func.name = "gmidi function"; + midi->func.strings = midi_strings; + midi->func.bind = f_midi_bind; + midi->func.unbind = f_midi_unbind; + midi->func.set_alt = f_midi_set_alt; + midi->func.disable = f_midi_disable; + midi->func.free_func = f_midi_free; + + return &midi->func; + +kstrdup_fail: + f_midi_unregister_card(midi); +setup_fail: + for (--i; i >= 0; i--) + kfree(midi->in_port[i]); + kfree(midi); + return ERR_PTR(status); +} + +DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc); +#endif diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h new file mode 100644 index 0000000..76bccc1 --- /dev/null +++ b/drivers/usb/gadget/function/u_midi.h @@ -0,0 +1,32 @@ +/* + * u_midi.h + * + * Utility definitions for the midi function + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz + * + * 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 U_MIDI_H +#define U_MIDI_H + +#include + +struct f_midi_opts { + struct usb_function_instance func_inst; + int index; + char *id; + unsigned int in_ports; + unsigned int out_ports; + unsigned int buflen; + unsigned int qlen; +}; + +#endif /* U_MIDI_H */ + diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index 3d696b8..f704c55 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -37,6 +37,7 @@ #include "gadget_chips.h" +#define USBF_MIDI_INCLUDED #include "f_midi.c" /*-------------------------------------------------------------------------*/ -- cgit v0.10.2 From 32522a51c7f44a48dc298fce738795dca5c8fcd6 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:28 +0200 Subject: usb: gadget: midi: convert to new interface of f_midi Use the new f_midi interface so that the old can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 24392d2..8011b19 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -287,6 +287,7 @@ config USB_MIDI_GADGET depends on SND select USB_LIBCOMPOSITE select SND_RAWMIDI + select USB_F_MIDI help The MIDI Gadget acts as a USB Audio device, with one MIDI input and one MIDI output. These MIDI jacks appear as diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index f704c55..0d01e46 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -37,8 +37,7 @@ #include "gadget_chips.h" -#define USBF_MIDI_INCLUDED -#include "f_midi.c" +#include "u_midi.h" /*-------------------------------------------------------------------------*/ @@ -116,8 +115,13 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; +struct usb_function_instance *fi_midi; +struct usb_function *f_midi; + static int __exit midi_unbind(struct usb_composite_dev *dev) { + usb_put_function(f_midi); + usb_put_function_instance(fi_midi); return 0; } @@ -131,28 +135,54 @@ static struct usb_configuration midi_config = { static int __init midi_bind_config(struct usb_configuration *c) { - return f_midi_bind_config(c, index, id, - in_ports, out_ports, - buflen, qlen); + int status; + + f_midi = usb_get_function(fi_midi); + if (IS_ERR(f_midi)) + return PTR_ERR(f_midi); + + status = usb_add_function(c, f_midi); + if (status < 0) { + usb_put_function(f_midi); + return status; + } + + return 0; } static int __init midi_bind(struct usb_composite_dev *cdev) { + struct f_midi_opts *midi_opts; int status; + fi_midi = usb_get_function_instance("midi"); + if (IS_ERR(fi_midi)) + return PTR_ERR(fi_midi); + + midi_opts = container_of(fi_midi, struct f_midi_opts, func_inst); + midi_opts->index = index; + midi_opts->id = id; + midi_opts->in_ports = in_ports; + midi_opts->out_ports = out_ports; + midi_opts->buflen = buflen; + midi_opts->qlen = qlen; + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) - return status; + goto put; device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; midi_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id; status = usb_add_config(cdev, &midi_config, midi_bind_config); if (status < 0) - return status; + goto put; usb_composite_overwrite_options(cdev, &coverwrite); pr_info("%s\n", longname); return 0; +put: + usb_put_function_instance(fi_midi); + return status; } static __refdata struct usb_composite_driver midi_driver = { -- cgit v0.10.2 From 33cfad66efbb72de0ebe72f554b31b6688957052 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:29 +0200 Subject: usb: gadget: f_midi: remove compatibility layer There are no old f_midi interface users left, so remove it. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index f3e7d95..5cd77be 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -389,31 +389,6 @@ static void f_midi_disable(struct usb_function *f) usb_ep_disable(midi->out_ep); } -#ifdef USBF_MIDI_INCLUDED -static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = f->config->cdev; - struct f_midi *midi = func_to_midi(f); - struct snd_card *card; - - DBG(cdev, "unbind\n"); - - /* just to be sure */ - f_midi_disable(f); - - card = midi->card; - midi->card = NULL; - if (card) - snd_card_free(card); - - kfree(midi->id); - midi->id = NULL; - - usb_free_all_descriptors(f); - kfree(midi); -} -#endif - static int f_midi_snd_free(struct snd_device *device) { return 0; @@ -744,14 +719,12 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) struct f_midi *midi = func_to_midi(f); int status, n, jack = 1, i = 0; -#ifndef USBF_MIDI_INCLUDED midi->gadget = cdev->gadget; tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); status = f_midi_register_card(midi); if (status < 0) goto fail_register; -#endif /* maybe allocate device-global string ID */ if (midi_string_defs[0].id == 0) { status = usb_string_id(c->cdev); @@ -908,10 +881,8 @@ fail_f_midi: kfree(midi_function); usb_free_descriptors(f->hs_descriptors); fail: -#ifndef USBF_MIDI_INCLUDED f_midi_unregister_card(midi); fail_register: -#endif /* we might as well release our claims on endpoints */ if (midi->out_ep) midi->out_ep->driver_data = NULL; @@ -923,98 +894,6 @@ fail_register: return status; } -#ifdef USBF_MIDI_INCLUDED -/** - * f_midi_bind_config - add USB MIDI function to a configuration - * @c: the configuration to supcard the USB audio function - * @index: the soundcard index to use for the ALSA device creation - * @id: the soundcard id to use for the ALSA device creation - * @buflen: the buffer length to use - * @qlen the number of read requests to pre-allocate - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - */ -int __init f_midi_bind_config(struct usb_configuration *c, - int index, char *id, - unsigned int in_ports, - unsigned int out_ports, - unsigned int buflen, - unsigned int qlen) -{ - struct f_midi *midi; - int status, i; - - /* sanity check */ - if (in_ports > MAX_PORTS || out_ports > MAX_PORTS) - return -EINVAL; - - /* allocate and initialize one new instance */ - midi = kzalloc(sizeof *midi, GFP_KERNEL); - if (!midi) { - status = -ENOMEM; - goto fail; - } - - for (i = 0; i < in_ports; i++) { - struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); - if (!port) { - status = -ENOMEM; - goto setup_fail; - } - - port->midi = midi; - port->active = 0; - port->cable = i; - midi->in_port[i] = port; - } - - midi->gadget = c->cdev->gadget; - tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); - - /* set up ALSA midi devices */ - midi->in_ports = in_ports; - midi->out_ports = out_ports; - midi->index = index; - status = f_midi_register_card(midi); - if (status < 0) - goto setup_fail; - - midi->func.name = "gmidi function"; - midi->func.strings = midi_strings; - midi->func.bind = f_midi_bind; - midi->func.unbind = f_midi_unbind; - midi->func.set_alt = f_midi_set_alt; - midi->func.disable = f_midi_disable; - - midi->id = kstrdup(id, GFP_KERNEL); - if (id && !midi->id) { - status = -ENOMEM; - goto kstrdup_fail; - } - midi->buflen = buflen; - midi->qlen = qlen; - - status = usb_add_function(c, &midi->func); - if (status) - goto add_fail; - - return 0; - -add_fail: - kfree(midi->id); -kstrdup_fail: - f_midi_unregister_card(midi); -setup_fail: - for (--i; i >= 0; i--) - kfree(midi->in_port[i]); - kfree(midi); -fail: - return status; -} - -#else - static void f_midi_free_inst(struct usb_function_instance *f) { struct f_midi_opts *opts; @@ -1131,4 +1010,3 @@ setup_fail: } DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc); -#endif -- cgit v0.10.2 From 9caa0d77f7ce6ca0ec6bb81e28a93db1b6287b0f Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:30 +0200 Subject: usb: gadget: f_midi: use usb_gstrings_attach In order to add configfs support the usb_gstrings_attach must be used. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 5cd77be..ec2a9ce 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -717,6 +717,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS]; struct usb_composite_dev *cdev = c->cdev; struct f_midi *midi = func_to_midi(f); + struct usb_string *us; int status, n, jack = 1, i = 0; midi->gadget = cdev->gadget; @@ -726,12 +727,13 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail_register; /* maybe allocate device-global string ID */ - if (midi_string_defs[0].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - goto fail; - midi_string_defs[0].id = status; + us = usb_gstrings_attach(c->cdev, midi_strings, + ARRAY_SIZE(midi_string_defs)); + if (IS_ERR(us)) { + status = PTR_ERR(us); + goto fail; } + ac_interface_desc.iInterface = us[STRING_FUNC_IDX].id; /* We have two interfaces, AudioControl and MIDIStreaming */ status = usb_interface_id(c, f); @@ -991,7 +993,6 @@ struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->qlen = opts->qlen; midi->func.name = "gmidi function"; - midi->func.strings = midi_strings; midi->func.bind = f_midi_bind; midi->func.unbind = f_midi_unbind; midi->func.set_alt = f_midi_set_alt; -- cgit v0.10.2 From 6f1de344557315a8e5de0d15a28276198ca7fdac Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 16 Oct 2014 13:33:31 +0200 Subject: usb: gadget: f_midi: add configfs support Make the midi function available for gadgets composed with configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/testing/configfs-usb-gadget-midi b/Documentation/ABI/testing/configfs-usb-gadget-midi new file mode 100644 index 0000000..6b341df --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-midi @@ -0,0 +1,12 @@ +What: /config/usb-gadget/gadget/functions/midi.name +Date: Nov 2014 +KernelVersion: 3.19 +Description: + The attributes: + + index - index value for the USB MIDI adapter + id - ID string for the USB MIDI adapter + buflen - MIDI buffer length + qlen - USB read request queue length + in_ports - number of MIDI input ports + out_ports - number of MIDI output ports diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b513078..501c2a3 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -396,6 +396,20 @@ config USB_CONFIGFS_F_UAC2 received from the USB Host and choose to provide whatever it wants as audio data to the USB Host. +config USB_CONFIGFS_F_MIDI + boolean "MIDI function" + depends on USB_CONFIGFS + depends on SND + select USB_LIBCOMPOSITE + select SND_RAWMIDI + select USB_F_MIDI + help + The MIDI Function acts as a USB Audio device, with one MIDI + input and one MIDI output. These MIDI jacks appear as + a sound "card" in the ALSA sound system. Other MIDI + connections can then be made on the gadget system, using + ALSA's aconnect utility etc. + source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index ec2a9ce..1f94dad 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -896,12 +896,145 @@ fail_register: return status; } +static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_midi_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_midi_opts); +CONFIGFS_ATTR_OPS(f_midi_opts); + +static void midi_attr_release(struct config_item *item) +{ + struct f_midi_opts *opts = to_f_midi_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations midi_item_ops = { + .release = midi_attr_release, + .show_attribute = f_midi_opts_attr_show, + .store_attribute = f_midi_opts_attr_store, +}; + +#define F_MIDI_OPT(name, test_limit, limit) \ +static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \ +{ \ + int result; \ + \ + mutex_lock(&opts->lock); \ + result = sprintf(page, "%d\n", opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_midi_opts_##name##_store(struct f_midi_opts *opts, \ + const char *page, size_t len) \ +{ \ + int ret; \ + u32 num; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = kstrtou32(page, 0, &num); \ + if (ret) \ + goto end; \ + \ + if (test_limit && num > limit) { \ + ret = -EINVAL; \ + goto end; \ + } \ + opts->name = num; \ + ret = len; \ + \ +end: \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +static struct f_midi_opts_attribute f_midi_opts_##name = \ + __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_midi_opts_##name##_show, \ + f_midi_opts_##name##_store) + +F_MIDI_OPT(index, true, SNDRV_CARDS); +F_MIDI_OPT(buflen, false, 0); +F_MIDI_OPT(qlen, false, 0); +F_MIDI_OPT(in_ports, true, MAX_PORTS); +F_MIDI_OPT(out_ports, true, MAX_PORTS); + +static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = strlcpy(page, opts->id, PAGE_SIZE); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_midi_opts_id_store(struct f_midi_opts *opts, + const char *page, size_t len) +{ + int ret; + char *c; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + c = kstrndup(page, len, GFP_KERNEL); + if (!c) { + ret = -ENOMEM; + goto end; + } + if (opts->id_allocated) + kfree(opts->id); + opts->id = c; + opts->id_allocated = true; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_midi_opts_attribute f_midi_opts_id = + __CONFIGFS_ATTR(id, S_IRUGO | S_IWUSR, f_midi_opts_id_show, + f_midi_opts_id_store); + +static struct configfs_attribute *midi_attrs[] = { + &f_midi_opts_index.attr, + &f_midi_opts_buflen.attr, + &f_midi_opts_qlen.attr, + &f_midi_opts_in_ports.attr, + &f_midi_opts_out_ports.attr, + &f_midi_opts_id.attr, + NULL, +}; + +static struct config_item_type midi_func_type = { + .ct_item_ops = &midi_item_ops, + .ct_attrs = midi_attrs, + .ct_owner = THIS_MODULE, +}; + static void f_midi_free_inst(struct usb_function_instance *f) { struct f_midi_opts *opts; opts = container_of(f, struct f_midi_opts, func_inst); + if (opts->id_allocated) + kfree(opts->id); + kfree(opts); } @@ -912,7 +1045,18 @@ static struct usb_function_instance *f_midi_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); + + mutex_init(&opts->lock); opts->func_inst.free_func_inst = f_midi_free_inst; + opts->index = SNDRV_DEFAULT_IDX1; + opts->id = SNDRV_DEFAULT_STR1; + opts->buflen = 256; + opts->qlen = 32; + opts->in_ports = 1; + opts->out_ports = 1; + + config_group_init_type_name(&opts->func_inst.group, "", + &midi_func_type); return &opts->func_inst; } @@ -926,9 +1070,12 @@ static void f_midi_free(struct usb_function *f) midi = func_to_midi(f); opts = container_of(f->fi, struct f_midi_opts, func_inst); kfree(midi->id); + mutex_lock(&opts->lock); for (i = opts->in_ports - 1; i >= 0; --i) kfree(midi->in_port[i]); kfree(midi); + --opts->refcnt; + mutex_unlock(&opts->lock); } static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) @@ -957,20 +1104,27 @@ struct usb_function *f_midi_alloc(struct usb_function_instance *fi) int status, i; opts = container_of(fi, struct f_midi_opts, func_inst); + + mutex_lock(&opts->lock); /* sanity check */ - if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) + if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) { + mutex_unlock(&opts->lock); return ERR_PTR(-EINVAL); + } /* allocate and initialize one new instance */ midi = kzalloc(sizeof(*midi), GFP_KERNEL); - if (!midi) + if (!midi) { + mutex_unlock(&opts->lock); return ERR_PTR(-ENOMEM); + } for (i = 0; i < opts->in_ports; i++) { struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) { status = -ENOMEM; + mutex_unlock(&opts->lock); goto setup_fail; } @@ -984,6 +1138,7 @@ struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->id = kstrdup(opts->id, GFP_KERNEL); if (opts->id && !midi->id) { status = -ENOMEM; + mutex_unlock(&opts->lock); goto kstrdup_fail; } midi->in_ports = opts->in_ports; @@ -991,6 +1146,8 @@ struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->index = opts->index; midi->buflen = opts->buflen; midi->qlen = opts->qlen; + ++opts->refcnt; + mutex_unlock(&opts->lock); midi->func.name = "gmidi function"; midi->func.bind = f_midi_bind; diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h index 76bccc1..2251018 100644 --- a/drivers/usb/gadget/function/u_midi.h +++ b/drivers/usb/gadget/function/u_midi.h @@ -22,10 +22,18 @@ struct f_midi_opts { struct usb_function_instance func_inst; int index; char *id; + bool id_allocated; unsigned int in_ports; unsigned int out_ports; unsigned int buflen; unsigned int qlen; + + /* + * Protect the data form concurrent access by read/write + * and create symlink/remove symlink. + */ + struct mutex lock; + int refcnt; }; #endif /* U_MIDI_H */ -- cgit v0.10.2 From 79018420441bbbc2b567d891fc3d12ad69f1cd5f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 10 Oct 2014 00:02:12 +0400 Subject: usb: phy: remove file names from heading comments File names in the heading comments fell out of favor long ago, and these weren't even changed when the drivers were moved from drivers/usb/otg/, so remove them at last... Signed-off-by: Sergei Shtylyov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 3a802fa..30c96f0 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -1,6 +1,4 @@ /* - * drivers/usb/otg/ab8500_usb.c - * * USB transceiver driver for AB8500 family chips * * Copyright (C) 2010-2013 ST-Ericsson AB diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 0c01bd1..4ba1f57 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -1,6 +1,4 @@ /* - * drivers/usb/otg/nop-usb-xceiv.c - * * NOP USB transceiver for all USB transceiver which are either built-in * into USB IP or which are mostly autonomous. * -- cgit v0.10.2 From 06529407329841ed836b30e4a99905a522ffa323 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:11:56 +0100 Subject: usb: gadget: f_hid: check return value of class_create class_create() might fail, so check its return value and react appropriately. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 59ab62c..f3b3e19 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -742,6 +742,10 @@ int __init ghid_setup(struct usb_gadget *g, int count) dev_t dev; hidg_class = class_create(THIS_MODULE, "hidg"); + if (IS_ERR(hidg_class)) { + hidg_class = NULL; + return PTR_ERR(hidg_class); + } status = alloc_chrdev_region(&dev, 0, count, "hidg"); if (!status) { -- cgit v0.10.2 From 634060870afbfbe37a567f35b78da9b74e81ad84 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:11:57 +0100 Subject: usb: gadget: f_hid: check return value of device_create device_create() might fail, so check its return value and react appropriately. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index f3b3e19..ad53881 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -556,6 +556,7 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_ep *ep; struct f_hidg *hidg = func_to_hidg(f); + struct device *device; int status; dev_t dev; @@ -623,10 +624,16 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail_free_descs; - device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor); + device = device_create(hidg_class, NULL, dev, NULL, + "%s%d", "hidg", hidg->minor); + if (IS_ERR(device)) { + status = PTR_ERR(device); + goto del; + } return 0; - +del: + cdev_del(&hidg->cdev); fail_free_descs: usb_free_all_descriptors(f); fail: -- cgit v0.10.2 From 00896f66f5032e5f53874a76e02cdad09f7ff90b Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:11:58 +0100 Subject: usb: gadget: hid: mirror init operations in module cleanup So far platform driver has been unregistered first, so just after that the usb composite is still available, but there is no hid data any more. Reverse the order so that first the usb composite becomes unavailable and second the hid data goes away. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index 778613eb..fba80a2 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -260,7 +260,7 @@ module_init(hidg_init); static void __exit hidg_cleanup(void) { - platform_driver_unregister(&hidg_plat_driver); usb_composite_unregister(&hidg_driver); + platform_driver_unregister(&hidg_plat_driver); } module_exit(hidg_cleanup); -- cgit v0.10.2 From cb382536052fcc7713988869b54a81137069e5a9 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:11:59 +0100 Subject: usb: gadget: f_hid: convert to new function interface with backward compatibility Converting hid to the new function interface requires converting the USB hid's function code and its users. This patch converts the f_hid.c to the new function interface. The file can now be compiled into a separate usb_f_hid.ko module. The old function interface is provided by means of a preprocessor conditional directives. After all users are converted, the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 501c2a3..ea2d770 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -193,6 +193,9 @@ config USB_F_UVC config USB_F_MIDI tristate +config USB_F_HID + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 576eea5..dd68091 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -40,3 +40,5 @@ usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o usb_f_midi-y := f_midi.o obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o +usb_f_hid-y := f_hid.o +obj-$(CONFIG_USB_F_HID) += usb_f_hid.o diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index ad53881..f5dcf94 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,9 +22,16 @@ #include #include "u_f.h" +#include "u_hid.h" + +#define HIDG_MINORS 4 static int major, minors; static struct class *hidg_class; +#ifndef USBF_HID_INCLUDED +static DEFINE_IDA(hidg_ida); +static DEFINE_MUTEX(hidg_ida_lock); /* protects access to hidg_ida */ +#endif /*-------------------------------------------------------------------------*/ /* HID gadget struct */ @@ -161,6 +169,26 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = { }; /*-------------------------------------------------------------------------*/ +/* Strings */ + +#define CT_FUNC_HID_IDX 0 + +static struct usb_string ct_func_string_defs[] = { + [CT_FUNC_HID_IDX].s = "HID Interface", + {}, /* end of list */ +}; + +static struct usb_gadget_strings ct_func_string_table = { + .language = 0x0409, /* en-US */ + .strings = ct_func_string_defs, +}; + +static struct usb_gadget_strings *ct_func_strings[] = { + &ct_func_string_table, + NULL, +}; + +/*-------------------------------------------------------------------------*/ /* Char Device */ static ssize_t f_hidg_read(struct file *file, char __user *buffer, @@ -552,7 +580,7 @@ const struct file_operations f_hidg_fops = { .llseek = noop_llseek, }; -static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) +static int hidg_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_ep *ep; struct f_hidg *hidg = func_to_hidg(f); @@ -560,6 +588,15 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) int status; dev_t dev; + /* maybe allocate device-global string IDs, and patch descriptors */ + if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) { + status = usb_string_id(c->cdev); + if (status < 0) + return status; + ct_func_string_defs[CT_FUNC_HID_IDX].id = status; + hidg_interface_desc.iInterface = status; + } + /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) @@ -647,6 +684,7 @@ fail: return status; } +#ifdef USBF_HID_INCLUDED static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_hidg *hidg = func_to_hidg(f); @@ -667,28 +705,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) } /*-------------------------------------------------------------------------*/ -/* Strings */ - -#define CT_FUNC_HID_IDX 0 - -static struct usb_string ct_func_string_defs[] = { - [CT_FUNC_HID_IDX].s = "HID Interface", - {}, /* end of list */ -}; - -static struct usb_gadget_strings ct_func_string_table = { - .language = 0x0409, /* en-US */ - .strings = ct_func_string_defs, -}; - -static struct usb_gadget_strings *ct_func_strings[] = { - &ct_func_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ /* usb_configuration */ - int __init hidg_bind_config(struct usb_configuration *c, struct hidg_func_descriptor *fdesc, int index) { @@ -698,15 +715,6 @@ int __init hidg_bind_config(struct usb_configuration *c, if (index >= minors) return -ENOENT; - /* maybe allocate device-global string IDs, and patch descriptors */ - if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ct_func_string_defs[CT_FUNC_HID_IDX].id = status; - hidg_interface_desc.iInterface = status; - } - /* allocate and initialize one new instance */ hidg = kzalloc(sizeof *hidg, GFP_KERNEL); if (!hidg) @@ -743,7 +751,153 @@ int __init hidg_bind_config(struct usb_configuration *c, return status; } -int __init ghid_setup(struct usb_gadget *g, int count) +#else + +static inline int hidg_get_minor(void) +{ + int ret; + + ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL); + + return ret; +} + +static inline void hidg_put_minor(int minor) +{ + ida_simple_remove(&hidg_ida, minor); +} + +static void hidg_free_inst(struct usb_function_instance *f) +{ + struct f_hid_opts *opts; + + opts = container_of(f, struct f_hid_opts, func_inst); + + mutex_lock(&hidg_ida_lock); + + hidg_put_minor(opts->minor); + if (idr_is_empty(&hidg_ida.idr)) + ghid_cleanup(); + + mutex_unlock(&hidg_ida_lock); + + if (opts->report_desc_alloc) + kfree(opts->report_desc); + + kfree(opts); +} + +static struct usb_function_instance *hidg_alloc_inst(void) +{ + struct f_hid_opts *opts; + struct usb_function_instance *ret; + int status = 0; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = hidg_free_inst; + ret = &opts->func_inst; + + mutex_lock(&hidg_ida_lock); + + if (idr_is_empty(&hidg_ida.idr)) { + status = ghid_setup(NULL, HIDG_MINORS); + if (status) { + ret = ERR_PTR(status); + kfree(opts); + goto unlock; + } + } + + opts->minor = hidg_get_minor(); + if (opts->minor < 0) { + ret = ERR_PTR(opts->minor); + kfree(opts); + if (idr_is_empty(&hidg_ida.idr)) + ghid_cleanup(); + } + +unlock: + mutex_unlock(&hidg_ida_lock); + return ret; +} + +static void hidg_free(struct usb_function *f) +{ + struct f_hidg *hidg; + + hidg = func_to_hidg(f); + kfree(hidg->report_desc); + kfree(hidg); +} + +static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_hidg *hidg = func_to_hidg(f); + + device_destroy(hidg_class, MKDEV(major, hidg->minor)); + cdev_del(&hidg->cdev); + + /* disable/free request and end point */ + usb_ep_disable(hidg->in_ep); + usb_ep_dequeue(hidg->in_ep, hidg->req); + kfree(hidg->req->buf); + usb_ep_free_request(hidg->in_ep, hidg->req); + + usb_free_all_descriptors(f); +} + +struct usb_function *hidg_alloc(struct usb_function_instance *fi) +{ + struct f_hidg *hidg; + struct f_hid_opts *opts; + + /* allocate and initialize one new instance */ + hidg = kzalloc(sizeof(*hidg), GFP_KERNEL); + if (!hidg) + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_hid_opts, func_inst); + + hidg->minor = opts->minor; + hidg->bInterfaceSubClass = opts->subclass; + hidg->bInterfaceProtocol = opts->protocol; + hidg->report_length = opts->report_length; + hidg->report_desc_length = opts->report_desc_length; + if (opts->report_desc) { + hidg->report_desc = kmemdup(opts->report_desc, + opts->report_desc_length, + GFP_KERNEL); + if (!hidg->report_desc) { + kfree(hidg); + return ERR_PTR(-ENOMEM); + } + } + + hidg->func.name = "hid"; + hidg->func.strings = ct_func_strings; + hidg->func.bind = hidg_bind; + hidg->func.unbind = hidg_unbind; + hidg->func.set_alt = hidg_set_alt; + hidg->func.disable = hidg_disable; + hidg->func.setup = hidg_setup; + hidg->func.free_func = hidg_free; + + /* this could me made configurable at some point */ + hidg->qlen = 4; + + return &hidg->func; +} + +DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Fabien Chouteau"); + +#endif + +int ghid_setup(struct usb_gadget *g, int count) { int status; dev_t dev; diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h new file mode 100644 index 0000000..3edfc95 --- /dev/null +++ b/drivers/usb/gadget/function/u_hid.h @@ -0,0 +1,35 @@ +/* + * u_hid.h + * + * Utility definitions for the hid function + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz + * + * 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 U_HID_H +#define U_HID_H + +#include + +struct f_hid_opts { + struct usb_function_instance func_inst; + int minor; + unsigned char subclass; + unsigned char protocol; + unsigned short report_length; + unsigned short report_desc_length; + unsigned char *report_desc; + bool report_desc_alloc; +}; + +int ghid_setup(struct usb_gadget *g, int count); +void ghid_cleanup(void); + +#endif /* U_HID_H */ diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index fba80a2..26cb4ea 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -36,6 +36,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#define USBF_HID_INCLUDED #include "f_hid.c" -- cgit v0.10.2 From 4bc8a33f2407975a5a40bd6adf86de815d2ce913 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:12:00 +0100 Subject: usb: gadget: hid: convert to new interface of f_hid Use the new f_hid interface in order for the old to be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 8011b19..fd48ef3 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -420,6 +420,7 @@ endif # TTY config USB_G_HID tristate "HID Gadget" select USB_LIBCOMPOSITE + select USB_F_HID help The HID gadget driver provides generic emulation of USB Human Interface Devices (HID). diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index 26cb4ea..633fe7e 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -17,11 +17,14 @@ #include #include #include +#include #include "gadget_chips.h" #define DRIVER_DESC "HID Gadget" #define DRIVER_VERSION "2010/03/16" +#include "u_hid.h" + /*-------------------------------------------------------------------------*/ #define HIDG_VENDOR_NUM 0x0525 /* XXX NetChip */ @@ -29,18 +32,9 @@ /*-------------------------------------------------------------------------*/ -/* - * kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#define USBF_HID_INCLUDED -#include "f_hid.c" - - struct hidg_func_node { + struct usb_function_instance *fi; + struct usb_function *f; struct list_head node; struct hidg_func_descriptor *func; }; @@ -114,8 +108,8 @@ static struct usb_gadget_strings *dev_strings[] = { static int __init do_config(struct usb_configuration *c) { - struct hidg_func_node *e; - int func = 0, status = 0; + struct hidg_func_node *e, *n; + int status = 0; if (gadget_is_otg(c->cdev->gadget)) { c->descriptors = otg_desc; @@ -123,11 +117,24 @@ static int __init do_config(struct usb_configuration *c) } list_for_each_entry(e, &hidg_func_list, node) { - status = hidg_bind_config(c, e->func, func++); - if (status) - break; + e->f = usb_get_function(e->fi); + if (IS_ERR(e->f)) + goto put; + status = usb_add_function(c, e->f); + if (status < 0) { + usb_put_function(e->f); + goto put; + } } + return 0; +put: + list_for_each_entry(n, &hidg_func_list, node) { + if (n == e) + break; + usb_remove_function(c, n->f); + usb_put_function(n->f); + } return status; } @@ -144,6 +151,8 @@ static int __init hid_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct list_head *tmp; + struct hidg_func_node *n, *m; + struct f_hid_opts *hid_opts; int status, funcs = 0; list_for_each(tmp, &hidg_func_list) @@ -152,10 +161,20 @@ static int __init hid_bind(struct usb_composite_dev *cdev) if (!funcs) return -ENODEV; - /* set up HID */ - status = ghid_setup(cdev->gadget, funcs); - if (status < 0) - return status; + list_for_each_entry(n, &hidg_func_list, node) { + n->fi = usb_get_function_instance("hid"); + if (IS_ERR(n->fi)) { + status = PTR_ERR(n->fi); + goto put; + } + hid_opts = container_of(n->fi, struct f_hid_opts, func_inst); + hid_opts->subclass = n->func->subclass; + hid_opts->protocol = n->func->protocol; + hid_opts->report_length = n->func->report_length; + hid_opts->report_desc_length = n->func->report_desc_length; + hid_opts->report_desc = n->func->report_desc; + } + /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. @@ -163,24 +182,37 @@ static int __init hid_bind(struct usb_composite_dev *cdev) status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) - return status; + goto put; device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register our configuration */ status = usb_add_config(cdev, &config_driver, do_config); if (status < 0) - return status; + goto put; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); return 0; + +put: + list_for_each_entry(m, &hidg_func_list, node) { + if (m == n) + break; + usb_put_function_instance(m->fi); + } + return status; } static int __exit hid_unbind(struct usb_composite_dev *cdev) { - ghid_cleanup(); + struct hidg_func_node *n; + + list_for_each_entry(n, &hidg_func_list, node) { + usb_put_function(n->f); + usb_put_function_instance(n->fi); + } return 0; } -- cgit v0.10.2 From 5d66a39102b1c18494bb3801100a5fb3cf7e5bdb Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:12:01 +0100 Subject: usb: gadget: f_hid: remove compatibility layer There are no old function interface users left, so remove it. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index f5dcf94..df3cc32 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -28,10 +28,8 @@ static int major, minors; static struct class *hidg_class; -#ifndef USBF_HID_INCLUDED static DEFINE_IDA(hidg_ida); static DEFINE_MUTEX(hidg_ida_lock); /* protects access to hidg_ida */ -#endif /*-------------------------------------------------------------------------*/ /* HID gadget struct */ @@ -684,75 +682,6 @@ fail: return status; } -#ifdef USBF_HID_INCLUDED -static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_hidg *hidg = func_to_hidg(f); - - device_destroy(hidg_class, MKDEV(major, hidg->minor)); - cdev_del(&hidg->cdev); - - /* disable/free request and end point */ - usb_ep_disable(hidg->in_ep); - usb_ep_dequeue(hidg->in_ep, hidg->req); - kfree(hidg->req->buf); - usb_ep_free_request(hidg->in_ep, hidg->req); - - usb_free_all_descriptors(f); - - kfree(hidg->report_desc); - kfree(hidg); -} - -/*-------------------------------------------------------------------------*/ -/* usb_configuration */ -int __init hidg_bind_config(struct usb_configuration *c, - struct hidg_func_descriptor *fdesc, int index) -{ - struct f_hidg *hidg; - int status; - - if (index >= minors) - return -ENOENT; - - /* allocate and initialize one new instance */ - hidg = kzalloc(sizeof *hidg, GFP_KERNEL); - if (!hidg) - return -ENOMEM; - - hidg->minor = index; - hidg->bInterfaceSubClass = fdesc->subclass; - hidg->bInterfaceProtocol = fdesc->protocol; - hidg->report_length = fdesc->report_length; - hidg->report_desc_length = fdesc->report_desc_length; - hidg->report_desc = kmemdup(fdesc->report_desc, - fdesc->report_desc_length, - GFP_KERNEL); - if (!hidg->report_desc) { - kfree(hidg); - return -ENOMEM; - } - - hidg->func.name = "hid"; - hidg->func.strings = ct_func_strings; - hidg->func.bind = hidg_bind; - hidg->func.unbind = hidg_unbind; - hidg->func.set_alt = hidg_set_alt; - hidg->func.disable = hidg_disable; - hidg->func.setup = hidg_setup; - - /* this could me made configurable at some point */ - hidg->qlen = 4; - - status = usb_add_function(c, &hidg->func); - if (status) - kfree(hidg); - - return status; -} - -#else - static inline int hidg_get_minor(void) { int ret; @@ -895,8 +824,6 @@ DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Fabien Chouteau"); -#endif - int ghid_setup(struct usb_gadget *g, int count) { int status; -- cgit v0.10.2 From 5ca8d3ec9970f4798e68bd21a9d44db3d0ff4da7 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:12:02 +0100 Subject: usb: gadget: f_hid: use usb_gstrings_attach Before configfs is integrated the usb_gstrings_attach() interface must be used. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index df3cc32..dfdb432 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -582,18 +582,17 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_ep *ep; struct f_hidg *hidg = func_to_hidg(f); + struct usb_string *us; struct device *device; int status; dev_t dev; /* maybe allocate device-global string IDs, and patch descriptors */ - if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ct_func_string_defs[CT_FUNC_HID_IDX].id = status; - hidg_interface_desc.iInterface = status; - } + us = usb_gstrings_attach(c->cdev, ct_func_strings, + ARRAY_SIZE(ct_func_string_defs)); + if (IS_ERR(us)) + return PTR_ERR(us); + hidg_interface_desc.iInterface = us[CT_FUNC_HID_IDX].id; /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); @@ -806,7 +805,6 @@ struct usb_function *hidg_alloc(struct usb_function_instance *fi) } hidg->func.name = "hid"; - hidg->func.strings = ct_func_strings; hidg->func.bind = hidg_bind; hidg->func.unbind = hidg_unbind; hidg->func.set_alt = hidg_set_alt; -- cgit v0.10.2 From 21a9476a7ba847e413bf1c144d7c614532aed6dd Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 6 Nov 2014 11:12:03 +0100 Subject: usb: gadget: hid: add configfs support Make the hid function available for gadgets composed with configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/testing/configfs-usb-gadget-hid b/Documentation/ABI/testing/configfs-usb-gadget-hid new file mode 100644 index 0000000..f12e00e --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-hid @@ -0,0 +1,11 @@ +What: /config/usb-gadget/gadget/functions/hid.name +Date: Nov 2014 +KernelVersion: 3.19 +Description: + The attributes: + + protocol - HID protocol to use + report_desc - blob corresponding to HID report descriptors + except the data passed through /dev/hidg + report_length - HID report length + subclass - HID device subclass to use diff --git a/Documentation/usb/gadget_hid.txt b/Documentation/usb/gadget_hid.txt index 12696c2..7a0fb8e 100644 --- a/Documentation/usb/gadget_hid.txt +++ b/Documentation/usb/gadget_hid.txt @@ -74,6 +74,13 @@ static struct platform_device my_hid = { You can add as many HID functions as you want, only limited by the amount of interrupt endpoints your gadget driver supports. +Configuration with configfs + + Instead of adding fake platform devices and drivers in order to pass + some data to the kernel, if HID is a part of a gadget composed with + configfs the hidg_func_descriptor.report_desc is passed to the kernel + by writing the appropriate stream of bytes to a configfs attribute. + Send and receive HID reports HID reports can be sent/received using read/write on the diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index ea2d770..747ef53 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -413,6 +413,16 @@ config USB_CONFIGFS_F_MIDI connections can then be made on the gadget system, using ALSA's aconnect utility etc. +config USB_CONFIGFS_F_HID + boolean "HID function" + depends on USB_CONFIGFS + select USB_F_HID + help + The HID function driver provides generic emulation of USB + Human Interface Devices (HID). + + For more information, see Documentation/usb/gadget_hid.txt. + source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index dfdb432..56ca3fc 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -690,6 +690,136 @@ static inline int hidg_get_minor(void) return ret; } +static inline struct f_hid_opts *to_f_hid_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_hid_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_hid_opts); +CONFIGFS_ATTR_OPS(f_hid_opts); + +static void hid_attr_release(struct config_item *item) +{ + struct f_hid_opts *opts = to_f_hid_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations hidg_item_ops = { + .release = hid_attr_release, + .show_attribute = f_hid_opts_attr_show, + .store_attribute = f_hid_opts_attr_store, +}; + +#define F_HID_OPT(name, prec, limit) \ +static ssize_t f_hid_opts_##name##_show(struct f_hid_opts *opts, char *page)\ +{ \ + int result; \ + \ + mutex_lock(&opts->lock); \ + result = sprintf(page, "%d\n", opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_hid_opts_##name##_store(struct f_hid_opts *opts, \ + const char *page, size_t len) \ +{ \ + int ret; \ + u##prec num; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = kstrtou##prec(page, 0, &num); \ + if (ret) \ + goto end; \ + \ + if (num > limit) { \ + ret = -EINVAL; \ + goto end; \ + } \ + opts->name = num; \ + ret = len; \ + \ +end: \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +static struct f_hid_opts_attribute f_hid_opts_##name = \ + __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_hid_opts_##name##_show,\ + f_hid_opts_##name##_store) + +F_HID_OPT(subclass, 8, 255); +F_HID_OPT(protocol, 8, 255); +F_HID_OPT(report_length, 16, 65536); + +static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = opts->report_desc_length; + memcpy(page, opts->report_desc, opts->report_desc_length); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_hid_opts_report_desc_store(struct f_hid_opts *opts, + const char *page, size_t len) +{ + int ret = -EBUSY; + char *d; + + mutex_lock(&opts->lock); + + if (opts->refcnt) + goto end; + if (len > PAGE_SIZE) { + ret = -ENOSPC; + goto end; + } + d = kmemdup(page, len, GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto end; + } + kfree(opts->report_desc); + opts->report_desc = d; + opts->report_desc_length = len; + opts->report_desc_alloc = true; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_hid_opts_attribute f_hid_opts_report_desc = + __CONFIGFS_ATTR(report_desc, S_IRUGO | S_IWUSR, + f_hid_opts_report_desc_show, + f_hid_opts_report_desc_store); + +static struct configfs_attribute *hid_attrs[] = { + &f_hid_opts_subclass.attr, + &f_hid_opts_protocol.attr, + &f_hid_opts_report_length.attr, + &f_hid_opts_report_desc.attr, + NULL, +}; + +static struct config_item_type hid_func_type = { + .ct_item_ops = &hidg_item_ops, + .ct_attrs = hid_attrs, + .ct_owner = THIS_MODULE, +}; + static inline void hidg_put_minor(int minor) { ida_simple_remove(&hidg_ida, minor); @@ -724,7 +854,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); - + mutex_init(&opts->lock); opts->func_inst.free_func_inst = hidg_free_inst; ret = &opts->func_inst; @@ -746,6 +876,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) if (idr_is_empty(&hidg_ida.idr)) ghid_cleanup(); } + config_group_init_type_name(&opts->func_inst.group, "", &hid_func_type); unlock: mutex_unlock(&hidg_ida_lock); @@ -755,10 +886,15 @@ unlock: static void hidg_free(struct usb_function *f) { struct f_hidg *hidg; + struct f_hid_opts *opts; hidg = func_to_hidg(f); + opts = container_of(f->fi, struct f_hid_opts, func_inst); kfree(hidg->report_desc); kfree(hidg); + mutex_lock(&opts->lock); + --opts->refcnt; + mutex_unlock(&opts->lock); } static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) @@ -789,6 +925,9 @@ struct usb_function *hidg_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_hid_opts, func_inst); + mutex_lock(&opts->lock); + ++opts->refcnt; + hidg->minor = opts->minor; hidg->bInterfaceSubClass = opts->subclass; hidg->bInterfaceProtocol = opts->protocol; @@ -800,10 +939,13 @@ struct usb_function *hidg_alloc(struct usb_function_instance *fi) GFP_KERNEL); if (!hidg->report_desc) { kfree(hidg); + mutex_unlock(&opts->lock); return ERR_PTR(-ENOMEM); } } + mutex_unlock(&opts->lock); + hidg->func.name = "hid"; hidg->func.bind = hidg_bind; hidg->func.unbind = hidg_unbind; diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 3edfc95..aaa0e36 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -27,6 +27,13 @@ struct f_hid_opts { unsigned short report_desc_length; unsigned char *report_desc; bool report_desc_alloc; + + /* + * Protect the data form concurrent access by read/write + * and create symlink/remove symlink. + */ + struct mutex lock; + int refcnt; }; int ghid_setup(struct usb_gadget *g, int count); -- cgit v0.10.2 From cd72f890d2d344f36d8f51f27bed2607062bb985 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Nov 2014 11:31:00 -0600 Subject: usb: dwc3: core: enable phy suspend quirk on non-FPGA as it turns out, at least AM437x silicon (non-FPGA) needs to enable PHY suspend quirk. So let's allow for PHY suspend quirk to be used with non-FPGA builds too. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 8ae42b8..25ddc39 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -404,7 +404,7 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->tx_de_emphasis_quirk) reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); - if (dwc->dis_u3_susphy_quirk && dwc->is_fpga) + if (dwc->dis_u3_susphy_quirk) reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); @@ -422,7 +422,7 @@ static void dwc3_phy_setup(struct dwc3 *dwc) if (dwc->revision > DWC3_REVISION_194A) reg |= DWC3_GUSB2PHYCFG_SUSPHY; - if (dwc->dis_u2_susphy_quirk && dwc->is_fpga) + if (dwc->dis_u2_susphy_quirk) reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); -- cgit v0.10.2 From 55dc68c012bf056880c03d9f6eb34c00880f9e88 Mon Sep 17 00:00:00 2001 From: Mark Knibbs Date: Tue, 4 Nov 2014 13:00:22 +0000 Subject: USB: storage: Reject bogus max LUN values Some mass storage devices return a bogus value in response to a Get Max LUN request. The Iomega Jaz USB Adapter responds with 0x10, hence my recent patch to use the US_FL_SINGLE_LUN quirk for it. The USB MSC Bulk Only Transport document says "The device shall return one byte of data that contains the maximum LUN supported by the device." Since the LUN field in the command block wrapper is only 4 bits wide, it might be helpful to report too-large LUN values in the kernel log, and assume max LUN is actually 0. That could get some devices which currently need the US_FL_SINGLE_LUN quirk to work. Signed-off-by: Mark Knibbs Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 22c7d43..d614dee 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1035,9 +1035,20 @@ int usb_stor_Bulk_max_lun(struct us_data *us) usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n", result, us->iobuf[0]); - /* if we have a successful request, return the result */ - if (result > 0) - return us->iobuf[0]; + /* + * If we have a successful request, return the result if valid. The + * CBW LUN field is 4 bits wide, so the value reported by the device + * should fit into that. + */ + if (result > 0) { + if (us->iobuf[0] < 16) { + return us->iobuf[0]; + } else { + dev_info(&us->pusb_intf->dev, + "Max LUN %d is not valid, using 0 instead", + us->iobuf[0]); + } + } /* * Some devices don't like GetMaxLUN. They may STALL the control -- cgit v0.10.2 From 6827f7e3113ae11689546404f557fbfdba20aa50 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:17:10 +0530 Subject: host: uhci-platform: fix NULL pointer dereference on resource Fix in accessing NULL if resource didn't get. Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index b987f1d..cf8f460 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -86,14 +86,14 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto err_rmr; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + uhci = hcd_to_uhci(hcd); uhci->regs = hcd->regs; -- cgit v0.10.2 From 239ab7a41ada94a0248028c380b66be7704db054 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:17:11 +0530 Subject: host: ehci-sead3: fix NULL pointer dereference on resource Fix on accessing NULL pointer dereference on get resource failed. Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c index cf12676..9b6e8d0 100644 --- a/drivers/usb/host/ehci-sead3.c +++ b/drivers/usb/host/ehci-sead3.c @@ -110,14 +110,13 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto err1; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); /* Root hub has integrated TT. */ hcd->has_tt = 1; -- cgit v0.10.2 From 0fb5f700e984d6e5c035d241ffab1900d0f1ebd2 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:08 +0530 Subject: host: ehci-atmel: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index ec9f7b7..56a8850 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -107,22 +107,15 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto fail_request_resource; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto fail_request_resource; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + iclk = devm_clk_get(&pdev->dev, "ehci_clk"); if (IS_ERR(iclk)) { dev_err(&pdev->dev, "Error getting interface clock\n"); -- cgit v0.10.2 From 54891d7404267ac7a89a464752feba6a851d18fd Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:09 +0530 Subject: host: ohci-da8xx: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index df06be6..1c76999 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -313,16 +313,13 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver, return -ENOMEM; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) - return -ENODEV; - hcd->rsrc_start = mem->start; - hcd->rsrc_len = resource_size(mem); - hcd->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(hcd->regs)) { error = PTR_ERR(hcd->regs); goto err; } + hcd->rsrc_start = mem->start; + hcd->rsrc_len = resource_size(mem); ohci_hcd_init(hcd_to_ohci(hcd)); -- cgit v0.10.2 From a36cc4237f8e8aabb7d78b3d17eac7a23550992e Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:10 +0530 Subject: host: ehci-tegra: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 3e6f685..19a9af1 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -460,18 +460,14 @@ static int tegra_ehci_probe(struct platform_device *pdev) "nvidia,needs-double-reset"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get I/O memory\n"); - err = -ENXIO; - goto cleanup_clk_en; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); goto cleanup_clk_en; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + ehci->caps = hcd->regs + 0x100; ehci->has_hostpc = soc_config->has_hostpc; -- cgit v0.10.2 From 0af6b07094b6ad560bc1a1d062a81aaaebc57199 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:11 +0530 Subject: host: ehci-w90x900: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index a9303af..4717bf2 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -42,27 +42,20 @@ static int usb_w90x900_probe(const struct hc_driver *driver, int retval = 0, irq; unsigned long val; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENXIO; - goto err1; - } - hcd = usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI"); if (!hcd) { retval = -ENOMEM; goto err1; } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto err2; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; -- cgit v0.10.2 From 04dc3150a3d341cda494b3689c14b334aa8f94e2 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:12 +0530 Subject: host: ohci-at91: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 6181549..3940660 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -133,12 +133,6 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, struct resource *res; int irq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_dbg(dev, "hcd probe: missing memory resource\n"); - return -ENXIO; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_dbg(dev, "hcd probe: missing irq resource\n"); @@ -148,14 +142,15 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, hcd = usb_create_hcd(driver, dev, "at91"); if (!hcd) return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto err; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); iclk = devm_clk_get(dev, "ohci_clk"); if (IS_ERR(iclk)) { -- cgit v0.10.2 From b87a9c5294c640b07a7da8cec615bef650ef074d Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:13 +0530 Subject: host: ohci-exynos: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 39f366b..035a8a8 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -155,19 +155,13 @@ skip_phy: goto fail_clk; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get I/O memory\n"); - err = -ENXIO; - goto fail_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); goto fail_io; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); irq = platform_get_irq(pdev, 0); if (!irq) { -- cgit v0.10.2 From 5c36cc64c5036463e608d2ccaaf71bec50112119 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:14 +0530 Subject: host: ohci-jz4740: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c index c2c221a..8ddd8f5 100644 --- a/drivers/usb/host/ohci-jz4740.c +++ b/drivers/usb/host/ohci-jz4740.c @@ -153,13 +153,6 @@ static int jz4740_ohci_probe(struct platform_device *pdev) struct resource *res; int irq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - if (!res) { - dev_err(&pdev->dev, "Failed to get platform resource\n"); - return -ENOENT; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "Failed to get platform irq\n"); @@ -174,14 +167,14 @@ static int jz4740_ohci_probe(struct platform_device *pdev) jz4740_ohci = hcd_to_jz4740_hcd(hcd); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto err_free; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); jz4740_ohci->clk = devm_clk_get(&pdev->dev, "uhc"); if (IS_ERR(jz4740_ohci->clk)) { -- cgit v0.10.2 From c6d413cebd82cf35b6a4257cd94724ff60cffb71 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:15 +0530 Subject: host: ohci-octeon: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c index 15af895..20d861b 100644 --- a/drivers/usb/host/ohci-octeon.c +++ b/drivers/usb/host/ohci-octeon.c @@ -120,12 +120,6 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev) return -ENODEV; } - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem == NULL) { - dev_err(&pdev->dev, "No register space assigned\n"); - return -ENODEV; - } - /* Ohci is a 32-bit device. */ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) @@ -135,14 +129,14 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(&pdev->dev, res_mem); if (IS_ERR(reg_base)) { ret = PTR_ERR(reg_base); goto err1; } + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); ohci_octeon_hw_start(); -- cgit v0.10.2 From 7b519291b1b8ef82187936c9b6d1edfc5c805b3d Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:16 +0530 Subject: host: ohci-platform: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index adb691d..9434c1d 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -134,12 +134,6 @@ static int ohci_platform_probe(struct platform_device *dev) return irq; } - res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res_mem) { - dev_err(&dev->dev, "no memory resource provided"); - return -ENXIO; - } - hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, dev_name(&dev->dev)); if (!hcd) @@ -231,14 +225,15 @@ static int ohci_platform_probe(struct platform_device *dev) goto err_reset; } - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - + res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); goto err_power; } + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); + err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) goto err_power; -- cgit v0.10.2 From 15c85d9cc83b6aea97859377d887e7493f141193 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:17 +0530 Subject: host: ohci-pxa27x: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index e68f3d0..1339981 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -447,20 +447,13 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device return -ENOMEM; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - pr_err("no resource of IORESOURCE_MEM"); - retval = -ENXIO; - goto err; - } - - hcd->rsrc_start = r->start; - hcd->rsrc_len = resource_size(r); - hcd->regs = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto err; } + hcd->rsrc_start = r->start; + hcd->rsrc_len = resource_size(r); /* initialize "struct pxa27x_ohci" */ pxa_ohci = to_pxa27x_ohci(hcd); -- cgit v0.10.2 From e71827f49415b9da0b4723cab398258c9a40ed08 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:18 +0530 Subject: host: ehci-sh: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index f9ebf8a..0e0ce68 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -86,15 +86,6 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - ret = -ENODEV; - goto fail_create_hcd; - } - irq = platform_get_irq(pdev, 0); if (irq <= 0) { dev_err(&pdev->dev, @@ -114,14 +105,14 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) goto fail_create_hcd; } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto fail_request_resource; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv), GFP_KERNEL); -- cgit v0.10.2 From 0bf80cbf0642124329117fa9ba4b0ed9c0176329 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:19 +0530 Subject: host: ohci-spear: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 8d58766..4a54f9d 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -74,20 +74,15 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENODEV; - goto err_put_hcd; - } - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto err_put_hcd; } + hcd->rsrc_start = pdev->resource[0].start; + hcd->rsrc_len = resource_size(res); + sohci_p = to_spear_ohci(hcd); sohci_p->clk = usbh_clk; -- cgit v0.10.2 From e507bf577e5a4c4f28dab4113625f218c5231ca7 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:20 +0530 Subject: host: ehci-msm: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 9dc2118..9db74ca 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -88,19 +88,13 @@ static int ehci_msm_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Unable to get memory resource\n"); - ret = -ENODEV; - goto put_hcd; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto put_hcd; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); /* * OTG driver takes care of PHY initialization, clock management, -- cgit v0.10.2 From 6144171ddccfe2db193496614159501bf641034f Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:21 +0530 Subject: host: ehci-mv: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index b1855c1..849806a 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -169,12 +169,6 @@ static int mv_ehci_probe(struct platform_device *pdev) } 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_hcd; - } - ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(ehci_mv->phy_regs)) { retval = PTR_ERR(ehci_mv->phy_regs); @@ -182,12 +176,6 @@ static int mv_ehci_probe(struct platform_device *pdev) } 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_put_hcd; - } - ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(ehci_mv->cap_regs)) { retval = PTR_ERR(ehci_mv->cap_regs); -- cgit v0.10.2 From d6e269ae4fb147eaa65ae6980064ee0c013fc7d6 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:22 +0530 Subject: host: ehci-mxc: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index dbe5e4e..c7a9b31 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -69,20 +69,13 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr. Check setup!\n"); - ret = -ENODEV; - goto err_alloc; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto err_alloc; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); hcd->has_tt = 1; ehci = hcd_to_ehci(hcd); -- cgit v0.10.2 From 073153bf227649057a911ff8d4383117fb866e2b Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:23 +0530 Subject: host: ehci-octeon: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index 9051439..2d0c4bc 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -106,12 +106,6 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) return -ENODEV; } - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem == NULL) { - dev_err(&pdev->dev, "No register space assigned\n"); - return -ENODEV; - } - /* * We can DMA from anywhere. But the descriptors must be in * the lower 4GB. @@ -125,14 +119,14 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res_mem); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto err1; } + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); ehci_octeon_start(); -- cgit v0.10.2 From 69b89c603bdbc495a751c926b6311ce3db018f04 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:24 +0530 Subject: host: ehci-orion: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Reviewed-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 22e15ca..36b4657 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -175,15 +175,6 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) goto err; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - err = -ENODEV; - goto err; - } - /* * Right now device-tree probed devices don't get dma_mask * set. Since shared usb code relies on it, set it here for @@ -193,6 +184,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) if (err) goto err; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(regs)) { err = PTR_ERR(regs); -- cgit v0.10.2 From 2062ff489ca9d97b4bfee56e944727d9b02b0d63 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:25 +0530 Subject: host: ehci-platform: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index da056fe..35a9aed 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -164,11 +164,6 @@ static int ehci_platform_probe(struct platform_device *dev) dev_err(&dev->dev, "no irq provided"); return irq; } - res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res_mem) { - dev_err(&dev->dev, "no memory resource provided"); - return -ENXIO; - } hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, dev_name(&dev->dev)); @@ -250,14 +245,15 @@ static int ehci_platform_probe(struct platform_device *dev) goto err_reset; } - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - + res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&dev->dev, res_mem); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); goto err_power; } + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); + err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) goto err_power; -- cgit v0.10.2 From 3b59d31dd86b4839a62ac05de708cca3e20dfed4 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:26 +0530 Subject: host: ehci-spear: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 1355ff0..34e1474 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -99,18 +99,13 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENODEV; - goto err_put_hcd; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto err_put_hcd; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); sehci = to_spear_ehci(hcd); sehci->clk = usbh_clk; -- cgit v0.10.2 From e7020f193a3d135e5dda476452e3372e27cc1789 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:27 +0530 Subject: host: xhci-plat: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Acked-by: Felipe Balbi Reviewed-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3d78b0c..e68b4ec 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -83,9 +83,6 @@ static int xhci_plat_probe(struct platform_device *pdev) if (irq < 0) return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; if (of_device_is_compatible(pdev->dev.of_node, "marvell,armada-375-xhci") || @@ -109,15 +106,16 @@ static int xhci_plat_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto put_hcd; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + /* * Not all platforms have a clk so it is not an error if the * clock does not exists. -- cgit v0.10.2 From 972b98344beca6ca2f1de84141005a2ce2f8ffe5 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:28 +0530 Subject: musb: musb_core: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b841ee0..55ebd4b 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2080,10 +2080,10 @@ static int musb_probe(struct platform_device *pdev) struct resource *iomem; void __iomem *base; - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem || irq <= 0) + if (irq <= 0) return -ENODEV; + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, iomem); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v0.10.2 From f3f5972f9e8754f772cffcb5bd7c47573d8cba3b Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:29 +0530 Subject: musb: musb_dsps: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 48bc09e..965c552 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -447,9 +447,6 @@ static int dsps_musb_init(struct musb *musb) int ret; r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); - if (!r) - return -EINVAL; - reg_base = devm_ioremap_resource(dev, r); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); -- cgit v0.10.2 From 7520bee2f1ee18d285877e7c979d4b296458324e Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:30 +0530 Subject: phy: phy-rcar-usb: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c index 33265a5..e9f3a93 100644 --- a/drivers/usb/phy/phy-rcar-usb.c +++ b/drivers/usb/phy/phy-rcar-usb.c @@ -195,11 +195,9 @@ static int rcar_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(reg0); res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res1) { - reg1 = devm_ioremap_resource(dev, res1); - if (IS_ERR(reg1)) - return PTR_ERR(reg1); - } + reg1 = devm_ioremap_resource(dev, res1); + if (IS_ERR(reg1)) + return PTR_ERR(reg1); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) { -- cgit v0.10.2 From ec2a4f32b0e1c897f72f4b541a153969b62c2164 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:31 +0530 Subject: dwc3: dwc3-keystone: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 7ec8495..dd8d2df 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -104,11 +104,6 @@ static int kdwc3_probe(struct platform_device *pdev) kdwc->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing usbss resource\n"); - return -EINVAL; - } - kdwc->usbss = devm_ioremap_resource(dev, res); if (IS_ERR(kdwc->usbss)) return PTR_ERR(kdwc->usbss); -- cgit v0.10.2 From ce98f5486090aab28e6ef80ec180d75b65aa8ffe Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:32 +0530 Subject: host: ehci-fsl: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 2d2ae8d..fb7bd0c 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -93,21 +93,15 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto err2; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto err2; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + pdata->regs = hcd->regs; if (pdata->power_budget) -- cgit v0.10.2 From 35df647c80b44b29dffab3a8374f45d9c0523c26 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:33 +0530 Subject: host: ehci-exynos: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 1b726bf..f58c975 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -187,20 +187,15 @@ skip_phy: goto fail_clk; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get I/O memory\n"); - err = -ENXIO; - goto fail_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); goto fail_io; } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + irq = platform_get_irq(pdev, 0); if (!irq) { dev_err(&pdev->dev, "Failed to get IRQ\n"); -- cgit v0.10.2 From d9a887023076ceed7221c216627a0018ad3b86fa Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 4 Nov 2014 07:51:34 +0530 Subject: renesas_usbhs: common: remove duplicate check on resource Sanity check on resource happening with devm_ioremap_resource(). Signed-off-by: Varka Bhadram Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 6dae115..169307b 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -496,9 +496,8 @@ static int usbhs_probe(struct platform_device *pdev) } /* platform data */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res || !irq_res) { + if (!irq_res) { dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n"); return -ENODEV; } @@ -508,6 +507,7 @@ static int usbhs_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); -- cgit v0.10.2 From b9ec1c9da64f0c1d130beb125a916d0725363ec9 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:45 -0600 Subject: usb: Create separate header for ehci-dbgp The FUSBH200 and FOTG210 controllers implement sufficiently EHCI- compatible debug ports to leverage ehci-dbgp from their respective drivers. Rather than including header, though, they replicate the necessary declarations in their own headers. Move the ehci-dbgp stuff into its own header as a first step towards removing this redundancy. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/usb/ehci-dbgp.h b/include/linux/usb/ehci-dbgp.h new file mode 100644 index 0000000..796c1cd --- /dev/null +++ b/include/linux/usb/ehci-dbgp.h @@ -0,0 +1,84 @@ +/* + * Standalone EHCI usb debug driver + * + * Originally written by: + * Eric W. Biederman" and + * Yinghai Lu + * + * Changes for early/late printk and HW errata: + * Jason Wessel + * Copyright (C) 2009 Wind River Systems, Inc. + * + */ + +#ifndef __LINUX_USB_EHCI_DBGP_H +#define __LINUX_USB_EHCI_DBGP_H + +#include +#include + +/* Appendix C, Debug port ... intended for use with special "debug devices" + * that can help if there's no serial console. (nonstandard enumeration.) + */ +struct ehci_dbg_port { + u32 control; +#define DBGP_OWNER (1<<30) +#define DBGP_ENABLED (1<<28) +#define DBGP_DONE (1<<16) +#define DBGP_INUSE (1<<10) +#define DBGP_ERRCODE(x) (((x)>>7)&0x07) +# define DBGP_ERR_BAD 1 +# define DBGP_ERR_SIGNAL 2 +#define DBGP_ERROR (1<<6) +#define DBGP_GO (1<<5) +#define DBGP_OUT (1<<4) +#define DBGP_LEN(x) (((x)>>0)&0x0f) + u32 pids; +#define DBGP_PID_GET(x) (((x)>>16)&0xff) +#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) + u32 data03; + u32 data47; + u32 address; +#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) +}; + +#ifdef CONFIG_EARLY_PRINTK_DBGP +#include +extern int __init early_dbgp_init(char *s); +extern struct console early_dbgp_console; +#endif /* CONFIG_EARLY_PRINTK_DBGP */ + +struct usb_hcd; + +#ifdef CONFIG_XEN_DOM0 +extern int xen_dbgp_reset_prep(struct usb_hcd *); +extern int xen_dbgp_external_startup(struct usb_hcd *); +#else +static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) +{ + return 1; /* Shouldn't this be 0? */ +} + +static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) +{ + return -1; +} +#endif + +#ifdef CONFIG_EARLY_PRINTK_DBGP +/* Call backs from ehci host driver to ehci debug driver */ +extern int dbgp_external_startup(struct usb_hcd *); +extern int dbgp_reset_prep(struct usb_hcd *); +#else +static inline int dbgp_reset_prep(struct usb_hcd *hcd) +{ + return xen_dbgp_reset_prep(hcd); +} + +static inline int dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_external_startup(hcd); +} +#endif + +#endif /* __LINUX_USB_EHCI_DBGP_H */ diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h index daec99a..966889a 100644 --- a/include/linux/usb/ehci_def.h +++ b/include/linux/usb/ehci_def.h @@ -19,6 +19,8 @@ #ifndef __LINUX_USB_EHCI_DEF_H #define __LINUX_USB_EHCI_DEF_H +#include + /* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ /* Section 2.2 Host Controller Capability Registers */ @@ -190,67 +192,4 @@ struct ehci_regs { #define USBMODE_EX_HC (3<<0) /* host controller mode */ }; -/* Appendix C, Debug port ... intended for use with special "debug devices" - * that can help if there's no serial console. (nonstandard enumeration.) - */ -struct ehci_dbg_port { - u32 control; -#define DBGP_OWNER (1<<30) -#define DBGP_ENABLED (1<<28) -#define DBGP_DONE (1<<16) -#define DBGP_INUSE (1<<10) -#define DBGP_ERRCODE(x) (((x)>>7)&0x07) -# define DBGP_ERR_BAD 1 -# define DBGP_ERR_SIGNAL 2 -#define DBGP_ERROR (1<<6) -#define DBGP_GO (1<<5) -#define DBGP_OUT (1<<4) -#define DBGP_LEN(x) (((x)>>0)&0x0f) - u32 pids; -#define DBGP_PID_GET(x) (((x)>>16)&0xff) -#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) - u32 data03; - u32 data47; - u32 address; -#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) -}; - -#ifdef CONFIG_EARLY_PRINTK_DBGP -#include -extern int __init early_dbgp_init(char *s); -extern struct console early_dbgp_console; -#endif /* CONFIG_EARLY_PRINTK_DBGP */ - -struct usb_hcd; - -#ifdef CONFIG_XEN_DOM0 -extern int xen_dbgp_reset_prep(struct usb_hcd *); -extern int xen_dbgp_external_startup(struct usb_hcd *); -#else -static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) -{ - return 1; /* Shouldn't this be 0? */ -} - -static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) -{ - return -1; -} -#endif - -#ifdef CONFIG_EARLY_PRINTK_DBGP -/* Call backs from ehci host driver to ehci debug driver */ -extern int dbgp_external_startup(struct usb_hcd *); -extern int dbgp_reset_prep(struct usb_hcd *hcd); -#else -static inline int dbgp_reset_prep(struct usb_hcd *hcd) -{ - return xen_dbgp_reset_prep(hcd); -} -static inline int dbgp_external_startup(struct usb_hcd *hcd) -{ - return xen_dbgp_external_startup(hcd); -} -#endif - #endif /* __LINUX_USB_EHCI_DEF_H */ -- cgit v0.10.2 From 895baf2404ebc2f875fad39d2d81f98a38a8f9cc Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:46 -0600 Subject: fusbh200: Make Xen notificaiton consistent with EHCI If CONFIG_XEN_DOM0 is enabled, the ehci-dbgp driver notifies Xen of controller reset events via xen_dbgp_reset_prep() and xen_dbgp_external_startup() (via calls to xen_dbgp_op().) Otherwise defines them as no-ops to disable this logic. The fusbh200 driver copies much of the dbgp code from ehci_def.h, but it unconditionally defines the Xen hooks as no-ops, effectively disabling these notifications when CONFIG_EARLY_PRINTK_DBGP is disabled. When enabled, though, notifying Xen is dependent on CONFIG_XEN_DOM0 due to fusbh200 leveraging the ehci-dbgp driver. The following table compares the implementations of xen_dbgp_reset_prep() and xen_dbgp_external_startup() in the ehci-dbgp and fusbh200 drivers under the relevant configurations: EARLY_PRINTK_DBGP? XEN_DOM0? ehci-dbgp fusbh200 ------------------ --------- ------------- ------------- n n no-op no-op n y xen_dbgp_op() no-op y n no-op no-op y y xen_dbgp_op() xen_dbgp_op() This suggests that fusbh200 is, at best, indifferent to whether Xen is notified of these events. Make fusbh200 consistent with ehci-dbgp as a step towards consolidating this code duplication. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fusbh200.h b/drivers/usb/host/fusbh200.h index 6b719e0..6e7b8c1 100644 --- a/drivers/usb/host/fusbh200.h +++ b/drivers/usb/host/fusbh200.h @@ -318,6 +318,10 @@ extern struct console early_dbgp_console; struct usb_hcd; +#ifdef CONFIG_XEN_DOM0 +extern int xen_dbgp_reset_prep(struct usb_hcd *); +extern int xen_dbgp_external_startup(struct usb_hcd *); +#else static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) { return 1; /* Shouldn't this be 0? */ @@ -327,6 +331,7 @@ static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) { return -1; } +#endif #ifdef CONFIG_EARLY_PRINTK_DBGP /* Call backs from fusbh200 host driver to fusbh200 debug driver */ -- cgit v0.10.2 From d67bba78b308f7753dc5b4d5801f67817967b736 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:47 -0600 Subject: fusbh200: Remove superfluous macro definitions The fusbh200_dbg_port struct is a copy of the ehci_dbg_port definition in the header. Embedded in this definition are a number of macros which came along for the ride. These macros are not used in the fusbh200 driver and will conflict those in the new header. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fusbh200.h b/drivers/usb/host/fusbh200.h index 6e7b8c1..da7152b 100644 --- a/drivers/usb/host/fusbh200.h +++ b/drivers/usb/host/fusbh200.h @@ -290,24 +290,10 @@ struct fusbh200_regs { */ struct fusbh200_dbg_port { u32 control; -#define DBGP_OWNER (1<<30) -#define DBGP_ENABLED (1<<28) -#define DBGP_DONE (1<<16) -#define DBGP_INUSE (1<<10) -#define DBGP_ERRCODE(x) (((x)>>7)&0x07) -# define DBGP_ERR_BAD 1 -# define DBGP_ERR_SIGNAL 2 -#define DBGP_ERROR (1<<6) -#define DBGP_GO (1<<5) -#define DBGP_OUT (1<<4) -#define DBGP_LEN(x) (((x)>>0)&0x0f) u32 pids; -#define DBGP_PID_GET(x) (((x)>>16)&0xff) -#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) u32 data03; u32 data47; u32 address; -#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) }; #ifdef CONFIG_EARLY_PRINTK_DBGP -- cgit v0.10.2 From e004631a4f183a9e64db91e3753e97edc5a8cb94 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:48 -0600 Subject: fusbh200: Remove duplicate ehci-dbgp declarations Now that ehci-dbgp has its own header, use it rather than duplicating the declarations, etc. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fusbh200.h b/drivers/usb/host/fusbh200.h index da7152b..47aecfc 100644 --- a/drivers/usb/host/fusbh200.h +++ b/drivers/usb/host/fusbh200.h @@ -1,6 +1,8 @@ #ifndef __LINUX_FUSBH200_H #define __LINUX_FUSBH200_H +#include + /* definitions used for the EHCI driver */ /* @@ -296,44 +298,6 @@ struct fusbh200_dbg_port { u32 address; }; -#ifdef CONFIG_EARLY_PRINTK_DBGP -#include -extern int __init early_dbgp_init(char *s); -extern struct console early_dbgp_console; -#endif /* CONFIG_EARLY_PRINTK_DBGP */ - -struct usb_hcd; - -#ifdef CONFIG_XEN_DOM0 -extern int xen_dbgp_reset_prep(struct usb_hcd *); -extern int xen_dbgp_external_startup(struct usb_hcd *); -#else -static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) -{ - return 1; /* Shouldn't this be 0? */ -} - -static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) -{ - return -1; -} -#endif - -#ifdef CONFIG_EARLY_PRINTK_DBGP -/* Call backs from fusbh200 host driver to fusbh200 debug driver */ -extern int dbgp_external_startup(struct usb_hcd *); -extern int dbgp_reset_prep(struct usb_hcd *hcd); -#else -static inline int dbgp_reset_prep(struct usb_hcd *hcd) -{ - return xen_dbgp_reset_prep(hcd); -} -static inline int dbgp_external_startup(struct usb_hcd *hcd) -{ - return xen_dbgp_external_startup(hcd); -} -#endif - /*-------------------------------------------------------------------------*/ #define QTD_NEXT(fusbh200, dma) cpu_to_hc32(fusbh200, (u32)dma) -- cgit v0.10.2 From da5d5c58f3e9314cd43bf1d28a1a9e3b2659d632 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:49 -0600 Subject: fusbh200: Use ehci_dbg_port struct The FUSBH200 debug port has a EHCI-compatible register layout so there is no need to define a custom struct. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fusbh200.h b/drivers/usb/host/fusbh200.h index 47aecfc..d6e5b3d 100644 --- a/drivers/usb/host/fusbh200.h +++ b/drivers/usb/host/fusbh200.h @@ -86,7 +86,7 @@ struct fusbh200_hcd { /* one per controller */ /* glue to PCI and HCD framework */ struct fusbh200_caps __iomem *caps; struct fusbh200_regs __iomem *regs; - struct fusbh200_dbg_port __iomem *debug; + struct ehci_dbg_port __iomem *debug; __u32 hcs_params; /* cached register copy */ spinlock_t lock; @@ -287,17 +287,6 @@ struct fusbh200_regs { #define BMIER_VBUS_ERR_EN (1<<0) }; -/* Appendix C, Debug port ... intended for use with special "debug devices" - * that can help if there's no serial console. (nonstandard enumeration.) - */ -struct fusbh200_dbg_port { - u32 control; - u32 pids; - u32 data03; - u32 data47; - u32 address; -}; - /*-------------------------------------------------------------------------*/ #define QTD_NEXT(fusbh200, dma) cpu_to_hc32(fusbh200, (u32)dma) -- cgit v0.10.2 From a648c147011d97e0d410f251c27175231975584d Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:50 -0600 Subject: fotg210: Make Xen notification consistent with EHCI If CONFIG_XEN_DOM0 is enabled, the ehci-dbgp driver notifies Xen of controller reset events via xen_dbgp_reset_prep() and xen_dbgp_external_startup() (via calls to xen_dbgp_op().) Otherwise defines them as no-ops to disable this logic. The fotg210 driver copies much of the dbgp code from ehci_def.h, but it unconditionally defines the Xen hooks as no-ops, effectively disabling these notifications when CONFIG_EARLY_PRINTK_DBGP is disabled. When enabled, though, notifying Xen is dependent on CONFIG_XEN_DOM0 due to fotg210 leveraging the ehci-dbgp driver. The following table compares the implementations of xen_dbgp_reset_prep() and xen_dbgp_external_startup() in the ehci-dbgp and fotg210 drivers under the relevant configurations: EARLY_PRINTK_DBGP? XEN_DOM0? ehci-dbgp fotg210 ------------------ --------- ------------- ------------- n n no-op no-op n y xen_dbgp_op() no-op y n no-op no-op y y xen_dbgp_op() xen_dbgp_op() This suggests that fotg210 is, at best, indifferent to whether Xen is notified of these events. Make fotg210 consistent with ehci-dbgp as a step towards consolidating this code duplication. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index ac6cd1b..98c9670 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -326,6 +326,10 @@ extern struct console early_dbgp_console; struct usb_hcd; +#ifdef CONFIG_XEN_DOM0 +extern int xen_dbgp_reset_prep(struct usb_hcd *); +extern int xen_dbgp_external_startup(struct usb_hcd *); +#else static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) { return 1; /* Shouldn't this be 0? */ @@ -335,6 +339,7 @@ static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) { return -1; } +#endif #ifdef CONFIG_EARLY_PRINTK_DBGP /* Call backs from fotg210 host driver to fotg210 debug driver */ -- cgit v0.10.2 From 0fa57f01278b78174848ca628ca9a87c4dd37696 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:51 -0600 Subject: fotg210: Remove superfluous macro definitions The fotg210_dbg_port struct is a copy of the ehci_dbg_port definition in the header. Embedded in this definition are a number of macros which came along for the ride. These macros are not used in the fotg210 driver and will conflict those in the new header. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index 98c9670..c2e5134 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -298,24 +298,10 @@ struct fotg210_regs { */ struct fotg210_dbg_port { u32 control; -#define DBGP_OWNER (1<<30) -#define DBGP_ENABLED (1<<28) -#define DBGP_DONE (1<<16) -#define DBGP_INUSE (1<<10) -#define DBGP_ERRCODE(x) (((x)>>7)&0x07) -# define DBGP_ERR_BAD 1 -# define DBGP_ERR_SIGNAL 2 -#define DBGP_ERROR (1<<6) -#define DBGP_GO (1<<5) -#define DBGP_OUT (1<<4) -#define DBGP_LEN(x) (((x)>>0)&0x0f) u32 pids; -#define DBGP_PID_GET(x) (((x)>>16)&0xff) -#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) u32 data03; u32 data47; u32 address; -#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) }; #ifdef CONFIG_EARLY_PRINTK_DBGP -- cgit v0.10.2 From b1f6ccf580a9c547d0299561149c6a03c833515a Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:52 -0600 Subject: fotg210: Remove duplicate ehci-dbgp declarations Now that ehci-dbgp has its own header, use it rather than duplicating the declarations, etc. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index c2e5134..975d9bb 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -1,6 +1,8 @@ #ifndef __LINUX_FOTG210_H #define __LINUX_FOTG210_H +#include + /* definitions used for the EHCI driver */ /* @@ -304,44 +306,6 @@ struct fotg210_dbg_port { u32 address; }; -#ifdef CONFIG_EARLY_PRINTK_DBGP -#include -extern int __init early_dbgp_init(char *s); -extern struct console early_dbgp_console; -#endif /* CONFIG_EARLY_PRINTK_DBGP */ - -struct usb_hcd; - -#ifdef CONFIG_XEN_DOM0 -extern int xen_dbgp_reset_prep(struct usb_hcd *); -extern int xen_dbgp_external_startup(struct usb_hcd *); -#else -static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) -{ - return 1; /* Shouldn't this be 0? */ -} - -static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) -{ - return -1; -} -#endif - -#ifdef CONFIG_EARLY_PRINTK_DBGP -/* Call backs from fotg210 host driver to fotg210 debug driver */ -extern int dbgp_external_startup(struct usb_hcd *); -extern int dbgp_reset_prep(struct usb_hcd *hcd); -#else -static inline int dbgp_reset_prep(struct usb_hcd *hcd) -{ - return xen_dbgp_reset_prep(hcd); -} -static inline int dbgp_external_startup(struct usb_hcd *hcd) -{ - return xen_dbgp_external_startup(hcd); -} -#endif - /*-------------------------------------------------------------------------*/ #define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma) -- cgit v0.10.2 From 9183b3641f50c3cc70c24073117bb9d53b858fb0 Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:53 -0600 Subject: fotg210: Use ehci_dbg_port struct The FUSBH200 debug port has a EHCI-compatible register layout so there is no need to define a custom struct. Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index 975d9bb..3bad178 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -86,7 +86,7 @@ struct fotg210_hcd { /* one per controller */ /* glue to PCI and HCD framework */ struct fotg210_caps __iomem *caps; struct fotg210_regs __iomem *regs; - struct fotg210_dbg_port __iomem *debug; + struct ehci_dbg_port __iomem *debug; __u32 hcs_params; /* cached register copy */ spinlock_t lock; @@ -295,17 +295,6 @@ struct fotg210_regs { #define GMIR_MDEV_INT (1 << 0) }; -/* Appendix C, Debug port ... intended for use with special "debug devices" - * that can help if there's no serial console. (nonstandard enumeration.) - */ -struct fotg210_dbg_port { - u32 control; - u32 pids; - u32 data03; - u32 data47; - u32 address; -}; - /*-------------------------------------------------------------------------*/ #define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma) -- cgit v0.10.2 From 35a27eab6f94e15fa30f7662af00fbec50526f4a Mon Sep 17 00:00:00 2001 From: Chris Rorvick Date: Tue, 4 Nov 2014 19:18:54 -0600 Subject: usb: Remove __init from early_dbgp_init() prototype Specifying these attributes in both the prototype and the function definition is unnecessary and could cause confusion or bugs if they are inconsistent. As such, __init should only be specified at the function definition. Keith Owens suggested this as a janitorial task on LKML several years ago: https://lkml.org/lkml/2006/1/14/305 Signed-off-by: Chris Rorvick Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/usb/ehci-dbgp.h b/include/linux/usb/ehci-dbgp.h index 796c1cd..7344d9e 100644 --- a/include/linux/usb/ehci-dbgp.h +++ b/include/linux/usb/ehci-dbgp.h @@ -43,8 +43,7 @@ struct ehci_dbg_port { }; #ifdef CONFIG_EARLY_PRINTK_DBGP -#include -extern int __init early_dbgp_init(char *s); +extern int early_dbgp_init(char *s); extern struct console early_dbgp_console; #endif /* CONFIG_EARLY_PRINTK_DBGP */ -- cgit v0.10.2 From 60f0e628c9940dc59463e986ddfa2c9e74ea89bb Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Nov 2014 11:32:35 -0600 Subject: arm: boot: dts: am4372: enable dwc3 suspend PHY quirk Whenever Suspend PHY bit is set on AM437x devices, USB will not work due to Set EP Configuration command always failing. This was only found after a recent commit 2164a47 (usb: dwc3: set SUSPHY bit for all cores, which will be merged for v3.19) added a missing *required* step to dwc3 initialization. Synopsys Databook requires that we enable Suspend PHY bit after initialization but that, unfortunately, breaks AM437x. Acked-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 46660ff..e19068d 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -817,6 +817,8 @@ maximum-speed = "high-speed"; dr_mode = "otg"; status = "disabled"; + snps,dis_u3_susphy_quirk; + snps,dis_u2_susphy_quirk; }; }; @@ -839,6 +841,8 @@ maximum-speed = "high-speed"; dr_mode = "otg"; status = "disabled"; + snps,dis_u3_susphy_quirk; + snps,dis_u2_susphy_quirk; }; }; -- cgit v0.10.2 From 004f7d457ef57d46ddf5f8380aa169214c166fca Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 29 Oct 2014 21:58:33 +0100 Subject: usb: gadget: pxa27x_udc: fix warning in non device-tree build The recent change bringing device-tree support triggers a warning in a non device-tree build : drivers/usb/gadget/udc/pxa27x_udc.c:2405:28: warning: 'udc_pxa_dt_ids' defined but not used [-Wunused-variable] Fix the warning with a preprocessor condition. Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 69e7b816..9b03fab 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2400,11 +2400,13 @@ static struct pxa_udc memory = { } }; +#if defined(CONFIG_OF) static struct of_device_id udc_pxa_dt_ids[] = { { .compatible = "marvell,pxa270-udc" }, {} }; MODULE_DEVICE_TABLE(of, udc_pxa_dt_ids); +#endif /** * pxa_udc_probe - probes the udc device -- cgit v0.10.2 From 8b9ca2767b2d1ea405287e530da3a7b234120b95 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Nov 2014 09:06:04 -0600 Subject: phy: twl4030: Fix build breakage commit e47d925 (usb: move the OTG state from the USB PHY to the OTG structure) moved the OTG state field from struct usb_phy to struct usb_otg but, even though I fixed many other build breakages, I still missed one on phy-twl4030-usb.c. Fix the build breakage now. While at that, also a build warning introduced by the same commit. Cc: Kishon Vijay Abraham I Cc: Antoine Tenart Signed-off-by: Felipe Balbi diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 7b04bef..e2698d29 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -606,7 +606,7 @@ static int twl4030_set_peripheral(struct usb_otg *otg, otg->gadget = gadget; if (!gadget) - otg->phy->state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; return 0; } @@ -618,7 +618,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host) otg->host = host; if (!host) - otg->phy->state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; return 0; } @@ -676,7 +676,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) twl->phy.otg = otg; twl->phy.type = USB_PHY_TYPE_USB2; - otg->phy = &twl->phy; + otg->usb_phy = &twl->phy; otg->set_host = twl4030_set_host; otg->set_peripheral = twl4030_set_peripheral; -- cgit v0.10.2 From 6876d58f2f0548ce130b388c323eed17dc5d8689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ky=C3=B6sti=20M=C3=A4lkki?= Date: Mon, 3 Nov 2014 17:18:04 +0200 Subject: usb: gadget: dbgp: Fix endpoint config after USB disconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SET_FEATURE request with DEBUG_MODE only worked the first time after module initialisation. Per the USB 2.0 debug device specification, said request is to be treated as if it were a SET_CONFIGURATION request, i.e. endpoint must be re-configured. As configure_endpoints() may now get called multiple times, move it outside __init and move serial_alloc_tty() call into __init. Code has assumption that endpoint mapping remains unchanged with consecutive calls of configure_endpoints(). Signed-off-by: Kyösti Mälkki Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 1b07513..633683a 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -237,7 +237,7 @@ static void dbgp_unbind(struct usb_gadget *gadget) static unsigned char tty_line; #endif -static int __init dbgp_configure_endpoints(struct usb_gadget *gadget) +static int dbgp_configure_endpoints(struct usb_gadget *gadget) { int stp; @@ -273,19 +273,10 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget) dbgp.serial->in->desc = &i_desc; dbgp.serial->out->desc = &o_desc; - - if (gserial_alloc_line(&tty_line)) { - stp = 3; - goto fail_3; - } +#endif return 0; -fail_3: - dbgp.o_ep->driver_data = NULL; -#else - return 0; -#endif fail_2: dbgp.i_ep->driver_data = NULL; fail_1: @@ -324,10 +315,17 @@ static int __init dbgp_bind(struct usb_gadget *gadget, err = -ENOMEM; goto fail; } + + if (gserial_alloc_line(&tty_line)) { + stp = 4; + err = -ENODEV; + goto fail; + } #endif + err = dbgp_configure_endpoints(gadget); if (err < 0) { - stp = 4; + stp = 5; goto fail; } @@ -383,6 +381,10 @@ static int dbgp_setup(struct usb_gadget *gadget, #ifdef CONFIG_USB_G_DBGP_PRINTK err = dbgp_enable_ep(); #else + err = dbgp_configure_endpoints(gadget); + if (err < 0) { + goto fail; + } err = gserial_connect(dbgp.serial, tty_line); #endif if (err < 0) -- cgit v0.10.2 From 8e74475b0e0ac2fd3634f3c1b9a109fb1d6269f7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Nov 2014 14:27:53 +0800 Subject: usb: dwc3: gadget: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Felipe Balbi Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 398c12f..f03b136 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2041,6 +2041,17 @@ static void dwc3_resume_gadget(struct dwc3 *dwc) if (dwc->gadget_driver && dwc->gadget_driver->resume) { spin_unlock(&dwc->lock); dwc->gadget_driver->resume(&dwc->gadget); + } +} + +static void dwc3_reset_gadget(struct dwc3 *dwc) +{ + if (!dwc->gadget_driver) + return; + + if (dwc->gadget.speed != USB_SPEED_UNKNOWN) { + spin_unlock(&dwc->lock); + usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver); spin_lock(&dwc->lock); } } @@ -2185,11 +2196,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_gadget_disconnect_interrupt(dwc); } - /* after reset -> Default State */ - usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT); - - if (dwc->gadget.speed != USB_SPEED_UNKNOWN) - dwc3_disconnect_gadget(dwc); + dwc3_reset_gadget(dwc); reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; -- cgit v0.10.2 From 1189f7f6dcf045ff970f619734420c6dd3d8526e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Nov 2014 14:27:54 +0800 Subject: usb: musb: gadget: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Felipe Balbi Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 56c31b7..49b04cb 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -2083,9 +2083,12 @@ __acquires(musb->lock) : NULL ); - /* report disconnect, if we didn't already (flushing EP state) */ - if (musb->g.speed != USB_SPEED_UNKNOWN) - musb_g_disconnect(musb); + /* report reset, if we didn't already (flushing EP state) */ + if (musb->gadget_driver && musb->g.speed != USB_SPEED_UNKNOWN) { + spin_unlock(&musb->lock); + usb_gadget_udc_reset(&musb->g, musb->gadget_driver); + spin_lock(&musb->lock); + } /* clear HR */ else if (devctl & MUSB_DEVCTL_HR) -- cgit v0.10.2 From 8480484d6f4a5b7d50262702db082b0fd13e7df5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 6 Nov 2014 14:27:55 +0800 Subject: usb: gadget: dummy-hcd: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Peter chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 254b9e7..1c69c76 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -367,19 +367,22 @@ static void set_link_state(struct dummy_hcd *dum_hcd) dum_hcd->active) dum_hcd->resuming = 0; - /* if !connected or reset */ + /* Currently !connected or in reset */ if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 || (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) { - /* - * We're connected and not reset (reset occurred now), - * and driver attached - disconnect! - */ - if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 && - (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && - dum->driver) { + unsigned disconnect = USB_PORT_STAT_CONNECTION & + dum_hcd->old_status & (~dum_hcd->port_status); + unsigned reset = USB_PORT_STAT_RESET & + (~dum_hcd->old_status) & dum_hcd->port_status; + + /* Report reset and disconnect events to the driver */ + if (dum->driver && (disconnect || reset)) { stop_activity(dum); spin_unlock(&dum->lock); - dum->driver->disconnect(&dum->gadget); + if (reset) + usb_gadget_udc_reset(&dum->gadget, dum->driver); + else + dum->driver->disconnect(&dum->gadget); spin_lock(&dum->lock); } } else if (dum_hcd->active != dum_hcd->old_active) { -- cgit v0.10.2 From b611e424f1ad189409dde50fe950eb8c05f75cab Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 6 Nov 2014 14:27:56 +0800 Subject: usb: gadget: net2280: use udc-core's reset notifier This patch adds support for the new udc-core reset notifier to the net2280 driver. Signed-off-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index bd03a1b..c491794 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -3308,17 +3308,42 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) * only indicates a change in the reset state). */ if (stat & tmp) { + bool reset = false; + bool disconnect = false; + + /* + * Ignore disconnects and resets if the speed hasn't been set. + * VBUS can bounce and there's always an initial reset. + */ writel(tmp, &dev->regs->irqstat1); - if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) && - ((readl(&dev->usb->usbstat) & mask) == 0)) || - ((readl(&dev->usb->usbctl) & - BIT(VBUS_PIN)) == 0)) && - (dev->gadget.speed != USB_SPEED_UNKNOWN)) { - ep_dbg(dev, "disconnect %s\n", - dev->driver->driver.name); - stop_activity(dev, dev->driver); - ep0_start(dev); - return; + if (dev->gadget.speed != USB_SPEED_UNKNOWN) { + if ((stat & BIT(VBUS_INTERRUPT)) && + (readl(&dev->usb->usbctl) & + BIT(VBUS_PIN)) == 0) { + disconnect = true; + ep_dbg(dev, "disconnect %s\n", + dev->driver->driver.name); + } else if ((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) && + (readl(&dev->usb->usbstat) & mask) + == 0) { + reset = true; + ep_dbg(dev, "reset %s\n", + dev->driver->driver.name); + } + + if (disconnect || reset) { + stop_activity(dev, dev->driver); + ep0_start(dev); + spin_unlock(&dev->lock); + if (reset) + usb_gadget_udc_reset + (&dev->gadget, dev->driver); + else + (dev->driver->disconnect) + (&dev->gadget); + spin_lock(&dev->lock); + return; + } } stat &= ~tmp; -- cgit v0.10.2 From 5ca1ccdaa88ac15d1468c5e8bb40885dc6b8a364 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 6 Nov 2014 14:27:57 +0800 Subject: usb: gadget: net2272: use udc-core's reset notifier This patch adds support for the new udc-core reset notifier to the net2272 driver. Signed-off-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index ab3a739..3a90856 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1982,17 +1982,42 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat) mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED); if (stat & tmp) { + bool reset = false; + bool disconnect = false; + + /* + * Ignore disconnects and resets if the speed hasn't been set. + * VBUS can bounce and there's always an initial reset. + */ net2272_write(dev, IRQSTAT1, tmp); - if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && - ((net2272_read(dev, USBCTL1) & mask) == 0)) - || ((net2272_read(dev, USBCTL1) & (1 << VBUS_PIN)) - == 0)) - && (dev->gadget.speed != USB_SPEED_UNKNOWN)) { - dev_dbg(dev->dev, "disconnect %s\n", - dev->driver->driver.name); - stop_activity(dev, dev->driver); - net2272_ep0_start(dev); - return; + if (dev->gadget.speed != USB_SPEED_UNKNOWN) { + if ((stat & (1 << VBUS_INTERRUPT)) && + (net2272_read(dev, USBCTL1) & + (1 << VBUS_PIN)) == 0) { + disconnect = true; + dev_dbg(dev->dev, "disconnect %s\n", + dev->driver->driver.name); + } else if ((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && + (net2272_read(dev, USBCTL1) & mask) + == 0) { + reset = true; + dev_dbg(dev->dev, "reset %s\n", + dev->driver->driver.name); + } + + if (disconnect || reset) { + stop_activity(dev, dev->driver); + net2272_ep0_start(dev); + spin_unlock(&dev->lock); + if (reset) + usb_gadget_udc_reset + (&dev->gadget, dev->driver); + else + (dev->driver->disconnect) + (&dev->gadget); + spin_lock(&dev->lock); + return; + } } stat &= ~tmp; -- cgit v0.10.2 From afbe47758a5931aa1ddd71da53189092f564b230 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:27:58 +0800 Subject: usb: chipidea: gadget: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index a2d80ab..bdaa7ba 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -692,10 +692,8 @@ __acquires(ci->lock) int retval; spin_unlock(&ci->lock); - if (ci->gadget.speed != USB_SPEED_UNKNOWN) { - if (ci->driver) - ci->driver->disconnect(&ci->gadget); - } + if (ci->gadget.speed != USB_SPEED_UNKNOWN) + usb_gadget_udc_reset(&ci->gadget, ci->driver); retval = _gadget_stop_activity(&ci->gadget); if (retval) @@ -709,8 +707,6 @@ __acquires(ci->lock) if (ci->status == NULL) retval = -ENOMEM; - usb_gadget_set_state(&ci->gadget, USB_STATE_DEFAULT); - done: spin_lock(&ci->lock); -- cgit v0.10.2 From 90834d3ecb952f8f0ab8a5687e58c472935a4e70 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:27:59 +0800 Subject: usb: gadget: pxa25x_udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 2944092..8664b99 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1284,6 +1284,33 @@ bind_fail: } static void +reset_gadget(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) +{ + int i; + + /* don't disconnect drivers more than once */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { + struct pxa25x_ep *ep = &dev->ep[i]; + + ep->stopped = 1; + nuke(ep, -ESHUTDOWN); + } + del_timer_sync(&dev->timer); + + /* report reset; the driver is already quiesced */ + if (driver) + usb_gadget_udc_reset(&dev->gadget, driver); + + /* re-init driver-visible data structures */ + udc_reinit(dev); +} + +static void stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) { int i; @@ -1721,7 +1748,7 @@ pxa25x_udc_irq(int irq, void *_dev) /* reset driver and endpoints, * in case that's not yet done */ - stop_activity (dev, dev->driver); + reset_gadget(dev, dev->driver); } else { DBG(DBG_VERBOSE, "USB reset end\n"); -- cgit v0.10.2 From 373ef692e00624b426271a22b8dadb92a46897ef Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:00 +0800 Subject: usb: gadget: m66592-udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 311ec5f..ef3f73d 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1142,7 +1142,7 @@ static void irq_device_state(struct m66592 *m66592) m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0); if (dvsq == M66592_DS_DFLT) { /* bus reset */ - m66592->driver->disconnect(&m66592->gadget); + usb_gadget_udc_reset(&m66592->gadget, m66592->driver); m66592_update_usb_speed(m66592); } if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) -- cgit v0.10.2 From 363ea206efb25dfcb09d57878fdbdb4cd6b01775 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:01 +0800 Subject: usb: gadget: fsl_udc_core: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index b184ed3..f340181 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1771,7 +1771,7 @@ static void bus_resume(struct fsl_udc *udc) } /* Clear up all ep queues */ -static int reset_queues(struct fsl_udc *udc) +static int reset_queues(struct fsl_udc *udc, bool bus_reset) { u8 pipe; @@ -1780,7 +1780,10 @@ static int reset_queues(struct fsl_udc *udc) /* report disconnect; the driver is already quiesced */ spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); + if (bus_reset) + usb_gadget_udc_reset(&udc->gadget, udc->driver); + else + udc->driver->disconnect(&udc->gadget); spin_lock(&udc->lock); return 0; @@ -1834,7 +1837,7 @@ static void reset_irq(struct fsl_udc *udc) udc->bus_reset = 1; /* Reset all the queues, include XD, dTD, EP queue * head and TR Queue */ - reset_queues(udc); + reset_queues(udc, true); udc->usb_state = USB_STATE_DEFAULT; } else { VDBG("Controller reset"); @@ -1843,7 +1846,7 @@ static void reset_irq(struct fsl_udc *udc) dr_controller_setup(udc); /* Reset all internal used Queues */ - reset_queues(udc); + reset_queues(udc, false); ep0_setup(udc); -- cgit v0.10.2 From 236e5064fc06ce3609b3521ca148ad0f8c3c18f6 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:02 +0800 Subject: usb: gadget: at91_udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index f47f16c..753e93b 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -840,6 +840,31 @@ static void udc_reinit(struct at91_udc *udc) } } +static void reset_gadget(struct at91_udc *udc) +{ + struct usb_gadget_driver *driver = udc->driver; + int i; + + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->suspended = 0; + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct at91_ep *ep = &udc->ep[i]; + + ep->stopped = 1; + nuke(ep, -ESHUTDOWN); + } + if (driver) { + spin_unlock(&udc->lock); + usb_gadget_udc_reset(&udc->gadget, driver); + spin_lock(&udc->lock); + } + + udc_reinit(udc); +} + static void stop_activity(struct at91_udc *udc) { struct usb_gadget_driver *driver = udc->driver; @@ -1426,7 +1451,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); VDBG("end bus reset\n"); udc->addr = 0; - stop_activity(udc); + reset_gadget(udc); /* enable ep0 */ at91_udp_write(udc, AT91_UDP_CSR(0), -- cgit v0.10.2 From 69aa1f9f5e210aac765e3595d3d67a7477ae431a Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:03 +0800 Subject: usb: gadget: mv_udc_core: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index f104ac0..d4edd76 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -1307,6 +1307,23 @@ static void nuke(struct mv_ep *ep, int status) } } +static void gadget_reset(struct mv_udc *udc, struct usb_gadget_driver *driver) +{ + struct mv_ep *ep; + + nuke(&udc->eps[0], -ESHUTDOWN); + + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + nuke(ep, -ESHUTDOWN); + } + + /* report reset; the driver is already quiesced */ + if (driver) { + spin_unlock(&udc->lock); + usb_gadget_udc_reset(&udc->gadget, driver); + spin_lock(&udc->lock); + } +} /* stop all USB activities */ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver) { @@ -1881,7 +1898,7 @@ static void irq_process_reset(struct mv_udc *udc) dev_info(&udc->dev->dev, "usb bus reset\n"); udc->usb_state = USB_STATE_DEFAULT; /* reset all the queues, stop all USB activities */ - stop_activity(udc, udc->driver); + gadget_reset(udc, udc->driver); } else { dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n", readl(&udc->op_regs->portsc)); -- cgit v0.10.2 From fba45ceac46e1508fdefd3fe501be04bb3399792 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:04 +0800 Subject: usb: gadget: fsl_qe_udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 01f29ef..d201f9a 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -1917,7 +1917,7 @@ static int reset_queues(struct qe_udc *udc) /* report disconnect; the driver is already quiesced */ spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); + usb_gadget_udc_reset(&udc->gadget, udc->driver); spin_lock(&udc->lock); return 0; -- cgit v0.10.2 From 7918d8c56a6681850c0c359c41d0669a86a514c6 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:05 +0800 Subject: usb: gadget: pch_udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 6534f36..1c7379a 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -2592,9 +2592,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev) /* Complete request queue */ empty_req_queue(ep); } - if (dev->driver && dev->driver->disconnect) { + if (dev->driver) { spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); + usb_gadget_udc_reset(&dev->gadget, dev->driver); spin_lock(&dev->lock); } } -- cgit v0.10.2 From 107d13c76f46a3b96decac828ac09a1a87e07014 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:06 +0800 Subject: usb: gadget: amd5536udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c index 606b900..de7e5e2 100644 --- a/drivers/usb/gadget/udc/amd5536udc.c +++ b/drivers/usb/gadget/udc/amd5536udc.c @@ -2871,7 +2871,7 @@ __acquires(dev->lock) dev->driver->resume(&dev->gadget); dev->sys_suspended = 0; } - dev->driver->disconnect(&dev->gadget); + usb_gadget_udc_reset(&dev->gadget, dev->driver); spin_lock(&dev->lock); /* disable ep0 to empty req queue */ -- cgit v0.10.2 From 5443a7915f8ac529fb868ba26992046f63402760 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:07 +0800 Subject: usb: gadget: r8a66597-udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index be31b57..06870da 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1345,7 +1345,7 @@ static void irq_device_state(struct r8a66597 *r8a66597) if (dvsq == DS_DFLT) { /* bus reset */ spin_unlock(&r8a66597->lock); - r8a66597->driver->disconnect(&r8a66597->gadget); + usb_gadget_udc_reset(&r8a66597->gadget, r8a66597->driver); spin_lock(&r8a66597->lock); r8a66597_update_usb_speed(r8a66597); } -- cgit v0.10.2 From 4f6bd9fd4a7bee9b0b1b432f96dfade2414930df Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:08 +0800 Subject: usb: gadget: bcm63xx_udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 9319ff2..c790918 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -1962,7 +1962,7 @@ static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id) { struct bcm63xx_udc *udc = dev_id; u32 stat; - bool disconnected = false; + bool disconnected = false, bus_reset = false; stat = usbd_readl(udc, USBD_EVENT_IRQ_STATUS_REG) & usbd_readl(udc, USBD_EVENT_IRQ_MASK_REG); @@ -1990,7 +1990,7 @@ static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id) udc->ep0_req_reset = 1; schedule_work(&udc->ep0_wq); - disconnected = true; + bus_reset = true; } if (stat & BIT(USBD_EVENT_IRQ_SETUP)) { if (bcm63xx_update_link_speed(udc)) { @@ -2013,6 +2013,8 @@ static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id) if (disconnected && udc->driver) udc->driver->disconnect(&udc->gadget); + else if (bus_reset && udc->driver) + usb_gadget_udc_reset(&udc->gadget, udc->driver); return IRQ_HANDLED; } -- cgit v0.10.2 From 39dd96d6c5451f5fa005b3581bc409b109a4f0c7 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 6 Nov 2014 14:28:09 +0800 Subject: usb: gadget: atmel_usba_udc: use udc-core's reset notifier Replace usb_gadget_driver's disconnect with udc-core's reset notifier at bus reset handler. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index c537a66..990b26f 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1685,11 +1685,10 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) usba_writel(udc, INT_CLR, USBA_END_OF_RESET); reset_all_endpoints(udc); - if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver && udc->driver->disconnect) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) { udc->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); + usb_gadget_udc_reset(&udc->gadget, udc->driver); spin_lock(&udc->lock); } -- cgit v0.10.2 From 7e1bbeb4292783dcc079156b8fa08d66d17219e0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Nov 2014 19:43:45 -0600 Subject: usb: host: ohci: omap: fix build breakage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e47d925 (usb: move the OTG state from the USB PHY to the OTG structure) moved the OTG state field from struct usb_phy to struct usb_otg but, even though I fixed many other build breakages, I still missed one on ohci-omap.c. Fix the build breakage now. drivers/usb/host/ohci-omap.c: In function ‘start_hnp’: drivers/usb/host/ohci-omap.c:186:19: error: request for member ‘state’ in something not a structure or union hcd->usb_phy->otg.state = OTG_STATE_A_SUSPEND; Signed-off-by: Felipe Balbi diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index cf89b4b1..3e5df5a 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -183,7 +183,7 @@ static void start_hnp(struct ohci_hcd *ohci) otg_start_hnp(hcd->usb_phy->otg); local_irq_save(flags); - hcd->usb_phy->otg.state = OTG_STATE_A_SUSPEND; + hcd->usb_phy->otg->state = OTG_STATE_A_SUSPEND; writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]); l = omap_readl(OTG_CTRL); l &= ~OTG_A_BUSREQ; -- cgit v0.10.2 From 2fbbc96d16009276153fd33823616877dcca30d8 Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:18 +0100 Subject: phy: Add PHY header file for DT x Driver defines This provides the shared header file which will be reference from both PHY driver and its associated Device Tree node(s). Signed-off-by: Gabriel Fernandez diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h new file mode 100644 index 0000000..e8c6a3f --- /dev/null +++ b/include/dt-bindings/phy/phy.h @@ -0,0 +1,18 @@ +/* + * + * This header provides constants for the phy framework + * + * Copyright (C) 2014 STMicroelectronics + * Author: Gabriel Fernandez + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _DT_BINDINGS_PHY +#define _DT_BINDINGS_PHY + +#define PHY_TYPE_SATA 1 +#define PHY_TYPE_PCIE 2 +#define PHY_TYPE_USB2 3 +#define PHY_TYPE_USB3 4 + +#endif /* _DT_BINDINGS_PHY */ -- cgit v0.10.2 From 5de985de12d18ceca5d60cfd9d72a03cdfa94f4f Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:17 +0100 Subject: phy: miphy28lp: Add Device Tree bindings for the MiPHY28lp The MiPHY28lp is a Generic PHY which can serve various SATA or PCIe or USB3 devices. Signed-off-by: alexandre torgue Signed-off-by: Giuseppe Cavallaro Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt new file mode 100644 index 0000000..b7c13ad --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt @@ -0,0 +1,126 @@ +STMicroelectronics STi MIPHY28LP PHY binding +============================================ + +This binding describes a miphy device that is used to control PHY hardware +for SATA, PCIe or USB3. + +Required properties (controller (parent) node): +- compatible : Should be "st,miphy28lp-phy". +- st,syscfg : Should be a phandle of the system configuration register group + which contain the SATA, PCIe or USB3 mode setting bits. + +Required nodes : A sub-node is required for each channel the controller + provides. Address range information including the usual + 'reg' and 'reg-names' properties are used inside these + nodes to describe the controller's topology. These nodes + are translated by the driver's .xlate() function. + +Required properties (port (child) node): +- #phy-cells : Should be 1 (See second example) + Cell after port phandle is device type from: + - PHY_TYPE_SATA + - PHY_TYPE_PCI + - PHY_TYPE_USB3 +- reg : Address and length of the register set for the device. +- reg-names : The names of the register addresses corresponding to the registers + filled in "reg". It can also contain the offset of the system configuration + registers used as glue-logic to setup the device for SATA/PCIe or USB3 + devices. +- resets : phandle to the parent reset controller. +- reset-names : Associated name must be "miphy-sw-rst". + +Optional properties (port (child) node): +- st,osc-rdy : to check the MIPHY0_OSC_RDY status in the glue-logic. This + is not available in all the MiPHY. For example, for STiH407, only the + MiPHY0 has this bit. +- st,osc-force-ext : to select the external oscillator. This can change from + different MiPHY inside the same SoC. +- st,sata_gen : to select which SATA_SPDMODE has to be set in the SATA system config + register. +- st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive + line). + +example: + + miphy28lp_phy: miphy28lp@9b22000 { + compatible = "st,miphy28lp-phy"; + st,syscfg = <&syscfg_core>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + phy_port0: port@9b22000 { + reg = <0x9b22000 0xff>, + <0x9b09000 0xff>, + <0x9b04000 0xff>, + <0x114 0x4>, /* sysctrl MiPHY cntrl */ + <0x818 0x4>, /* sysctrl MiPHY status*/ + <0xe0 0x4>, /* sysctrl PCIe */ + <0xec 0x4>; /* sysctrl SATA */ + reg-names = "sata-up", + "pcie-up", + "pipew", + "miphy-ctrl-glue", + "miphy-status-glue", + "pcie-glue", + "sata-glue"; + #phy-cells = <1>; + st,osc-rdy; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY0_SOFTRESET>; + }; + + phy_port1: port@9b2a000 { + reg = <0x9b2a000 0xff>, + <0x9b19000 0xff>, + <0x9b14000 0xff>, + <0x118 0x4>, + <0x81c 0x4>, + <0xe4 0x4>, + <0xf0 0x4>; + reg-names = "sata-up", + "pcie-up", + "pipew", + "miphy-ctrl-glue", + "miphy-status-glue", + "pcie-glue", + "sata-glue"; + #phy-cells = <1>; + st,osc-force-ext; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY1_SOFTRESET>; + }; + + phy_port2: port@8f95000 { + reg = <0x8f95000 0xff>, + <0x8f90000 0xff>, + <0x11c 0x4>, + <0x820 0x4>; + reg-names = "pipew", + "usb3-up", + "miphy-ctrl-glue", + "miphy-status-glue"; + #phy-cells = <1>; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY2_SOFTRESET>; + }; + }; + + +Specifying phy control of devices +================================= + +Device nodes should specify the configuration required in their "phys" +property, containing a phandle to the miphy device node and an index +specifying which configuration to use, as described in phy-bindings.txt. + +example: + sata0: sata@9b20000 { + ... + phys = <&phy_port0 PHY_TYPE_SATA>; + ... + }; + +Macro definitions for the supported miphy configuration can be found in: + +include/dt-bindings/phy/phy-miphy28lp.h -- cgit v0.10.2 From 2c14e9be0c60bb3d89cfa16a40222ddcb83660ab Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:19 +0100 Subject: phy: miphy28lp: Provide support for the MiPHY28lp Generic PHY The MiPHY28lp is a Generic PHY which can serve various SATA or PCIe or USB3 devices. Signed-off-by: alexandre torgue Signed-off-by: Giuseppe Cavallaro Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 2a436e6..cfaced9 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -38,6 +38,14 @@ config PHY_MVEBU_SATA depends on OF select GENERIC_PHY +config PHY_MIPHY28LP + tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407" + depends on ARCH_STI + select GENERIC_PHY + help + Enable this to support the miphy transceiver (for SATA/PCIE/USB3) + that is part of STMicroelectronics STiH407 SoC. + config PHY_MIPHY365X tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series" depends on ARCH_STI diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index c4590fc..30d90a8 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o +obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c new file mode 100644 index 0000000..7d592e6 --- /dev/null +++ b/drivers/phy/phy-miphy28lp.c @@ -0,0 +1,1177 @@ +/* + * Copyright (C) 2014 STMicroelectronics + * + * STMicroelectronics PHY driver MiPHY28lp (for SoC STiH407). + * + * Author: Alexandre Torgue + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* MiPHY registers */ +#define MIPHY_CONF_RESET 0x00 +#define RST_APPLI_SW BIT(0) +#define RST_CONF_SW BIT(1) +#define RST_MACRO_SW BIT(2) + +#define MIPHY_RESET 0x01 +#define RST_PLL_SW BIT(0) +#define RST_COMP_SW BIT(2) + +#define MIPHY_STATUS_1 0x02 +#define PHY_RDY BIT(0) +#define HFC_RDY BIT(1) +#define HFC_PLL BIT(2) + +#define MIPHY_CONTROL 0x04 +#define TERM_EN_SW BIT(2) +#define DIS_LINK_RST BIT(3) +#define AUTO_RST_RX BIT(4) +#define PX_RX_POL BIT(5) + +#define MIPHY_BOUNDARY_SEL 0x0a +#define TX_SEL BIT(6) +#define SSC_SEL BIT(4) +#define GENSEL_SEL BIT(0) + +#define MIPHY_BOUNDARY_1 0x0b +#define MIPHY_BOUNDARY_2 0x0c +#define SSC_EN_SW BIT(2) + +#define MIPHY_PLL_CLKREF_FREQ 0x0d +#define MIPHY_SPEED 0x0e +#define TX_SPDSEL_80DEC 0 +#define TX_SPDSEL_40DEC 1 +#define TX_SPDSEL_20DEC 2 +#define RX_SPDSEL_80DEC 0 +#define RX_SPDSEL_40DEC (1 << 2) +#define RX_SPDSEL_20DEC (2 << 2) + +#define MIPHY_CONF 0x0f +#define MIPHY_CTRL_TEST_SEL 0x20 +#define MIPHY_CTRL_TEST_1 0x21 +#define MIPHY_CTRL_TEST_2 0x22 +#define MIPHY_CTRL_TEST_3 0x23 +#define MIPHY_CTRL_TEST_4 0x24 +#define MIPHY_FEEDBACK_TEST 0x25 +#define MIPHY_DEBUG_BUS 0x26 +#define MIPHY_DEBUG_STATUS_MSB 0x27 +#define MIPHY_DEBUG_STATUS_LSB 0x28 +#define MIPHY_PWR_RAIL_1 0x29 +#define MIPHY_PWR_RAIL_2 0x2a +#define MIPHY_SYNCHAR_CONTROL 0x30 + +#define MIPHY_COMP_FSM_1 0x3a +#define COMP_START BIT(6) + +#define MIPHY_COMP_FSM_6 0x3f +#define COMP_DONE BIT(7) + +#define MIPHY_COMP_POSTP 0x42 +#define MIPHY_TX_CTRL_1 0x49 +#define TX_REG_STEP_0V 0 +#define TX_REG_STEP_P_25MV 1 +#define TX_REG_STEP_P_50MV 2 +#define TX_REG_STEP_N_25MV 7 +#define TX_REG_STEP_N_50MV 6 +#define TX_REG_STEP_N_75MV 5 + +#define MIPHY_TX_CTRL_2 0x4a +#define TX_SLEW_SW_40_PS 0 +#define TX_SLEW_SW_80_PS 1 +#define TX_SLEW_SW_120_PS 2 + +#define MIPHY_TX_CTRL_3 0x4b +#define MIPHY_TX_CAL_MAN 0x4e +#define TX_SLEW_CAL_MAN_EN BIT(0) + +#define MIPHY_TST_BIAS_BOOST_2 0x62 +#define MIPHY_BIAS_BOOST_1 0x63 +#define MIPHY_BIAS_BOOST_2 0x64 +#define MIPHY_RX_DESBUFF_FDB_2 0x67 +#define MIPHY_RX_DESBUFF_FDB_3 0x68 +#define MIPHY_SIGDET_COMPENS1 0x69 +#define MIPHY_SIGDET_COMPENS2 0x6a +#define MIPHY_JITTER_PERIOD 0x6b +#define MIPHY_JITTER_AMPLITUDE_1 0x6c +#define MIPHY_JITTER_AMPLITUDE_2 0x6d +#define MIPHY_JITTER_AMPLITUDE_3 0x6e +#define MIPHY_RX_K_GAIN 0x78 +#define MIPHY_RX_BUFFER_CTRL 0x7a +#define VGA_GAIN BIT(0) +#define EQ_DC_GAIN BIT(2) +#define EQ_BOOST_GAIN BIT(3) + +#define MIPHY_RX_VGA_GAIN 0x7b +#define MIPHY_RX_EQU_GAIN_1 0x7f +#define MIPHY_RX_EQU_GAIN_2 0x80 +#define MIPHY_RX_EQU_GAIN_3 0x81 +#define MIPHY_RX_CAL_CTRL_1 0x97 +#define MIPHY_RX_CAL_CTRL_2 0x98 + +#define MIPHY_RX_CAL_OFFSET_CTRL 0x99 +#define CAL_OFFSET_VGA_64 (0x03 << 0) +#define CAL_OFFSET_THRESHOLD_64 (0x03 << 2) +#define VGA_OFFSET_POLARITY BIT(4) +#define OFFSET_COMPENSATION_EN BIT(6) + +#define MIPHY_RX_CAL_VGA_STEP 0x9a +#define MIPHY_RX_CAL_EYE_MIN 0x9d +#define MIPHY_RX_CAL_OPT_LENGTH 0x9f +#define MIPHY_RX_LOCK_CTRL_1 0xc1 +#define MIPHY_RX_LOCK_SETTINGS_OPT 0xc2 +#define MIPHY_RX_LOCK_STEP 0xc4 + +#define MIPHY_RX_SIGDET_SLEEP_OA 0xc9 +#define MIPHY_RX_SIGDET_SLEEP_SEL 0xca +#define MIPHY_RX_SIGDET_WAIT_SEL 0xcb +#define MIPHY_RX_SIGDET_DATA_SEL 0xcc +#define EN_ULTRA_LOW_POWER BIT(0) +#define EN_FIRST_HALF BIT(1) +#define EN_SECOND_HALF BIT(2) +#define EN_DIGIT_SIGNAL_CHECK BIT(3) + +#define MIPHY_RX_POWER_CTRL_1 0xcd +#define MIPHY_RX_POWER_CTRL_2 0xce +#define MIPHY_PLL_CALSET_CTRL 0xd3 +#define MIPHY_PLL_CALSET_1 0xd4 +#define MIPHY_PLL_CALSET_2 0xd5 +#define MIPHY_PLL_CALSET_3 0xd6 +#define MIPHY_PLL_CALSET_4 0xd7 +#define MIPHY_PLL_SBR_1 0xe3 +#define SET_NEW_CHANGE BIT(1) + +#define MIPHY_PLL_SBR_2 0xe4 +#define MIPHY_PLL_SBR_3 0xe5 +#define MIPHY_PLL_SBR_4 0xe6 +#define MIPHY_PLL_COMMON_MISC_2 0xe9 +#define START_ACT_FILT BIT(6) + +#define MIPHY_PLL_SPAREIN 0xeb + +/* + * On STiH407 the glue logic can be different among MiPHY devices; for example: + * MiPHY0: OSC_FORCE_EXT means: + * 0: 30MHz crystal clk - 1: 100MHz ext clk routed through MiPHY1 + * MiPHY1: OSC_FORCE_EXT means: + * 1: 30MHz crystal clk - 0: 100MHz ext clk routed through MiPHY1 + * Some devices have not the possibility to check if the osc is ready. + */ +#define MIPHY_OSC_FORCE_EXT BIT(3) +#define MIPHY_OSC_RDY BIT(5) + +#define MIPHY_CTRL_MASK 0x0f +#define MIPHY_CTRL_DEFAULT 0 +#define MIPHY_CTRL_SYNC_D_EN BIT(2) + +/* SATA / PCIe defines */ +#define SATA_CTRL_MASK 0x07 +#define PCIE_CTRL_MASK 0xff +#define SATA_CTRL_SELECT_SATA 1 +#define SATA_CTRL_SELECT_PCIE 0 +#define SYSCFG_PCIE_PCIE_VAL 0x80 +#define SATA_SPDMODE 1 + +struct miphy28lp_phy { + struct phy *phy; + struct miphy28lp_dev *phydev; + void __iomem *base; + void __iomem *pipebase; + + bool osc_force_ext; + bool osc_rdy; + bool px_rx_pol_inv; + + struct reset_control *miphy_rst; + + u32 sata_gen; + + /* Sysconfig registers offsets needed to configure the device */ + u32 syscfg_miphy_ctrl; + u32 syscfg_miphy_status; + u32 syscfg_pci; + u32 syscfg_sata; + u8 type; +}; + +struct miphy28lp_dev { + struct device *dev; + struct regmap *regmap; + struct mutex miphy_mutex; + struct miphy28lp_phy **phys; +}; + +struct miphy_initval { + u16 reg; + u16 val; +}; + +enum miphy_sata_gen { SATA_GEN1, SATA_GEN2, SATA_GEN3 }; + +static char *PHY_TYPE_name[] = { "sata-up", "pcie-up", "", "usb3-up" }; + +struct pll_ratio { + int clk_ref; + int calset_1; + int calset_2; + int calset_3; + int calset_4; + int cal_ctrl; +}; + +static struct pll_ratio sata_pll_ratio = { + .clk_ref = 0x1e, + .calset_1 = 0xc8, + .calset_2 = 0x00, + .calset_3 = 0x00, + .calset_4 = 0x00, + .cal_ctrl = 0x00, +}; + +static struct pll_ratio pcie_pll_ratio = { + .clk_ref = 0x1e, + .calset_1 = 0xa6, + .calset_2 = 0xaa, + .calset_3 = 0xaa, + .calset_4 = 0x00, + .cal_ctrl = 0x00, +}; + +static struct pll_ratio usb3_pll_ratio = { + .clk_ref = 0x1e, + .calset_1 = 0xa6, + .calset_2 = 0xaa, + .calset_3 = 0xaa, + .calset_4 = 0x04, + .cal_ctrl = 0x00, +}; + +struct miphy28lp_pll_gen { + int bank; + int speed; + int bias_boost_1; + int bias_boost_2; + int tx_ctrl_1; + int tx_ctrl_2; + int tx_ctrl_3; + int rx_k_gain; + int rx_vga_gain; + int rx_equ_gain_1; + int rx_equ_gain_2; + int rx_equ_gain_3; + int rx_buff_ctrl; +}; + +static struct miphy28lp_pll_gen sata_pll_gen[] = { + { + .bank = 0x00, + .speed = TX_SPDSEL_80DEC | RX_SPDSEL_80DEC, + .bias_boost_1 = 0x00, + .bias_boost_2 = 0xae, + .tx_ctrl_2 = 0x53, + .tx_ctrl_3 = 0x00, + .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, + .rx_vga_gain = 0x00, + .rx_equ_gain_1 = 0x7d, + .rx_equ_gain_2 = 0x56, + .rx_equ_gain_3 = 0x00, + }, + { + .bank = 0x01, + .speed = TX_SPDSEL_40DEC | RX_SPDSEL_40DEC, + .bias_boost_1 = 0x00, + .bias_boost_2 = 0xae, + .tx_ctrl_2 = 0x72, + .tx_ctrl_3 = 0x20, + .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, + .rx_vga_gain = 0x00, + .rx_equ_gain_1 = 0x7d, + .rx_equ_gain_2 = 0x56, + .rx_equ_gain_3 = 0x00, + }, + { + .bank = 0x02, + .speed = TX_SPDSEL_20DEC | RX_SPDSEL_20DEC, + .bias_boost_1 = 0x00, + .bias_boost_2 = 0xae, + .tx_ctrl_2 = 0xc0, + .tx_ctrl_3 = 0x20, + .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, + .rx_vga_gain = 0x00, + .rx_equ_gain_1 = 0x7d, + .rx_equ_gain_2 = 0x56, + .rx_equ_gain_3 = 0x00, + }, +}; + +static struct miphy28lp_pll_gen pcie_pll_gen[] = { + { + .bank = 0x00, + .speed = TX_SPDSEL_40DEC | RX_SPDSEL_40DEC, + .bias_boost_1 = 0x00, + .bias_boost_2 = 0xa5, + .tx_ctrl_1 = TX_REG_STEP_N_25MV, + .tx_ctrl_2 = 0x71, + .tx_ctrl_3 = 0x60, + .rx_k_gain = 0x98, + .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, + .rx_vga_gain = 0x00, + .rx_equ_gain_1 = 0x79, + .rx_equ_gain_2 = 0x56, + }, + { + .bank = 0x01, + .speed = TX_SPDSEL_20DEC | RX_SPDSEL_20DEC, + .bias_boost_1 = 0x00, + .bias_boost_2 = 0xa5, + .tx_ctrl_1 = TX_REG_STEP_N_25MV, + .tx_ctrl_2 = 0x70, + .tx_ctrl_3 = 0x60, + .rx_k_gain = 0xcc, + .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN, + .rx_vga_gain = 0x00, + .rx_equ_gain_1 = 0x78, + .rx_equ_gain_2 = 0x07, + }, +}; + +static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy) +{ + void *base = miphy_phy->base; + u8 val; + + /* Putting Macro in reset */ + writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET); + + val = RST_APPLI_SW | RST_CONF_SW; + writeb_relaxed(val, base + MIPHY_CONF_RESET); + + writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET); + + /* Bringing the MIPHY-CPU registers out of reset */ + if (miphy_phy->type == PHY_TYPE_PCIE) { + val = AUTO_RST_RX | TERM_EN_SW; + writeb_relaxed(val, base + MIPHY_CONTROL); + } else { + val = AUTO_RST_RX | TERM_EN_SW | DIS_LINK_RST; + writeb_relaxed(val, base + MIPHY_CONTROL); + } +} + +static inline void miphy28lp_pll_calibration(struct miphy28lp_phy *miphy_phy, + struct pll_ratio *pll_ratio) +{ + void *base = miphy_phy->base; + u8 val; + + /* Applying PLL Settings */ + writeb_relaxed(0x1d, base + MIPHY_PLL_SPAREIN); + writeb_relaxed(pll_ratio->clk_ref, base + MIPHY_PLL_CLKREF_FREQ); + + /* PLL Ratio */ + writeb_relaxed(pll_ratio->calset_1, base + MIPHY_PLL_CALSET_1); + writeb_relaxed(pll_ratio->calset_2, base + MIPHY_PLL_CALSET_2); + writeb_relaxed(pll_ratio->calset_3, base + MIPHY_PLL_CALSET_3); + writeb_relaxed(pll_ratio->calset_4, base + MIPHY_PLL_CALSET_4); + writeb_relaxed(pll_ratio->cal_ctrl, base + MIPHY_PLL_CALSET_CTRL); + + writeb_relaxed(TX_SEL, base + MIPHY_BOUNDARY_SEL); + + val = (0x68 << 1) | TX_SLEW_CAL_MAN_EN; + writeb_relaxed(val, base + MIPHY_TX_CAL_MAN); + + val = VGA_OFFSET_POLARITY | CAL_OFFSET_THRESHOLD_64 | CAL_OFFSET_VGA_64; + + if (miphy_phy->type != PHY_TYPE_SATA) + val |= OFFSET_COMPENSATION_EN; + + writeb_relaxed(val, base + MIPHY_RX_CAL_OFFSET_CTRL); + + if (miphy_phy->type == PHY_TYPE_USB3) { + writeb_relaxed(0x00, base + MIPHY_CONF); + writeb_relaxed(0x70, base + MIPHY_RX_LOCK_STEP); + writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_SLEEP_OA); + writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_SLEEP_SEL); + writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_WAIT_SEL); + + val = EN_DIGIT_SIGNAL_CHECK | EN_FIRST_HALF; + writeb_relaxed(val, base + MIPHY_RX_SIGDET_DATA_SEL); + } + +} + +static inline void miphy28lp_sata_config_gen(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + int i; + + for (i = 0; i < ARRAY_SIZE(sata_pll_gen); i++) { + struct miphy28lp_pll_gen *gen = &sata_pll_gen[i]; + + /* Banked settings */ + writeb_relaxed(gen->bank, base + MIPHY_CONF); + writeb_relaxed(gen->speed, base + MIPHY_SPEED); + writeb_relaxed(gen->bias_boost_1, base + MIPHY_BIAS_BOOST_1); + writeb_relaxed(gen->bias_boost_2, base + MIPHY_BIAS_BOOST_2); + + /* TX buffer Settings */ + writeb_relaxed(gen->tx_ctrl_2, base + MIPHY_TX_CTRL_2); + writeb_relaxed(gen->tx_ctrl_3, base + MIPHY_TX_CTRL_3); + + /* RX Buffer Settings */ + writeb_relaxed(gen->rx_buff_ctrl, base + MIPHY_RX_BUFFER_CTRL); + writeb_relaxed(gen->rx_vga_gain, base + MIPHY_RX_VGA_GAIN); + writeb_relaxed(gen->rx_equ_gain_1, base + MIPHY_RX_EQU_GAIN_1); + writeb_relaxed(gen->rx_equ_gain_2, base + MIPHY_RX_EQU_GAIN_2); + writeb_relaxed(gen->rx_equ_gain_3, base + MIPHY_RX_EQU_GAIN_3); + } +} + +static inline void miphy28lp_pcie_config_gen(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + int i; + + for (i = 0; i < ARRAY_SIZE(pcie_pll_gen); i++) { + struct miphy28lp_pll_gen *gen = &pcie_pll_gen[i]; + + /* Banked settings */ + writeb_relaxed(gen->bank, base + MIPHY_CONF); + writeb_relaxed(gen->speed, base + MIPHY_SPEED); + writeb_relaxed(gen->bias_boost_1, base + MIPHY_BIAS_BOOST_1); + writeb_relaxed(gen->bias_boost_2, base + MIPHY_BIAS_BOOST_2); + + /* TX buffer Settings */ + writeb_relaxed(gen->tx_ctrl_1, base + MIPHY_TX_CTRL_1); + writeb_relaxed(gen->tx_ctrl_2, base + MIPHY_TX_CTRL_2); + writeb_relaxed(gen->tx_ctrl_3, base + MIPHY_TX_CTRL_3); + + writeb_relaxed(gen->rx_k_gain, base + MIPHY_RX_K_GAIN); + + /* RX Buffer Settings */ + writeb_relaxed(gen->rx_buff_ctrl, base + MIPHY_RX_BUFFER_CTRL); + writeb_relaxed(gen->rx_vga_gain, base + MIPHY_RX_VGA_GAIN); + writeb_relaxed(gen->rx_equ_gain_1, base + MIPHY_RX_EQU_GAIN_1); + writeb_relaxed(gen->rx_equ_gain_2, base + MIPHY_RX_EQU_GAIN_2); + } +} + +static inline int miphy28lp_wait_compensation(struct miphy28lp_phy *miphy_phy) +{ + unsigned long finish = jiffies + 5 * HZ; + u8 val; + + /* Waiting for Compensation to complete */ + do { + val = readb_relaxed(miphy_phy->base + MIPHY_COMP_FSM_6); + + if (time_after_eq(jiffies, finish)) + return -EBUSY; + cpu_relax(); + } while (!(val & COMP_DONE)); + + return 0; +} + + +static inline int miphy28lp_compensation(struct miphy28lp_phy *miphy_phy, + struct pll_ratio *pll_ratio) +{ + void __iomem *base = miphy_phy->base; + + /* Poll for HFC ready after reset release */ + /* Compensation measurement */ + writeb_relaxed(RST_PLL_SW | RST_COMP_SW, base + MIPHY_RESET); + + writeb_relaxed(0x00, base + MIPHY_PLL_COMMON_MISC_2); + writeb_relaxed(pll_ratio->clk_ref, base + MIPHY_PLL_CLKREF_FREQ); + writeb_relaxed(COMP_START, base + MIPHY_COMP_FSM_1); + + if (miphy_phy->type == PHY_TYPE_PCIE) + writeb_relaxed(RST_PLL_SW, base + MIPHY_RESET); + + writeb_relaxed(0x00, base + MIPHY_RESET); + writeb_relaxed(START_ACT_FILT, base + MIPHY_PLL_COMMON_MISC_2); + writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); + + /* TX compensation offset to re-center TX impedance */ + writeb_relaxed(0x00, base + MIPHY_COMP_POSTP); + + if (miphy_phy->type == PHY_TYPE_PCIE) + return miphy28lp_wait_compensation(miphy_phy); + + return 0; +} + +static inline void miphy28_usb3_miphy_reset(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + u8 val; + + /* MIPHY Reset */ + writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET); + writeb_relaxed(0x00, base + MIPHY_CONF_RESET); + writeb_relaxed(RST_COMP_SW, base + MIPHY_RESET); + + val = RST_COMP_SW | RST_PLL_SW; + writeb_relaxed(val, base + MIPHY_RESET); + + writeb_relaxed(0x00, base + MIPHY_PLL_COMMON_MISC_2); + writeb_relaxed(0x1e, base + MIPHY_PLL_CLKREF_FREQ); + writeb_relaxed(COMP_START, base + MIPHY_COMP_FSM_1); + writeb_relaxed(RST_PLL_SW, base + MIPHY_RESET); + writeb_relaxed(0x00, base + MIPHY_RESET); + writeb_relaxed(START_ACT_FILT, base + MIPHY_PLL_COMMON_MISC_2); + writeb_relaxed(0x00, base + MIPHY_CONF); + writeb_relaxed(0x00, base + MIPHY_BOUNDARY_1); + writeb_relaxed(0x00, base + MIPHY_TST_BIAS_BOOST_2); + writeb_relaxed(0x00, base + MIPHY_CONF); + writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); + writeb_relaxed(0xa5, base + MIPHY_DEBUG_BUS); + writeb_relaxed(0x00, base + MIPHY_CONF); +} + +static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + int err; + u8 val; + + /* Putting Macro in reset */ + miphy28lp_set_reset(miphy_phy); + + /* PLL calibration */ + miphy28lp_pll_calibration(miphy_phy, &sata_pll_ratio); + + /* Banked settings Gen1/Gen2/Gen3 */ + miphy28lp_sata_config_gen(miphy_phy); + + /* Power control */ + /* Input bridge enable, manual input bridge control */ + writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1); + + /* Macro out of reset */ + writeb_relaxed(0x00, base + MIPHY_CONF_RESET); + + /* Poll for HFC ready after reset release */ + /* Compensation measurement */ + err = miphy28lp_compensation(miphy_phy, &sata_pll_ratio); + if (err) + return err; + + if (miphy_phy->px_rx_pol_inv) { + /* Invert Rx polarity */ + val = readb_relaxed(miphy_phy->base + MIPHY_CONTROL); + val |= PX_RX_POL; + writeb_relaxed(val, miphy_phy->base + MIPHY_CONTROL); + } + + return 0; +} + +static inline int miphy28lp_configure_pcie(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + int err; + + /* Putting Macro in reset */ + miphy28lp_set_reset(miphy_phy); + + /* PLL calibration */ + miphy28lp_pll_calibration(miphy_phy, &pcie_pll_ratio); + + /* Banked settings Gen1/Gen2 */ + miphy28lp_pcie_config_gen(miphy_phy); + + /* Power control */ + /* Input bridge enable, manual input bridge control */ + writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1); + + /* Macro out of reset */ + writeb_relaxed(0x00, base + MIPHY_CONF_RESET); + + /* Poll for HFC ready after reset release */ + /* Compensation measurement */ + err = miphy28lp_compensation(miphy_phy, &pcie_pll_ratio); + if (err) + return err; + + return 0; +} + + +static inline void miphy28lp_configure_usb3(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + u8 val; + + /* Putting Macro in reset */ + miphy28lp_set_reset(miphy_phy); + + /* PLL calibration */ + miphy28lp_pll_calibration(miphy_phy, &usb3_pll_ratio); + + /* Writing The Speed Rate */ + writeb_relaxed(0x00, base + MIPHY_CONF); + + val = RX_SPDSEL_20DEC | TX_SPDSEL_20DEC; + writeb_relaxed(val, base + MIPHY_SPEED); + + /* RX Channel compensation and calibration */ + writeb_relaxed(0x1c, base + MIPHY_RX_LOCK_SETTINGS_OPT); + writeb_relaxed(0x51, base + MIPHY_RX_CAL_CTRL_1); + writeb_relaxed(0x70, base + MIPHY_RX_CAL_CTRL_2); + + val = OFFSET_COMPENSATION_EN | VGA_OFFSET_POLARITY | + CAL_OFFSET_THRESHOLD_64 | CAL_OFFSET_VGA_64; + writeb_relaxed(val, base + MIPHY_RX_CAL_OFFSET_CTRL); + writeb_relaxed(0x22, base + MIPHY_RX_CAL_VGA_STEP); + writeb_relaxed(0x0e, base + MIPHY_RX_CAL_OPT_LENGTH); + + val = EQ_DC_GAIN | VGA_GAIN; + writeb_relaxed(val, base + MIPHY_RX_BUFFER_CTRL); + writeb_relaxed(0x78, base + MIPHY_RX_EQU_GAIN_1); + writeb_relaxed(0x1b, base + MIPHY_SYNCHAR_CONTROL); + + /* TX compensation offset to re-center TX impedance */ + writeb_relaxed(0x02, base + MIPHY_COMP_POSTP); + + /* Enable GENSEL_SEL and SSC */ + /* TX_SEL=0 swing preemp forced by pipe registres */ + val = SSC_SEL | GENSEL_SEL; + writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL); + + /* MIPHY Bias boost */ + writeb_relaxed(0x00, base + MIPHY_BIAS_BOOST_1); + writeb_relaxed(0xa7, base + MIPHY_BIAS_BOOST_2); + + /* SSC modulation */ + writeb_relaxed(SSC_EN_SW, base + MIPHY_BOUNDARY_2); + + /* MIPHY TX control */ + writeb_relaxed(0x00, base + MIPHY_CONF); + + /* Validate Step component */ + writeb_relaxed(0x5a, base + MIPHY_PLL_SBR_3); + writeb_relaxed(0xa0, base + MIPHY_PLL_SBR_4); + + /* Validate Period component */ + writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2); + writeb_relaxed(0xa1, base + MIPHY_PLL_SBR_4); + + /* Clear any previous request */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + + /* requests the PLL to take in account new parameters */ + writeb_relaxed(0x02, base + MIPHY_PLL_SBR_1); + + /* To be sure there is no other pending requests */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + + /* Rx PI controller settings */ + writeb_relaxed(0xca, base + MIPHY_RX_K_GAIN); + + /* MIPHY RX input bridge control */ + /* INPUT_BRIDGE_EN_SW=1, manual input bridge control[0]=1 */ + writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1); + writeb_relaxed(0x29, base + MIPHY_RX_POWER_CTRL_1); + writeb_relaxed(0x1a, base + MIPHY_RX_POWER_CTRL_2); + + /* MIPHY Reset for usb3 */ + miphy28_usb3_miphy_reset(miphy_phy); +} + +static inline int miphy_is_ready(struct miphy28lp_phy *miphy_phy) +{ + unsigned long finish = jiffies + 5 * HZ; + u8 mask = HFC_PLL | HFC_RDY; + u8 val; + + /* + * For PCIe and USB3 check only that PLL and HFC are ready + * For SATA check also that phy is ready! + */ + if (miphy_phy->type == PHY_TYPE_SATA) + mask |= PHY_RDY; + + do { + val = readb_relaxed(miphy_phy->base + MIPHY_STATUS_1); + if ((val & mask) != mask) + cpu_relax(); + else + return 0; + } while (!time_after_eq(jiffies, finish)); + + return -EBUSY; +} + +static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy) +{ + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + unsigned long finish = jiffies + 5 * HZ; + u32 val; + + if (!miphy_phy->osc_rdy) + return 0; + + if (!miphy_phy->syscfg_miphy_status) + return -EINVAL; + + do { + regmap_read(miphy_dev->regmap, miphy_phy->syscfg_miphy_status, + &val); + + if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY) + cpu_relax(); + else + return 0; + } while (!time_after_eq(jiffies, finish)); + + return -EBUSY; +} + +static int miphy28lp_get_resource_byname(struct device_node *child, + char *rname, struct resource *res) +{ + int index; + + index = of_property_match_string(child, "reg-names", rname); + if (index < 0) + return -ENODEV; + + return of_address_to_resource(child, index, res); +} + +static int miphy28lp_get_one_addr(struct device *dev, + struct device_node *child, char *rname, + void __iomem **base) +{ + struct resource res; + int ret; + + ret = miphy28lp_get_resource_byname(child, rname, &res); + if (!ret) { + *base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!*base) { + dev_err(dev, "failed to ioremap %s address region\n" + , rname); + return -ENOENT; + } + } + + return 0; +} + +/* MiPHY reset and sysconf setup */ +static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val) +{ + int err; + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + + if (!miphy_phy->syscfg_miphy_ctrl) + return -EINVAL; + + err = reset_control_assert(miphy_phy->miphy_rst); + if (err) { + dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n"); + return err; + } + + if (miphy_phy->osc_force_ext) + miphy_val |= MIPHY_OSC_FORCE_EXT; + + regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_miphy_ctrl, + MIPHY_CTRL_MASK, miphy_val); + + err = reset_control_deassert(miphy_phy->miphy_rst); + if (err) { + dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n"); + return err; + } + + return miphy_osc_is_ready(miphy_phy); +} + +static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy) +{ + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + int err, sata_conf = SATA_CTRL_SELECT_SATA; + + if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci) + || (!miphy_phy->base)) + return -EINVAL; + + dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base); + + /* Configure the glue-logic */ + sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE); + + regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata, + SATA_CTRL_MASK, sata_conf); + + regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci, + PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE); + + /* MiPHY path and clocking init */ + err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_DEFAULT); + + if (err) { + dev_err(miphy_dev->dev, "SATA phy setup failed\n"); + return err; + } + + /* initialize miphy */ + miphy28lp_configure_sata(miphy_phy); + + return miphy_is_ready(miphy_phy); +} + +static int miphy28lp_init_pcie(struct miphy28lp_phy *miphy_phy) +{ + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + int err; + + if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci) + || (!miphy_phy->base) || (!miphy_phy->pipebase)) + return -EINVAL; + + dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base); + + /* Configure the glue-logic */ + regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata, + SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE); + + regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci, + PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL); + + /* MiPHY path and clocking init */ + err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_DEFAULT); + + if (err) { + dev_err(miphy_dev->dev, "PCIe phy setup failed\n"); + return err; + } + + /* initialize miphy */ + err = miphy28lp_configure_pcie(miphy_phy); + if (err) + return err; + + /* PIPE Wrapper Configuration */ + writeb_relaxed(0x68, miphy_phy->pipebase + 0x104); /* Rise_0 */ + writeb_relaxed(0x61, miphy_phy->pipebase + 0x105); /* Rise_1 */ + writeb_relaxed(0x68, miphy_phy->pipebase + 0x108); /* Fall_0 */ + writeb_relaxed(0x61, miphy_phy->pipebase + 0x109); /* Fall-1 */ + writeb_relaxed(0x68, miphy_phy->pipebase + 0x10c); /* Threshold_0 */ + writeb_relaxed(0x60, miphy_phy->pipebase + 0x10d); /* Threshold_1 */ + + /* Wait for phy_ready */ + return miphy_is_ready(miphy_phy); +} + +static int miphy28lp_init_usb3(struct miphy28lp_phy *miphy_phy) +{ + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + int err; + + if ((!miphy_phy->base) || (!miphy_phy->pipebase)) + return -EINVAL; + + dev_info(miphy_dev->dev, "usb3-up mode, addr 0x%p\n", miphy_phy->base); + + /* MiPHY path and clocking init */ + err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_SYNC_D_EN); + if (err) { + dev_err(miphy_dev->dev, "USB3 phy setup failed\n"); + return err; + } + + /* initialize miphy */ + miphy28lp_configure_usb3(miphy_phy); + + /* PIPE Wrapper Configuration */ + writeb_relaxed(0x68, miphy_phy->pipebase + 0x23); + writeb_relaxed(0x61, miphy_phy->pipebase + 0x24); + writeb_relaxed(0x68, miphy_phy->pipebase + 0x26); + writeb_relaxed(0x61, miphy_phy->pipebase + 0x27); + writeb_relaxed(0x18, miphy_phy->pipebase + 0x29); + writeb_relaxed(0x61, miphy_phy->pipebase + 0x2a); + + /* pipe Wrapper usb3 TX swing de-emph margin PREEMPH[7:4], SWING[3:0] */ + writeb_relaxed(0X67, miphy_phy->pipebase + 0x68); + writeb_relaxed(0x0d, miphy_phy->pipebase + 0x69); + writeb_relaxed(0X67, miphy_phy->pipebase + 0x6a); + writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6b); + writeb_relaxed(0X67, miphy_phy->pipebase + 0x6c); + writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6d); + writeb_relaxed(0X67, miphy_phy->pipebase + 0x6e); + writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6f); + + return miphy_is_ready(miphy_phy); +} + +static int miphy28lp_init(struct phy *phy) +{ + struct miphy28lp_phy *miphy_phy = phy_get_drvdata(phy); + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + int ret; + + mutex_lock(&miphy_dev->miphy_mutex); + + switch (miphy_phy->type) { + + case PHY_TYPE_SATA: + ret = miphy28lp_init_sata(miphy_phy); + break; + case PHY_TYPE_PCIE: + ret = miphy28lp_init_pcie(miphy_phy); + break; + case PHY_TYPE_USB3: + ret = miphy28lp_init_usb3(miphy_phy); + break; + default: + return -EINVAL; + } + + mutex_unlock(&miphy_dev->miphy_mutex); + + return ret; +} + +static int miphy28lp_get_addr(struct miphy28lp_phy *miphy_phy) +{ + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + struct device_node *phynode = miphy_phy->phy->dev.of_node; + int err; + + if ((miphy_phy->type != PHY_TYPE_SATA) && + (miphy_phy->type != PHY_TYPE_PCIE) && + (miphy_phy->type != PHY_TYPE_USB3)) { + return -EINVAL; + } + + err = miphy28lp_get_one_addr(miphy_dev->dev, phynode, + PHY_TYPE_name[miphy_phy->type - PHY_TYPE_SATA], + &miphy_phy->base); + if (err) + return err; + + if ((miphy_phy->type == PHY_TYPE_PCIE) || + (miphy_phy->type == PHY_TYPE_USB3)) { + err = miphy28lp_get_one_addr(miphy_dev->dev, phynode, "pipew", + &miphy_phy->pipebase); + if (err) + return err; + } + + return 0; +} + +static struct phy *miphy28lp_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct miphy28lp_dev *miphy_dev = dev_get_drvdata(dev); + struct miphy28lp_phy *miphy_phy = NULL; + struct device_node *phynode = args->np; + int ret, index = 0; + + if (!of_device_is_available(phynode)) { + dev_warn(dev, "Requested PHY is disabled\n"); + return ERR_PTR(-ENODEV); + } + + if (args->args_count != 1) { + dev_err(dev, "Invalid number of cells in 'phy' property\n"); + return ERR_PTR(-EINVAL); + } + + for (index = 0; index < of_get_child_count(dev->of_node); index++) + if (phynode == miphy_dev->phys[index]->phy->dev.of_node) { + miphy_phy = miphy_dev->phys[index]; + break; + } + + if (!miphy_phy) { + dev_err(dev, "Failed to find appropriate phy\n"); + return ERR_PTR(-EINVAL); + } + + miphy_phy->type = args->args[0]; + + ret = miphy28lp_get_addr(miphy_phy); + if (ret < 0) + return ERR_PTR(ret); + + return miphy_phy->phy; +} + +static struct phy_ops miphy28lp_ops = { + .init = miphy28lp_init, +}; + +static int miphy28lp_probe_resets(struct device_node *node, + struct miphy28lp_phy *miphy_phy) +{ + struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; + int err; + + miphy_phy->miphy_rst = of_reset_control_get(node, "miphy-sw-rst"); + + if (IS_ERR(miphy_phy->miphy_rst)) { + dev_err(miphy_dev->dev, + "miphy soft reset control not defined\n"); + return PTR_ERR(miphy_phy->miphy_rst); + } + + err = reset_control_deassert(miphy_phy->miphy_rst); + if (err) { + dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n"); + return err; + } + + return 0; +} + +static int miphy28lp_of_probe(struct device_node *np, + struct miphy28lp_phy *miphy_phy) +{ + struct resource res; + + miphy_phy->osc_force_ext = + of_property_read_bool(np, "st,osc-force-ext"); + + miphy_phy->osc_rdy = of_property_read_bool(np, "st,osc-rdy"); + + miphy_phy->px_rx_pol_inv = + of_property_read_bool(np, "st,px_rx_pol_inv"); + + of_property_read_u32(np, "st,sata-gen", &miphy_phy->sata_gen); + if (!miphy_phy->sata_gen) + miphy_phy->sata_gen = SATA_GEN1; + + if (!miphy28lp_get_resource_byname(np, "miphy-ctrl-glue", &res)) + miphy_phy->syscfg_miphy_ctrl = res.start; + + if (!miphy28lp_get_resource_byname(np, "miphy-status-glue", &res)) + miphy_phy->syscfg_miphy_status = res.start; + + if (!miphy28lp_get_resource_byname(np, "pcie-glue", &res)) + miphy_phy->syscfg_pci = res.start; + + if (!miphy28lp_get_resource_byname(np, "sata-glue", &res)) + miphy_phy->syscfg_sata = res.start; + + + return 0; +} + +static int miphy28lp_probe(struct platform_device *pdev) +{ + struct device_node *child, *np = pdev->dev.of_node; + struct miphy28lp_dev *miphy_dev; + struct phy_provider *provider; + struct phy *phy; + int chancount, port = 0; + int ret; + + miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL); + if (!miphy_dev) + return -ENOMEM; + + chancount = of_get_child_count(np); + miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount, + GFP_KERNEL); + if (!miphy_dev->phys) + return -ENOMEM; + + miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(miphy_dev->regmap)) { + dev_err(miphy_dev->dev, "No syscfg phandle specified\n"); + return PTR_ERR(miphy_dev->regmap); + } + + miphy_dev->dev = &pdev->dev; + + dev_set_drvdata(&pdev->dev, miphy_dev); + + mutex_init(&miphy_dev->miphy_mutex); + + for_each_child_of_node(np, child) { + struct miphy28lp_phy *miphy_phy; + + miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy), + GFP_KERNEL); + if (!miphy_phy) + return -ENOMEM; + + miphy_dev->phys[port] = miphy_phy; + + phy = devm_phy_create(&pdev->dev, child, &miphy28lp_ops, NULL); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(phy); + } + + miphy_dev->phys[port]->phy = phy; + miphy_dev->phys[port]->phydev = miphy_dev; + + ret = miphy28lp_of_probe(child, miphy_phy); + if (ret) + return ret; + + ret = miphy28lp_probe_resets(child, miphy_dev->phys[port]); + if (ret) + return ret; + + phy_set_drvdata(phy, miphy_dev->phys[port]); + port++; + + } + + provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate); + if (IS_ERR(provider)) + return PTR_ERR(provider); + + return 0; +} + +static const struct of_device_id miphy28lp_of_match[] = { + {.compatible = "st,miphy28lp-phy", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, miphy28lp_of_match); + +static struct platform_driver miphy28lp_driver = { + .probe = miphy28lp_probe, + .driver = { + .name = "miphy28lp-phy", + .owner = THIS_MODULE, + .of_match_table = miphy28lp_of_match, + } +}; + +module_platform_driver(miphy28lp_driver); + +MODULE_AUTHOR("Alexandre Torgue "); +MODULE_DESCRIPTION("STMicroelectronics miphy28lp driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 2b041b27a83fbe951d4b1cb1523001d4a8a5cccb Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:21 +0100 Subject: phy: miphy28lp: Add SSC support for SATA This patch to tune on/off the ssc on miphy sata setup. User can now enable ssc via dt blob, it is useful to reduce effects of EMI. Signed-off-by: Giuseppe Condorelli Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt index b7c13ad..4a3b4af 100644 --- a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt +++ b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt @@ -39,6 +39,7 @@ Optional properties (port (child) node): register. - st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive line). +- st,scc-on : enable ssc to reduce effects of EMI (only for sata or PCIe). example: diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 7d592e6..d2f797c 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -191,6 +191,8 @@ #define SYSCFG_PCIE_PCIE_VAL 0x80 #define SATA_SPDMODE 1 +#define MIPHY_SATA_BANK_NB 3 + struct miphy28lp_phy { struct phy *phy; struct miphy28lp_dev *phydev; @@ -200,6 +202,7 @@ struct miphy28lp_phy { bool osc_force_ext; bool osc_rdy; bool px_rx_pol_inv; + bool ssc; struct reset_control *miphy_rst; @@ -550,6 +553,44 @@ static inline void miphy28_usb3_miphy_reset(struct miphy28lp_phy *miphy_phy) writeb_relaxed(0x00, base + MIPHY_CONF); } +static void miphy_sata_tune_ssc(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + u8 val; + + /* Compensate Tx impedance to avoid out of range values */ + /* + * Enable the SSC on PLL for all banks + * SSC Modulation @ 31 KHz and 4000 ppm modulation amp + */ + val = readb_relaxed(base + MIPHY_BOUNDARY_2); + val |= SSC_EN_SW; + writeb_relaxed(val, base + MIPHY_BOUNDARY_2); + + val = readb_relaxed(base + MIPHY_BOUNDARY_SEL); + val |= SSC_SEL; + writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL); + + for (val = 0; val < MIPHY_SATA_BANK_NB; val++) { + writeb_relaxed(val, base + MIPHY_CONF); + + /* Add value to each reference clock cycle */ + /* and define the period length of the SSC */ + writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2); + writeb_relaxed(0x6c, base + MIPHY_PLL_SBR_3); + writeb_relaxed(0x81, base + MIPHY_PLL_SBR_4); + + /* Clear any previous request */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + + /* requests the PLL to take in account new parameters */ + writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); + + /* To be sure there is no other pending requests */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + } +} + static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) { void __iomem *base = miphy_phy->base; @@ -585,6 +626,9 @@ static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) writeb_relaxed(val, miphy_phy->base + MIPHY_CONTROL); } + if (miphy_phy->ssc) + miphy_sata_tune_ssc(miphy_phy); + return 0; } @@ -1064,6 +1108,8 @@ static int miphy28lp_of_probe(struct device_node *np, miphy_phy->px_rx_pol_inv = of_property_read_bool(np, "st,px_rx_pol_inv"); + miphy_phy->ssc = of_property_read_bool(np, "st,ssc-on"); + of_property_read_u32(np, "st,sata-gen", &miphy_phy->sata_gen); if (!miphy_phy->sata_gen) miphy_phy->sata_gen = SATA_GEN1; -- cgit v0.10.2 From a2108dee3cd39f7291d013c50c33c2a639a17b42 Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:22 +0100 Subject: phy: miphy28lp: Add SSC support for PCIE SSC is the technique of modulating the operating frequency of a signal slightly to spread its radiated emissions over a range of frequencies. This reduction in the maximum emission for a given frequency helps meet radiated emission requirements. These settings are applicable for PCIE with Internal clock. Signed-off-by: Harsh Gupta Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index d2f797c..d8ff895 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -192,6 +192,7 @@ #define SATA_SPDMODE 1 #define MIPHY_SATA_BANK_NB 3 +#define MIPHY_PCIE_BANK_NB 2 struct miphy28lp_phy { struct phy *phy; @@ -591,6 +592,46 @@ static void miphy_sata_tune_ssc(struct miphy28lp_phy *miphy_phy) } } +static void miphy_pcie_tune_ssc(struct miphy28lp_phy *miphy_phy) +{ + void __iomem *base = miphy_phy->base; + u8 val; + + /* Compensate Tx impedance to avoid out of range values */ + /* + * Enable the SSC on PLL for all banks + * SSC Modulation @ 31 KHz and 4000 ppm modulation amp + */ + val = readb_relaxed(base + MIPHY_BOUNDARY_2); + val |= SSC_EN_SW; + writeb_relaxed(val, base + MIPHY_BOUNDARY_2); + + val = readb_relaxed(base + MIPHY_BOUNDARY_SEL); + val |= SSC_SEL; + writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL); + + for (val = 0; val < MIPHY_PCIE_BANK_NB; val++) { + writeb_relaxed(val, base + MIPHY_CONF); + + /* Validate Step component */ + writeb_relaxed(0x69, base + MIPHY_PLL_SBR_3); + writeb_relaxed(0x21, base + MIPHY_PLL_SBR_4); + + /* Validate Period component */ + writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2); + writeb_relaxed(0x21, base + MIPHY_PLL_SBR_4); + + /* Clear any previous request */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + + /* requests the PLL to take in account new parameters */ + writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1); + + /* To be sure there is no other pending requests */ + writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1); + } +} + static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) { void __iomem *base = miphy_phy->base; @@ -659,6 +700,9 @@ static inline int miphy28lp_configure_pcie(struct miphy28lp_phy *miphy_phy) if (err) return err; + if (miphy_phy->ssc) + miphy_pcie_tune_ssc(miphy_phy); + return 0; } -- cgit v0.10.2 From 28ba384dc5e42a23328dca7e5e72d19e2dd4c9ce Mon Sep 17 00:00:00 2001 From: Gabriel FERNANDEZ Date: Tue, 4 Nov 2014 11:51:23 +0100 Subject: phy: miphy28lp: Tune tx impedance across Soc cuts This patch to compensate tx impedance (Sata, PCIe) depending on Soc cuts the kernel is built for. Signed-off-by: Giuseppe Condorelli Signed-off-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt index 4a3b4af..46a135d 100644 --- a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt +++ b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt @@ -40,6 +40,7 @@ Optional properties (port (child) node): - st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive line). - st,scc-on : enable ssc to reduce effects of EMI (only for sata or PCIe). +- st,tx-impedance-comp : to compensate tx impedance avoiding out of range values. example: diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index d8ff895..87dcc9a 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -204,6 +204,7 @@ struct miphy28lp_phy { bool osc_rdy; bool px_rx_pol_inv; bool ssc; + bool tx_impedance; struct reset_control *miphy_rst; @@ -632,6 +633,12 @@ static void miphy_pcie_tune_ssc(struct miphy28lp_phy *miphy_phy) } } +static inline void miphy_tune_tx_impedance(struct miphy28lp_phy *miphy_phy) +{ + /* Compensate Tx impedance to avoid out of range values */ + writeb_relaxed(0x02, miphy_phy->base + MIPHY_COMP_POSTP); +} + static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) { void __iomem *base = miphy_phy->base; @@ -670,6 +677,9 @@ static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy) if (miphy_phy->ssc) miphy_sata_tune_ssc(miphy_phy); + if (miphy_phy->tx_impedance) + miphy_tune_tx_impedance(miphy_phy); + return 0; } @@ -703,6 +713,9 @@ static inline int miphy28lp_configure_pcie(struct miphy28lp_phy *miphy_phy) if (miphy_phy->ssc) miphy_pcie_tune_ssc(miphy_phy); + if (miphy_phy->tx_impedance) + miphy_tune_tx_impedance(miphy_phy); + return 0; } @@ -1154,6 +1167,9 @@ static int miphy28lp_of_probe(struct device_node *np, miphy_phy->ssc = of_property_read_bool(np, "st,ssc-on"); + miphy_phy->tx_impedance = + of_property_read_bool(np, "st,tx-impedance-comp"); + of_property_read_u32(np, "st,sata-gen", &miphy_phy->sata_gen); if (!miphy_phy->sata_gen) miphy_phy->sata_gen = SATA_GEN1; -- cgit v0.10.2 From 491e049064a4ea69ba4b35bdf614f12bc762a717 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 31 Oct 2014 14:04:20 +0530 Subject: phy: phy-core: use the np present in of_phandle_args to get the PHY Instead of using the node pointer of the PHY provider and then scanning its child nodes to get a reference to the PHY, directly use the node pointer present in of_phandle_args to get a reference to the PHY. Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index ff5eec5..1606ce9 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -414,21 +414,13 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args { struct phy *phy; struct class_dev_iter iter; - struct device_node *node = dev->of_node; - struct device_node *child; class_dev_iter_init(&iter, phy_class, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) { phy = to_phy(dev); - if (node != phy->dev.of_node) { - for_each_child_of_node(node, child) { - if (child == phy->dev.of_node) - goto phy_found; - } + if (args->np != phy->dev.of_node) continue; - } -phy_found: class_dev_iter_exit(&iter); return phy; } -- cgit v0.10.2 From e5ba1c024aa0c21ef1755402fd94fabfd6e18c16 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Nov 2014 08:31:40 -0600 Subject: usb: phy: fsl: Fix build errors commit e47d925 (usb: move the OTG state from the USB PHY to the OTG structure) moved the OTG state from struct usb_phy to struct usb_otg. Unfortunately, even though I fixed quite a few build regressions with that patch already, this one was still missing. Note that this driver still has other randconfig build problems which I'll leave for driver author to fix, as that's less trivial. Reported-by: Fengguang Wu Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index b7f36b2..ab38aa3 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -274,7 +274,7 @@ void b_srp_end(unsigned long foo) fsl_otg_dischrg_vbus(0); srp_wait_done = 1; - if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) && + if ((fsl_otg_dev->phy.otg->state == OTG_STATE_B_SRP_INIT) && fsl_otg_dev->fsm.b_sess_vld) fsl_otg_dev->fsm.b_srp_done = 1; } @@ -624,7 +624,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host) /* Mini-A cable connected */ struct otg_fsm *fsm = &otg_dev->fsm; - otg.state = OTG_STATE_UNDEFINED; + otg->state = OTG_STATE_UNDEFINED; fsm->protocol = PROTO_UNDEF; } } @@ -682,7 +682,7 @@ static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA) { if (!fsl_otg_dev) return -ENODEV; - if (phy->otg.state == OTG_STATE_B_PERIPHERAL) + if (phy->otg->state == OTG_STATE_B_PERIPHERAL) pr_info("FSL OTG: Draw %d mA\n", mA); return 0; @@ -715,7 +715,7 @@ static int fsl_otg_start_srp(struct usb_otg *otg) { struct fsl_otg *otg_dev; - if (!otg || otg.state != OTG_STATE_B_IDLE) + if (!otg || otg->state != OTG_STATE_B_IDLE) return -ENODEV; otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy); @@ -990,10 +990,10 @@ int usb_otg_start(struct platform_device *pdev) * Also: record initial state of ID pin */ if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) { - p_otg->phy->otg.state = OTG_STATE_UNDEFINED; + p_otg->phy.otg->state = OTG_STATE_UNDEFINED; p_otg->fsm.id = 1; } else { - p_otg->phy->otg.state = OTG_STATE_A_IDLE; + p_otg->phy.otg->state = OTG_STATE_A_IDLE; p_otg->fsm.id = 0; } @@ -1048,7 +1048,7 @@ static int show_fsl_usb2_otg_state(struct device *dev, /* State */ t = scnprintf(next, size, "OTG state: %s\n\n", - usb_otg_state_string(fsl_otg_dev->phy.state)); + usb_otg_state_string(fsl_otg_dev->phy.otg->state)); size -= t; next += t; diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h index 5986c96..2314995 100644 --- a/drivers/usb/phy/phy-fsl-usb.h +++ b/drivers/usb/phy/phy-fsl-usb.h @@ -298,7 +298,7 @@ /* SE0 Time Before SRP */ #define TB_SE0_SRP (2) /* b_idle,minimum 2 ms, section:5.3.2 */ -#define SET_OTG_STATE(otg_ptr, newstate) ((otg_ptr)->state = newstate) +#define SET_OTG_STATE(phy, newstate) ((phy)->otg->state = newstate) struct usb_dr_mmap { /* Capability register */ -- cgit v0.10.2 From 0fc57ea0595e2d12eb4d5c8509d4b4aec864c9c5 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 12 Nov 2014 22:44:05 +0800 Subject: usb: gadget: f_hid: hidg_alloc() can be static drivers/usb/gadget/function/f_hid.c:852:21: sparse: symbol 'hidg_alloc' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 56ca3fc..7d18f41 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -913,7 +913,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) usb_free_all_descriptors(f); } -struct usb_function *hidg_alloc(struct usb_function_instance *fi) +static struct usb_function *hidg_alloc(struct usb_function_instance *fi) { struct f_hidg *hidg; struct f_hid_opts *opts; -- cgit v0.10.2 From f509fee81fa205c664ea4e446b6d8a8caae38c35 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 12 Nov 2014 21:28:24 +0800 Subject: usb: gadget: midi: f_midi_alloc() can be static drivers/usb/gadget/function/f_midi.c:1072:21: sparse: symbol 'f_midi_alloc' was not declared. Should it be static? drivers/usb/gadget/legacy/gmidi.c:118:30: sparse: symbol 'fi_midi' was not declared. Should it be static? drivers/usb/gadget/legacy/gmidi.c:119:21: sparse: symbol 'f_midi' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 1f94dad..a904403 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1097,7 +1097,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) usb_free_all_descriptors(f); } -struct usb_function *f_midi_alloc(struct usb_function_instance *fi) +static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) { struct f_midi *midi; struct f_midi_opts *opts; diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index 0d01e46..e02a095 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -115,8 +115,8 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; -struct usb_function_instance *fi_midi; -struct usb_function *f_midi; +static struct usb_function_instance *fi_midi; +static struct usb_function *f_midi; static int __exit midi_unbind(struct usb_composite_dev *dev) { -- cgit v0.10.2 From c907e423530f40132f258cafb0ec709b30a6bd29 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 10 Nov 2014 20:02:44 +0900 Subject: usb: renesas_usbhs: change d{0,1}fifo to dfifo array To extend DnFIFOs in the future, this patch changes d{0,1}fifo of usbhs_fifo_info to dfifo array. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 9b48384..341508a 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -21,8 +21,8 @@ #include "pipe.h" #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) -#define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo)) -#define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo)) +#define usbhsf_get_d0fifo(p) (&((p)->fifo_info.dfifo[0])) +#define usbhsf_get_d1fifo(p) (&((p)->fifo_info.dfifo[1])) #define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f) #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index 79ad5f9..e1e51c6 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -38,10 +38,10 @@ struct usbhs_fifo { struct sh_dmae_slave rx_slave; }; +#define USBHS_MAX_NUM_DFIFO 2 struct usbhs_fifo_info { struct usbhs_fifo cfifo; - struct usbhs_fifo d0fifo; - struct usbhs_fifo d1fifo; + struct usbhs_fifo dfifo[USBHS_MAX_NUM_DFIFO]; }; struct usbhs_pkt_handle; -- cgit v0.10.2 From 3a2634a5b4aadc08c3bbe316fd03524ca1300572 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 10 Nov 2014 20:02:45 +0900 Subject: usb: renesas_usbhs: standardize d{0,1}fifo control To expand DnFIFOs in the future, this patch standardizes the d{0,1}fifo control using new macros. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 341508a..6c775b7 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -21,8 +21,6 @@ #include "pipe.h" #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) -#define usbhsf_get_d0fifo(p) (&((p)->fifo_info.dfifo[0])) -#define usbhsf_get_d1fifo(p) (&((p)->fifo_info.dfifo[1])) #define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f) #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ @@ -761,18 +759,13 @@ static struct usbhs_fifo *usbhsf_get_dma_fifo(struct usbhs_priv *priv, struct usbhs_pkt *pkt) { struct usbhs_fifo *fifo; + int i; - /* DMA :: D0FIFO */ - fifo = usbhsf_get_d0fifo(priv); - if (usbhsf_dma_chan_get(fifo, pkt) && - !usbhsf_fifo_is_busy(fifo)) - return fifo; - - /* DMA :: D1FIFO */ - fifo = usbhsf_get_d1fifo(priv); - if (usbhsf_dma_chan_get(fifo, pkt) && - !usbhsf_fifo_is_busy(fifo)) - return fifo; + usbhs_for_each_dfifo(priv, fifo, i) { + if (usbhsf_dma_chan_get(fifo, pkt) && + !usbhsf_fifo_is_busy(fifo)) + return fifo; + } return NULL; } @@ -1185,8 +1178,8 @@ void usbhs_fifo_init(struct usbhs_priv *priv) { struct usbhs_mod *mod = usbhs_mod_get_current(priv); struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); - struct usbhs_fifo *d0fifo = usbhsf_get_d0fifo(priv); - struct usbhs_fifo *d1fifo = usbhsf_get_d1fifo(priv); + struct usbhs_fifo *dfifo; + int i; mod->irq_empty = usbhsf_irq_empty; mod->irq_ready = usbhsf_irq_ready; @@ -1194,8 +1187,8 @@ void usbhs_fifo_init(struct usbhs_priv *priv) mod->irq_brdysts = 0; cfifo->pipe = NULL; - d0fifo->pipe = NULL; - d1fifo->pipe = NULL; + usbhs_for_each_dfifo(priv, dfifo, i) + dfifo->pipe = NULL; } void usbhs_fifo_quit(struct usbhs_priv *priv) @@ -1208,6 +1201,20 @@ void usbhs_fifo_quit(struct usbhs_priv *priv) mod->irq_brdysts = 0; } +#define USBHS_DFIFO_INIT(priv, fifo, channel) \ +do { \ + fifo = usbhsf_get_dnfifo(priv, channel); \ + fifo->name = "D"#channel"FIFO"; \ + fifo->port = D##channel##FIFO; \ + fifo->sel = D##channel##FIFOSEL; \ + fifo->ctr = D##channel##FIFOCTR; \ + fifo->tx_slave.shdma_slave.slave_id = \ + usbhs_get_dparam(priv, d##channel##_tx_id); \ + fifo->rx_slave.shdma_slave.slave_id = \ + usbhs_get_dparam(priv, d##channel##_rx_id); \ + usbhsf_dma_init(priv, fifo); \ +} while (0) + int usbhs_fifo_probe(struct usbhs_priv *priv) { struct usbhs_fifo *fifo; @@ -1219,31 +1226,18 @@ int usbhs_fifo_probe(struct usbhs_priv *priv) fifo->sel = CFIFOSEL; fifo->ctr = CFIFOCTR; - /* D0FIFO */ - fifo = usbhsf_get_d0fifo(priv); - fifo->name = "D0FIFO"; - fifo->port = D0FIFO; - fifo->sel = D0FIFOSEL; - fifo->ctr = D0FIFOCTR; - fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id); - fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id); - usbhsf_dma_init(priv, fifo); - - /* D1FIFO */ - fifo = usbhsf_get_d1fifo(priv); - fifo->name = "D1FIFO"; - fifo->port = D1FIFO; - fifo->sel = D1FIFOSEL; - fifo->ctr = D1FIFOCTR; - fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id); - fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id); - usbhsf_dma_init(priv, fifo); + /* DFIFO */ + USBHS_DFIFO_INIT(priv, fifo, 0); + USBHS_DFIFO_INIT(priv, fifo, 1); return 0; } void usbhs_fifo_remove(struct usbhs_priv *priv) { - usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv)); - usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv)); + struct usbhs_fifo *fifo; + int i; + + usbhs_for_each_dfifo(priv, fifo, i) + usbhsf_dma_quit(priv, fifo); } diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index e1e51c6..899729a 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -43,6 +43,11 @@ struct usbhs_fifo_info { struct usbhs_fifo cfifo; struct usbhs_fifo dfifo[USBHS_MAX_NUM_DFIFO]; }; +#define usbhsf_get_dnfifo(p, n) (&((p)->fifo_info.dfifo[n])) +#define usbhs_for_each_dfifo(priv, dfifo, i) \ + for ((i) = 0, dfifo = usbhsf_get_dnfifo(priv, (i)); \ + ((i) < USBHS_MAX_NUM_DFIFO); \ + (i)++, dfifo = usbhsf_get_dnfifo(priv, (i))) struct usbhs_pkt_handle; struct usbhs_pkt { -- cgit v0.10.2 From 53e734b1ec13af5e4d687681275a56acfde646ba Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 10 Nov 2014 20:02:46 +0900 Subject: usb: renesas_usbhs: add a new macro for extending DnFIFOs To extend DnFIFOs in the future, this patch adds a new macro because some SoCs don't the "port" address for DnFIFOs. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 6c775b7..bc9a050 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -1201,11 +1201,11 @@ void usbhs_fifo_quit(struct usbhs_priv *priv) mod->irq_brdysts = 0; } -#define USBHS_DFIFO_INIT(priv, fifo, channel) \ +#define __USBHS_DFIFO_INIT(priv, fifo, channel, fifo_port) \ do { \ fifo = usbhsf_get_dnfifo(priv, channel); \ fifo->name = "D"#channel"FIFO"; \ - fifo->port = D##channel##FIFO; \ + fifo->port = fifo_port; \ fifo->sel = D##channel##FIFOSEL; \ fifo->ctr = D##channel##FIFOCTR; \ fifo->tx_slave.shdma_slave.slave_id = \ @@ -1215,6 +1215,11 @@ do { \ usbhsf_dma_init(priv, fifo); \ } while (0) +#define USBHS_DFIFO_INIT(priv, fifo, channel) \ + __USBHS_DFIFO_INIT(priv, fifo, channel, D##channel##FIFO) +#define USBHS_DFIFO_INIT_NO_PORT(priv, fifo, channel) \ + __USBHS_DFIFO_INIT(priv, fifo, channel, 0) + int usbhs_fifo_probe(struct usbhs_priv *priv) { struct usbhs_fifo *fifo; -- cgit v0.10.2 From d3cf6a4b01894e69e9e800ef76f34eaa13357ff1 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 10 Nov 2014 20:02:47 +0900 Subject: usb: renesas_usbhs: expand USB-DMAC channels for R-Car Gen2 This patch expands USB-DMAC channels for R-Car Gen2 SoCs. The SoCs have 4 channels. If d{2,3}_{t,x}x_id are not set, this driver never uses the expanded USB-DMAC channels. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index c45667f..0427cdd 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -102,6 +102,10 @@ struct usbhs_priv; #define DEVADD8 0x00E0 #define DEVADD9 0x00E2 #define DEVADDA 0x00E4 +#define D2FIFOSEL 0x00F0 /* for R-Car Gen2 */ +#define D2FIFOCTR 0x00F2 /* for R-Car Gen2 */ +#define D3FIFOSEL 0x00F4 /* for R-Car Gen2 */ +#define D3FIFOCTR 0x00F6 /* for R-Car Gen2 */ /* SYSCFG */ #define SCKE (1 << 10) /* USB Module Clock Enable */ diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index bc9a050..f46271c 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -1234,6 +1234,8 @@ int usbhs_fifo_probe(struct usbhs_priv *priv) /* DFIFO */ USBHS_DFIFO_INIT(priv, fifo, 0); USBHS_DFIFO_INIT(priv, fifo, 1); + USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 2); + USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 3); return 0; } diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index 899729a..f07037c1 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -38,7 +38,7 @@ struct usbhs_fifo { struct sh_dmae_slave rx_slave; }; -#define USBHS_MAX_NUM_DFIFO 2 +#define USBHS_MAX_NUM_DFIFO 4 struct usbhs_fifo_info { struct usbhs_fifo cfifo; struct usbhs_fifo dfifo[USBHS_MAX_NUM_DFIFO]; diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index d5952bb..9fd9e48 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -145,6 +145,10 @@ struct renesas_usbhs_driver_param { int d0_rx_id; int d1_tx_id; int d1_rx_id; + int d2_tx_id; + int d2_rx_id; + int d3_tx_id; + int d3_rx_id; /* * option: -- cgit v0.10.2 From 0cf884e819e05437287a668b9bfcc198bab6329c Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Mon, 10 Nov 2014 21:09:43 +0800 Subject: usb: dwc2: add bus suspend/resume for dwc2 Hcd controller needs bus_suspend/resume, dwc2 controller make root hub generate suspend/resume signal with hprt0 register when work in host mode. After the root hub enter suspend, we can make controller enter low power state with PCGCTL register. We also update the lx_state for hsotg state. This patch has tested on rk3288 with suspend/resume. Signed-off-by: Kever Yang Acked-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 0a0e6f0..7480078 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -1471,6 +1471,30 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) } } +static void dwc2_port_resume(struct dwc2_hsotg *hsotg) +{ + u32 hprt0; + + /* After clear the Stop PHY clock bit, we should wait for a moment + * for PLL work stable with clock output. + */ + writel(0, hsotg->regs + PCGCTL); + usleep_range(2000, 4000); + + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_RES; + writel(hprt0, hsotg->regs + HPRT0); + hprt0 &= ~HPRT0_SUSP; + /* according to USB2.0 Spec 7.1.7.7, the host must send the resume + * signal for at least 20ms + */ + usleep_range(20000, 25000); + + hprt0 &= ~HPRT0_RES; + writel(hprt0, hsotg->regs + HPRT0); + hsotg->lx_state = DWC2_L0; +} + /* Handles hub class-specific requests */ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, u16 wvalue, u16 windex, char *buf, u16 wlength) @@ -1516,17 +1540,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, case USB_PORT_FEAT_SUSPEND: dev_dbg(hsotg->dev, "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); - writel(0, hsotg->regs + PCGCTL); - usleep_range(20000, 40000); - - hprt0 = dwc2_read_hprt0(hsotg); - hprt0 |= HPRT0_RES; - writel(hprt0, hsotg->regs + HPRT0); - hprt0 &= ~HPRT0_SUSP; - usleep_range(100000, 150000); - - hprt0 &= ~HPRT0_RES; - writel(hprt0, hsotg->regs + HPRT0); + dwc2_port_resume(hsotg); break; case USB_PORT_FEAT_POWER: @@ -2299,6 +2313,55 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) usleep_range(1000, 3000); } +static int _dwc2_hcd_suspend(struct usb_hcd *hcd) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + u32 hprt0; + + if (!((hsotg->op_state == OTG_STATE_B_HOST) || + (hsotg->op_state == OTG_STATE_A_HOST))) + return 0; + + /* TODO: We get into suspend from 'on' state, maybe we need to do + * something if we get here from DWC2_L1(LPM sleep) state one day. + */ + if (hsotg->lx_state != DWC2_L0) + return 0; + + hprt0 = dwc2_read_hprt0(hsotg); + if (hprt0 & HPRT0_CONNSTS) { + dwc2_port_suspend(hsotg, 1); + } else { + u32 pcgctl = readl(hsotg->regs + PCGCTL); + + pcgctl |= PCGCTL_STOPPCLK; + writel(pcgctl, hsotg->regs + PCGCTL); + } + + return 0; +} + +static int _dwc2_hcd_resume(struct usb_hcd *hcd) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + u32 hprt0; + + if (!((hsotg->op_state == OTG_STATE_B_HOST) || + (hsotg->op_state == OTG_STATE_A_HOST))) + return 0; + + if (hsotg->lx_state != DWC2_L2) + return 0; + + hprt0 = dwc2_read_hprt0(hsotg); + if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP)) + dwc2_port_resume(hsotg); + else + writel(0, hsotg->regs + PCGCTL); + + return 0; +} + /* Returns the current frame number */ static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd) { @@ -2669,6 +2732,9 @@ static struct hc_driver dwc2_hc_driver = { .hub_status_data = _dwc2_hcd_hub_status_data, .hub_control = _dwc2_hcd_hub_control, .clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete, + + .bus_suspend = _dwc2_hcd_suspend, + .bus_resume = _dwc2_hcd_resume, }; /* -- cgit v0.10.2 From 6827a46f59942208d45e0c40e53f649bfc7792ed Mon Sep 17 00:00:00 2001 From: Roman Byshko Date: Mon, 10 Nov 2014 19:55:06 +0100 Subject: phy: sun4i: add support for USB phy0 The driver for sun4i USB phys currently supports only phy1 and phy2 which are used for USB host controllers. This patch adds support for USB phy0, which is used by the musb hdrc USB controller. Signed-off-by: Roman Byshko Acked-by: Maxime Ripard Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 0baf5ef..6bd2b0c 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -157,6 +157,10 @@ static int sun4i_usb_phy_init(struct phy *_phy) return ret; } + /* Enable USB 45 Ohm resistor calibration */ + if (phy->index == 0) + sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1); + /* Adjust PHY's magnitude and rate */ sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); @@ -213,7 +217,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, { struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); - if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys)) + if (args->args[0] >= data->num_phys) return ERR_PTR(-ENODEV); return data->phys[args->args[0]].phy; @@ -255,8 +259,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) if (IS_ERR(data->base)) return PTR_ERR(data->base); - /* Skip 0, 0 is the phy for otg which is not yet supported. */ - for (i = 1; i < data->num_phys; i++) { + for (i = 0; i < data->num_phys; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[16]; -- cgit v0.10.2 From a98d41d6a1204b61bac03bb3eabdbc2fe93b495d Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Thu, 30 Oct 2014 11:21:24 +0100 Subject: phy: berlin-sata: Move PHY_BASE into private data struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, Berlin SATA PHY driver assumes PHY_BASE address being constant. While this PHY_BASE is correct for BG2Q, older BG2 PHY_BASE is different. Prepare the driver for BG2 support by moving the phy_base into private driver data. Acked-by: Antoine Ténart Signed-off-by: Sebastian Hesselbarth Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index 69ced52..cdb46d1 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -30,7 +30,7 @@ #define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16) #define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19) -#define PHY_BASE 0x200 +#define BG2Q_PHY_BASE 0x200 /* register 0x01 */ #define REF_FREF_SEL_25 BIT(0) @@ -61,15 +61,16 @@ struct phy_berlin_priv { struct clk *clk; struct phy_berlin_desc **phys; unsigned nphys; + u32 phy_base; }; -static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg, - u32 mask, u32 val) +static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, + u32 phy_base, u32 reg, u32 mask, u32 val) { u32 regval; /* select register */ - writel(PHY_BASE + reg, ctrl_reg + PORT_VSR_ADDR); + writel(phy_base + reg, ctrl_reg + PORT_VSR_ADDR); /* set bits */ regval = readl(ctrl_reg + PORT_VSR_DATA); @@ -103,17 +104,20 @@ static int phy_berlin_sata_power_on(struct phy *phy) writel(regval, priv->base + HOST_VSA_DATA); /* set PHY mode and ref freq to 25 MHz */ - phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff, - REF_FREF_SEL_25 | PHY_MODE_SATA); + phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01, + 0x00ff, REF_FREF_SEL_25 | PHY_MODE_SATA); /* set PHY up to 6 Gbps */ - phy_berlin_sata_reg_setbits(ctrl_reg, 0x25, 0xc00, PHY_GEN_MAX_6_0); + phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x25, + 0x0c00, PHY_GEN_MAX_6_0); /* set 40 bits width */ - phy_berlin_sata_reg_setbits(ctrl_reg, 0x23, 0xc00, DATA_BIT_WIDTH_40); + phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x23, + 0x0c00, DATA_BIT_WIDTH_40); /* use max pll rate */ - phy_berlin_sata_reg_setbits(ctrl_reg, 0x2, 0x0, USE_MAX_PLL_RATE); + phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x02, + 0x0000, USE_MAX_PLL_RATE); /* set Gen3 controller speed */ regval = readl(ctrl_reg + PORT_SCR_CTL); @@ -218,6 +222,8 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) if (!priv->phys) return -ENOMEM; + priv->phy_base = BG2Q_PHY_BASE; + dev_set_drvdata(dev, priv); spin_lock_init(&priv->lock); -- cgit v0.10.2 From 8203f8b4619a158a685ba317356a679b5f1ac422 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Thu, 30 Oct 2014 11:21:25 +0100 Subject: phy: berlin-sata: Add support for BG2 SATA PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Berlin BG2 also has a SATA PHY compatible with the current driver except different PHY_BASE. Add a new compatible to the driver reflecting the different PHY_BASE. Acked-by: Antoine Ténart Signed-off-by: Sebastian Hesselbarth Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index cdb46d1..873e7a8 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -30,6 +30,7 @@ #define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16) #define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19) +#define BG2_PHY_BASE 0x080 #define BG2Q_PHY_BASE 0x200 /* register 0x01 */ @@ -222,7 +223,10 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) if (!priv->phys) return -ENOMEM; - priv->phy_base = BG2Q_PHY_BASE; + if (of_device_is_compatible(dev->of_node, "marvell,berlin2-sata-phy")) + priv->phy_base = BG2_PHY_BASE; + else + priv->phy_base = BG2Q_PHY_BASE; dev_set_drvdata(dev, priv); spin_lock_init(&priv->lock); @@ -271,6 +275,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) } static const struct of_device_id phy_berlin_sata_of_match[] = { + { .compatible = "marvell,berlin2-sata-phy" }, { .compatible = "marvell,berlin2q-sata-phy" }, { }, }; -- cgit v0.10.2 From ec4637bfff1c7d5f2bc7e51d180dd4aa51883af0 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Thu, 30 Oct 2014 11:21:26 +0100 Subject: phy: berlin-sata: Document BG2 compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Berlin BG2 SATA PHY is slightly different from currently supported BG2Q SATA PHY. Document the new compatible for BG2's PHY. Acked-by: Antoine Ténart Signed-off-by: Sebastian Hesselbarth Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt b/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt index 88f8c23..c0155f8 100644 --- a/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt +++ b/Documentation/devicetree/bindings/phy/berlin-sata-phy.txt @@ -2,7 +2,9 @@ Berlin SATA PHY --------------- Required properties: -- compatible: should be "marvell,berlin2q-sata-phy" +- compatible: should be one of + "marvell,berlin2-sata-phy" + "marvell,berlin2q-sata-phy" - address-cells: should be 1 - size-cells: should be 0 - phy-cells: from the generic PHY bindings, must be 1 -- cgit v0.10.2 From 941fcce4ff6701c5a7d673d0abb063a7de1234bf Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:33 -0600 Subject: usb: dwc2: Update the gadget driver to use common dwc2_hsotg structure Adds the gadget data structure and appropriate data structure pointers to the common dwc2_hsotg data structure. To keep the driver data dereference code looking clean, the gadget variable declares are only available for peripheral and dual-role mode. This is needed so that the dwc2_hsotg data structure can be used by the hcd and gadget drivers. Updates gadget.c to use the dwc2_hsotg data structure and gadget pointers that have been moved into the common dwc2_hsotg structure. Signed-off-by: Dinh Nguyen Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 55c90c5..7bcdc10 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -84,7 +84,7 @@ static const char * const s3c_hsotg_supply_names[] = { */ #define EP0_MPS_LIMIT 64 -struct s3c_hsotg; +struct dwc2_hsotg; struct s3c_hsotg_req; /** @@ -130,7 +130,7 @@ struct s3c_hsotg_req; struct s3c_hsotg_ep { struct usb_ep ep; struct list_head queue; - struct s3c_hsotg *parent; + struct dwc2_hsotg *parent; struct s3c_hsotg_req *req; struct dentry *debugfs; @@ -155,67 +155,6 @@ struct s3c_hsotg_ep { }; /** - * struct s3c_hsotg - driver state. - * @dev: The parent device supplied to the probe function - * @driver: USB gadget driver - * @phy: The otg phy transceiver structure for phy control. - * @uphy: The otg phy transceiver structure for old USB phy control. - * @plat: The platform specific configuration data. This can be removed once - * all SoCs support usb transceiver. - * @regs: The memory area mapped for accessing registers. - * @irq: The IRQ number we are using - * @supplies: Definition of USB power supplies - * @phyif: PHY interface width - * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. - * @num_of_eps: Number of available EPs (excluding EP0) - * @debug_root: root directrory for debugfs. - * @debug_file: main status file for debugfs. - * @debug_fifo: FIFO status file for debugfs. - * @ep0_reply: Request used for ep0 reply. - * @ep0_buff: Buffer for EP0 reply data, if needed. - * @ctrl_buff: Buffer for EP0 control requests. - * @ctrl_req: Request for EP0 control packets. - * @setup: NAK management for EP0 SETUP - * @last_rst: Time of last reset - * @eps: The endpoints being supplied to the gadget framework - */ -struct s3c_hsotg { - struct device *dev; - struct usb_gadget_driver *driver; - struct phy *phy; - struct usb_phy *uphy; - struct s3c_hsotg_plat *plat; - - spinlock_t lock; - - void __iomem *regs; - int irq; - struct clk *clk; - - struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; - - u32 phyif; - int fifo_mem; - unsigned int dedicated_fifos:1; - unsigned char num_of_eps; - u32 fifo_map; - - struct dentry *debug_root; - struct dentry *debug_file; - struct dentry *debug_fifo; - - struct usb_request *ep0_reply; - struct usb_request *ctrl_req; - u8 ep0_buff[8]; - u8 ctrl_buff[8]; - - struct usb_gadget gadget; - unsigned int setup; - unsigned long last_rst; - struct s3c_hsotg_ep *eps; -}; - -/** * struct s3c_hsotg_req - data transfer request * @req: The USB gadget request * @queue: The list of requests for the endpoint this is queued for. @@ -229,6 +168,7 @@ struct s3c_hsotg_req { unsigned char mapped; }; +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) #define call_gadget(_hs, _entry) \ do { \ if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ @@ -238,6 +178,9 @@ do { \ spin_lock(&_hs->lock); \ } \ } while (0) +#else +#define call_gadget(_hs, _entry) do {} while (0) +#endif struct dwc2_hsotg; struct dwc2_host_chan; @@ -495,11 +438,13 @@ struct dwc2_hw_params { * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic * and periodic schedules * + * These are common for both host and peripheral modes: + * * @dev: The struct device pointer * @regs: Pointer to controller regs - * @core_params: Parameters that define how the core should be configured * @hw_params: Parameters that were autodetected from the * hardware registers + * @core_params: Parameters that define how the core should be configured * @op_state: The operational State, during transitions (a_host=> * a_peripheral and b_device=>b_host) this may not match * the core, but allows the software to determine @@ -508,6 +453,8 @@ struct dwc2_hw_params { * - USB_DR_MODE_PERIPHERAL * - USB_DR_MODE_HOST * - USB_DR_MODE_OTG + * @lock: Spinlock that protects all the driver data structures + * @priv: Stores a pointer to the struct usb_hcd * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth * transfer are in process of being queued * @srp_success: Stores status of SRP request in the case of a FS PHY @@ -517,6 +464,9 @@ struct dwc2_hw_params { * interrupt * @wkp_timer: Timer object for handling Wakeup Detected interrupt * @lx_state: Lx state of connected device + * + * These are for host mode: + * * @flags: Flags for handling root port state changes * @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule. * Transfers associated with these QHs are not currently @@ -585,11 +535,31 @@ struct dwc2_hw_params { * @status_buf_dma: DMA address for status_buf * @start_work: Delayed work for handling host A-cable connection * @reset_work: Delayed work for handling a port reset - * @lock: Spinlock that protects all the driver data structures - * @priv: Stores a pointer to the struct usb_hcd * @otg_port: OTG port number * @frame_list: Frame list * @frame_list_dma: Frame list DMA address + * + * These are for peripheral mode: + * + * @driver: USB gadget driver + * @phy: The otg phy transceiver structure for phy control. + * @uphy: The otg phy transceiver structure for old USB phy control. + * @plat: The platform specific configuration data. This can be removed once + * all SoCs support usb transceiver. + * @supplies: Definition of USB power supplies + * @phyif: PHY interface width + * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. + * @num_of_eps: Number of available EPs (excluding EP0) + * @debug_root: Root directrory for debugfs. + * @debug_file: Main status file for debugfs. + * @debug_fifo: FIFO status file for debugfs. + * @ep0_reply: Request used for ep0 reply. + * @ep0_buff: Buffer for EP0 reply data, if needed. + * @ctrl_buff: Buffer for EP0 control requests. + * @ctrl_req: Request for EP0 control packets. + * @setup: NAK management for EP0 SETUP + * @last_rst: Time of last reset + * @eps: The endpoints being supplied to the gadget framework */ struct dwc2_hsotg { struct device *dev; @@ -601,6 +571,15 @@ struct dwc2_hsotg { enum usb_otg_state op_state; enum usb_dr_mode dr_mode; + struct phy *phy; + struct usb_phy *uphy; + struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + + spinlock_t lock; + void *priv; + int irq; + struct clk *clk; + unsigned int queuing_high_bandwidth:1; unsigned int srp_success:1; @@ -609,6 +588,18 @@ struct dwc2_hsotg { struct timer_list wkp_timer; enum dwc2_lx_state lx_state; + struct dentry *debug_root; + struct dentry *debug_file; + struct dentry *debug_fifo; + + /* DWC OTG HW Release versions */ +#define DWC2_CORE_REV_2_71a 0x4f54271a +#define DWC2_CORE_REV_2_90a 0x4f54290a +#define DWC2_CORE_REV_2_92a 0x4f54292a +#define DWC2_CORE_REV_2_94a 0x4f54294a +#define DWC2_CORE_REV_3_00a 0x4f54300a + +#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) union dwc2_hcd_internal_flags { u32 d32; struct { @@ -655,19 +646,10 @@ struct dwc2_hsotg { struct delayed_work start_work; struct delayed_work reset_work; - spinlock_t lock; - void *priv; u8 otg_port; u32 *frame_list; dma_addr_t frame_list_dma; - /* DWC OTG HW Release versions */ -#define DWC2_CORE_REV_2_71a 0x4f54271a -#define DWC2_CORE_REV_2_90a 0x4f54290a -#define DWC2_CORE_REV_2_92a 0x4f54292a -#define DWC2_CORE_REV_2_94a 0x4f54294a -#define DWC2_CORE_REV_3_00a 0x4f54300a - #ifdef DEBUG u32 frrem_samples; u64 frrem_accum; @@ -686,6 +668,29 @@ struct dwc2_hsotg { u32 hfnum_other_samples_b; u64 hfnum_other_frrem_accum_b; #endif +#endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */ + +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) + /* Gadget structures */ + struct usb_gadget_driver *driver; + struct s3c_hsotg_plat *plat; + + u32 phyif; + int fifo_mem; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; + u32 fifo_map; + + struct usb_request *ep0_reply; + struct usb_request *ctrl_req; + u8 ep0_buff[8]; + u8 ctrl_buff[8]; + + struct usb_gadget gadget; + unsigned int setup; + unsigned long last_rst; + struct s3c_hsotg_ep *eps; +#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ }; /* Reasons for halting a host channel */ diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index fcd2bb5..5a24e95 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -36,6 +36,7 @@ #include #include "core.h" +#include "hw.h" /* conversion functions */ static inline struct s3c_hsotg_req *our_req(struct usb_request *req) @@ -48,9 +49,9 @@ static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep) return container_of(ep, struct s3c_hsotg_ep, ep); } -static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget) +static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) { - return container_of(gadget, struct s3c_hsotg, gadget); + return container_of(gadget, struct dwc2_hsotg, gadget); } static inline void __orr32(void __iomem *ptr, u32 val) @@ -64,7 +65,7 @@ static inline void __bic32(void __iomem *ptr, u32 val) } /* forward decleration of functions */ -static void s3c_hsotg_dump(struct s3c_hsotg *hsotg); +static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg); /** * using_dma - return the DMA status of the driver. @@ -85,7 +86,7 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg); * * Until this issue is sorted out, we always return 'false'. */ -static inline bool using_dma(struct s3c_hsotg *hsotg) +static inline bool using_dma(struct dwc2_hsotg *hsotg) { return false; /* support is not complete */ } @@ -95,7 +96,7 @@ static inline bool using_dma(struct s3c_hsotg *hsotg) * @hsotg: The device state * @ints: A bitmask of the interrupts to enable */ -static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) +static void s3c_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) { u32 gsintmsk = readl(hsotg->regs + GINTMSK); u32 new_gsintmsk; @@ -113,7 +114,7 @@ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) * @hsotg: The device state * @ints: A bitmask of the interrupts to enable */ -static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) +static void s3c_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) { u32 gsintmsk = readl(hsotg->regs + GINTMSK); u32 new_gsintmsk; @@ -134,7 +135,7 @@ static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) * Set or clear the mask for an individual endpoint's interrupt * request. */ -static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, +static void s3c_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, unsigned int ep, unsigned int dir_in, unsigned int en) { @@ -159,7 +160,7 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, * s3c_hsotg_init_fifo - initialise non-periodic FIFOs * @hsotg: The device instance. */ -static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) +static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg) { unsigned int ep; unsigned int addr; @@ -283,7 +284,7 @@ static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) * This is the reverse of s3c_hsotg_map_dma(), called for the completion * of a request to ensure the buffer is ready for access by the caller. */ -static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, +static void s3c_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req) { @@ -312,7 +313,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, * * This routine is only needed for PIO */ -static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, +static int s3c_hsotg_write_fifo(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req) { @@ -517,7 +518,7 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) * Start the given request running by setting the endpoint registers * appropriately, and writing any data to the FIFOs. */ -static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, +static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req, bool continuing) @@ -707,7 +708,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, * DMA memory, then we map the memory and mark our request to allow us to * cleanup on completion. */ -static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, +static int s3c_hsotg_map_dma(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct usb_request *req) { @@ -736,7 +737,7 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, { struct s3c_hsotg_req *hs_req = our_req(req); struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; + struct dwc2_hsotg *hs = hs_ep->parent; bool first; dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", @@ -768,7 +769,7 @@ static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; + struct dwc2_hsotg *hs = hs_ep->parent; unsigned long flags = 0; int ret = 0; @@ -799,7 +800,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, struct usb_request *req) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; + struct dwc2_hsotg *hsotg = hs_ep->parent; dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); @@ -814,7 +815,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, * Convert the given wIndex into a pointer to an driver endpoint * structure, or return NULL if it is not a valid endpoint. */ -static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, +static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, u32 windex) { struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F]; @@ -843,7 +844,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, * Create a request and queue it on the given endpoint. This is useful as * an internal method of sending replies to certain control requests, etc. */ -static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg, +static int s3c_hsotg_send_reply(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *ep, void *buff, int length) @@ -884,7 +885,7 @@ static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg, * @hsotg: The device state * @ctrl: USB control request */ -static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg, +static int s3c_hsotg_process_req_status(struct dwc2_hsotg *hsotg, struct usb_ctrlrequest *ctrl) { struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; @@ -955,7 +956,7 @@ static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) * @hsotg: The device state * @ctrl: USB control request */ -static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, +static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, struct usb_ctrlrequest *ctrl) { struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; @@ -1028,8 +1029,8 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, return 1; } -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); -static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg); +static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); +static void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg); /** * s3c_hsotg_stall_ep0 - stall ep0 @@ -1037,7 +1038,7 @@ static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg); * * Set stall for ep0 as response for setup request. */ -static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) +static void s3c_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) { struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; u32 reg; @@ -1076,7 +1077,7 @@ static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) * needs to work out what to do next (and whether to pass it on to the * gadget driver). */ -static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, +static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg, struct usb_ctrlrequest *ctrl) { struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; @@ -1161,7 +1162,7 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep, struct usb_request *req) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; + struct dwc2_hsotg *hsotg = hs_ep->parent; if (req->status < 0) { dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); @@ -1183,7 +1184,7 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep, * Enqueue a request on EP0 if necessary to received any SETUP packets * received from the host. */ -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) +static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) { struct usb_request *req = hsotg->ctrl_req; struct s3c_hsotg_req *hs_req = our_req(req); @@ -1226,7 +1227,7 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) * * Note, expects the ep to already be locked as appropriate. */ -static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, +static void s3c_hsotg_complete_request(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req, int result) @@ -1291,7 +1292,7 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, * endpoint, so sort out whether we need to read the data into a request * that has been made for that endpoint. */ -static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) +static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) { struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; struct s3c_hsotg_req *hs_req = hs_ep->req; @@ -1356,7 +1357,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) * currently believed that we do not need to wait for any space in * the TxFIFO. */ -static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, +static void s3c_hsotg_send_zlp(struct dwc2_hsotg *hsotg, struct s3c_hsotg_req *req) { u32 ctrl; @@ -1398,7 +1399,7 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, * transfer for an OUT endpoint has been completed, either by a short * packet or by the finish of a transfer. */ -static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, +static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum, bool was_setup) { u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum)); @@ -1471,7 +1472,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, * * Return the current frame number */ -static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) +static u32 s3c_hsotg_read_frameno(struct dwc2_hsotg *hsotg) { u32 dsts; @@ -1498,7 +1499,7 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) * as the actual data should be sent to the memory directly and we turn * on the completion interrupts to get notifications of transfer completion. */ -static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) +static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg) { u32 grxstsr = readl(hsotg->regs + GRXSTSP); u32 epnum, status, size; @@ -1590,7 +1591,7 @@ static u32 s3c_hsotg_ep0_mps(unsigned int mps) * Configure the maximum packet size for the given endpoint, updating * the hardware control registers to reflect this. */ -static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, +static void s3c_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, unsigned int ep, unsigned int mps) { struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep]; @@ -1645,7 +1646,7 @@ bad_mps: * @hsotg: The driver state * @idx: The index for the endpoint (0..15) */ -static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) +static void s3c_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) { int timeout; int val; @@ -1681,7 +1682,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) * Check to see if there is a request that has data to send, and if so * make an attempt to write data into the FIFO. */ -static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg, +static int s3c_hsotg_trytx(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep) { struct s3c_hsotg_req *hs_req = hs_ep->req; @@ -1714,7 +1715,7 @@ static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg, * An IN transfer has been completed, update the transfer's state and then * call the relevant completion routines. */ -static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, +static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep) { struct s3c_hsotg_req *hs_req = hs_ep->req; @@ -1791,7 +1792,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, * * Process and clear any interrupt pending for an individual endpoint */ -static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, +static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, int dir_in) { struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx]; @@ -1916,7 +1917,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, * Handle updating the device settings after the enumeration phase has * been completed. */ -static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) +static void s3c_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) { u32 dsts = readl(hsotg->regs + DSTS); int ep0_mps = 0, ep_mps = 8; @@ -1993,7 +1994,7 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) * Go through the requests on the given endpoint and mark them * completed with the given result code. */ -static void kill_all_requests(struct s3c_hsotg *hsotg, +static void kill_all_requests(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *ep, int result, bool force) { @@ -2027,7 +2028,7 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, * transactions and signal the gadget driver that this * has happened. */ -static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg) +static void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg) { unsigned ep; @@ -2042,7 +2043,7 @@ static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg) * @hsotg: The device state: * @periodic: True if this is a periodic FIFO interrupt */ -static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) +static void s3c_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) { struct s3c_hsotg_ep *ep; int epno, ret; @@ -2076,7 +2077,7 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) * * Issue a soft reset to the core, and await the core finishing it. */ -static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) +static int s3c_hsotg_corereset(struct dwc2_hsotg *hsotg) { int timeout; u32 grstctl; @@ -2124,7 +2125,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) * * Issue a soft reset to the core, and await the core finishing it. */ -static void s3c_hsotg_core_init_disconnected(struct s3c_hsotg *hsotg) +static void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg) { s3c_hsotg_corereset(hsotg); @@ -2250,13 +2251,13 @@ static void s3c_hsotg_core_init_disconnected(struct s3c_hsotg *hsotg) hsotg->last_rst = jiffies; } -static void s3c_hsotg_core_disconnect(struct s3c_hsotg *hsotg) +static void s3c_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) { /* set the soft-disconnect bit */ __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); } -static void s3c_hsotg_core_connect(struct s3c_hsotg *hsotg) +static void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) { /* remove the soft-disconnect and let's go */ __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); @@ -2269,7 +2270,7 @@ static void s3c_hsotg_core_connect(struct s3c_hsotg *hsotg) */ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) { - struct s3c_hsotg *hsotg = pw; + struct dwc2_hsotg *hsotg = pw; int retry_count = 8; u32 gintsts; u32 gintmsk; @@ -2461,7 +2462,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; + struct dwc2_hsotg *hsotg = hs_ep->parent; unsigned long flags; int index = hs_ep->index; u32 epctrl_reg; @@ -2604,7 +2605,7 @@ error: static int s3c_hsotg_ep_disable(struct usb_ep *ep) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; + struct dwc2_hsotg *hsotg = hs_ep->parent; int dir_in = hs_ep->dir_in; int index = hs_ep->index; unsigned long flags; @@ -2669,7 +2670,7 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) { struct s3c_hsotg_req *hs_req = our_req(req); struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; + struct dwc2_hsotg *hs = hs_ep->parent; unsigned long flags; dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); @@ -2695,7 +2696,7 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; + struct dwc2_hsotg *hs = hs_ep->parent; int index = hs_ep->index; u32 epreg; u32 epctl; @@ -2759,7 +2760,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; + struct dwc2_hsotg *hs = hs_ep->parent; unsigned long flags = 0; int ret = 0; @@ -2788,7 +2789,7 @@ static struct usb_ep_ops s3c_hsotg_ep_ops = { * A wrapper for platform code responsible for controlling * low-level USB code */ -static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) +static void s3c_hsotg_phy_enable(struct dwc2_hsotg *hsotg) { struct platform_device *pdev = to_platform_device(hsotg->dev); @@ -2811,7 +2812,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) * A wrapper for platform code responsible for controlling * low-level USB code */ -static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) +static void s3c_hsotg_phy_disable(struct dwc2_hsotg *hsotg) { struct platform_device *pdev = to_platform_device(hsotg->dev); @@ -2829,7 +2830,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) * s3c_hsotg_init - initalize the usb core * @hsotg: The driver state */ -static void s3c_hsotg_init(struct s3c_hsotg *hsotg) +static void s3c_hsotg_init(struct dwc2_hsotg *hsotg) { /* unmask subset of endpoint interrupts */ @@ -2879,7 +2880,7 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) static int s3c_hsotg_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { - struct s3c_hsotg *hsotg = to_hsotg(gadget); + struct dwc2_hsotg *hsotg = to_hsotg(gadget); unsigned long flags; int ret; @@ -2942,7 +2943,7 @@ err: */ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) { - struct s3c_hsotg *hsotg = to_hsotg(gadget); + struct dwc2_hsotg *hsotg = to_hsotg(gadget); unsigned long flags = 0; int ep; @@ -2989,7 +2990,7 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) */ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) { - struct s3c_hsotg *hsotg = to_hsotg(gadget); + struct dwc2_hsotg *hsotg = to_hsotg(gadget); unsigned long flags = 0; dev_dbg(hsotg->dev, "%s: is_on: %d\n", __func__, is_on); @@ -3026,7 +3027,7 @@ static const struct usb_gadget_ops s3c_hsotg_gadget_ops = { * creation) to give to the gadget driver. Setup the endpoint name, any * direction information and other state that may be required. */ -static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, +static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, int epnum) { @@ -3075,7 +3076,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, * * Read the USB core HW configuration registers */ -static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg) +static void s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) { u32 cfg2, cfg3, cfg4; /* check hardware configuration */ @@ -3099,7 +3100,7 @@ static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg) * s3c_hsotg_dump - dump state of the udc * @param: The device state */ -static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) +static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg) { #ifdef DEBUG struct device *dev = hsotg->dev; @@ -3158,7 +3159,7 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) */ static int state_show(struct seq_file *seq, void *v) { - struct s3c_hsotg *hsotg = seq->private; + struct dwc2_hsotg *hsotg = seq->private; void __iomem *regs = hsotg->regs; int idx; @@ -3228,7 +3229,7 @@ static const struct file_operations state_fops = { */ static int fifo_show(struct seq_file *seq, void *v) { - struct s3c_hsotg *hsotg = seq->private; + struct dwc2_hsotg *hsotg = seq->private; void __iomem *regs = hsotg->regs; u32 val; int idx; @@ -3284,7 +3285,7 @@ static const char *decode_direction(int is_in) static int ep_show(struct seq_file *seq, void *v) { struct s3c_hsotg_ep *ep = seq->private; - struct s3c_hsotg *hsotg = ep->parent; + struct dwc2_hsotg *hsotg = ep->parent; struct s3c_hsotg_req *req; void __iomem *regs = hsotg->regs; int index = ep->index; @@ -3361,7 +3362,7 @@ static const struct file_operations ep_fops = { * with the same name as the device itself, in case we end up * with multiple blocks in future systems. */ -static void s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) +static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg) { struct dentry *root; unsigned epidx; @@ -3407,7 +3408,7 @@ static void s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) * * Cleanup (remove) the debugfs files for use on module exit. */ -static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) +static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg) { unsigned epidx; @@ -3425,7 +3426,6 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) * s3c_hsotg_probe - probe function for hsotg driver * @pdev: The platform information for the driver */ - static int s3c_hsotg_probe(struct platform_device *pdev) { struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); @@ -3433,13 +3433,13 @@ static int s3c_hsotg_probe(struct platform_device *pdev) struct usb_phy *uphy; struct device *dev = &pdev->dev; struct s3c_hsotg_ep *eps; - struct s3c_hsotg *hsotg; + struct dwc2_hsotg *hsotg; struct resource *res; int epnum; int ret; int i; - hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL); + hsotg = devm_kzalloc(&pdev->dev, sizeof(struct dwc2_hsotg), GFP_KERNEL); if (!hsotg) return -ENOMEM; @@ -3520,7 +3520,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), hsotg->supplies); if (ret) { - dev_err(dev, "failed to request supplies: %d\n", ret); + dev_err(hsotg->dev, "failed to request supplies: %d\n", ret); goto err_clk; } @@ -3528,7 +3528,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) hsotg->supplies); if (ret) { - dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); + dev_err(dev, "failed to enable supplies: %d\n", ret); goto err_supplies; } @@ -3592,7 +3592,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); if (ret) { - dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret); + dev_err(&pdev->dev, "failed to disable supplies: %d\n", ret); goto err_ep_mem; } @@ -3622,7 +3622,7 @@ err_clk: */ static int s3c_hsotg_remove(struct platform_device *pdev) { - struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); + struct dwc2_hsotg *hsotg = platform_get_drvdata(pdev); usb_del_gadget_udc(&hsotg->gadget); s3c_hsotg_delete_debug(hsotg); @@ -3633,7 +3633,7 @@ static int s3c_hsotg_remove(struct platform_device *pdev) static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) { - struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); + struct dwc2_hsotg *hsotg = platform_get_drvdata(pdev); unsigned long flags; int ret = 0; @@ -3664,7 +3664,7 @@ static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) static int s3c_hsotg_resume(struct platform_device *pdev) { - struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); + struct dwc2_hsotg *hsotg = platform_get_drvdata(pdev); unsigned long flags; int ret = 0; -- cgit v0.10.2 From 117777b2c3bb961ba1cb9943dee93f192d7a3abd Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:34 -0600 Subject: usb: dwc2: Move gadget probe function into platform code This patch will aggregate the probing of gadget/hcd driver into platform.c. The gadget probe funtion is converted into gadget_init that is now only responsible for gadget only initialization. All the gadget resources are now handled by platform.c Since the host workqueue will not get initialized if the driver is configured for peripheral mode only. Thus we need to check for wq_otg before calling queue_work(). Also, we move spin_lock_init to common location for both host and gadget that is either in platform.c or pci.c. We also move suspend/resume code to common platform code. Lastly, move the "samsung,s3c6400-hsotg" binding into dwc2_of_match_table. Signed-off-by: Dinh Nguyen Acked-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 7bcdc10..4905d88 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -960,4 +960,37 @@ extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg); */ extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg); +/* Gadget defines */ +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg); +extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2); +extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2); +extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); +#else +static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2) +{ return 0; } +static inline int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2) +{ return 0; } +static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2) +{ return 0; } +static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) +{ return 0; } +#endif + +#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg); +extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg); +extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg); +#else +static inline void dwc2_set_all_params(struct dwc2_core_params *params, int value) {} +static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg) +{ return 0; } +static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) {} +static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {} +static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {} +static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, + const struct dwc2_core_params *params) +{ return 0; } +#endif + #endif /* __DWC2_CORE_H__ */ diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index c93918b..b176c2f 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -287,9 +287,11 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg) * Release lock before scheduling workq as it holds spinlock during * scheduling. */ - spin_unlock(&hsotg->lock); - queue_work(hsotg->wq_otg, &hsotg->wf_otg); - spin_lock(&hsotg->lock); + if (hsotg->wq_otg) { + spin_unlock(&hsotg->lock); + queue_work(hsotg->wq_otg, &hsotg->wf_otg); + spin_lock(&hsotg->lock); + } /* Clear interrupt */ writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 5a24e95..9caea51 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3423,26 +3423,21 @@ static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg) } /** - * s3c_hsotg_probe - probe function for hsotg driver - * @pdev: The platform information for the driver + * dwc2_gadget_init - init function for gadget + * @dwc2: The data structure for the DWC2 driver. + * @irq: The IRQ number for the controller. */ -static int s3c_hsotg_probe(struct platform_device *pdev) +int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) { - struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); + struct device *dev = hsotg->dev; + struct s3c_hsotg_plat *plat = dev->platform_data; struct phy *phy; struct usb_phy *uphy; - struct device *dev = &pdev->dev; struct s3c_hsotg_ep *eps; - struct dwc2_hsotg *hsotg; - struct resource *res; int epnum; int ret; int i; - hsotg = devm_kzalloc(&pdev->dev, sizeof(struct dwc2_hsotg), GFP_KERNEL); - if (!hsotg) - return -ENOMEM; - /* Set default UTMI width */ hsotg->phyif = GUSBCFG_PHYIF16; @@ -3450,14 +3445,14 @@ static int s3c_hsotg_probe(struct platform_device *pdev) * Attempt to find a generic PHY, then look for an old style * USB PHY, finally fall back to pdata */ - phy = devm_phy_get(&pdev->dev, "usb2-phy"); + phy = devm_phy_get(dev, "usb2-phy"); if (IS_ERR(phy)) { uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); if (IS_ERR(uphy)) { /* Fallback for pdata */ - plat = dev_get_platdata(&pdev->dev); + plat = dev_get_platdata(dev); if (!plat) { - dev_err(&pdev->dev, + dev_err(dev, "no platform data or transceiver defined\n"); return -EPROBE_DEFER; } @@ -3474,36 +3469,12 @@ static int s3c_hsotg_probe(struct platform_device *pdev) hsotg->phyif = GUSBCFG_PHYIF8; } - hsotg->dev = dev; - - hsotg->clk = devm_clk_get(&pdev->dev, "otg"); + hsotg->clk = devm_clk_get(dev, "otg"); if (IS_ERR(hsotg->clk)) { dev_err(dev, "cannot get otg clock\n"); return PTR_ERR(hsotg->clk); } - platform_set_drvdata(pdev, hsotg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - hsotg->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hsotg->regs)) { - ret = PTR_ERR(hsotg->regs); - goto err_clk; - } - - ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "cannot find IRQ\n"); - goto err_clk; - } - - spin_lock_init(&hsotg->lock); - - hsotg->irq = ret; - - dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); - hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.ops = &s3c_hsotg_gadget_ops; hsotg->gadget.name = dev_name(dev); @@ -3520,7 +3491,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), hsotg->supplies); if (ret) { - dev_err(hsotg->dev, "failed to request supplies: %d\n", ret); + dev_err(dev, "failed to request supplies: %d\n", ret); goto err_clk; } @@ -3539,7 +3510,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) s3c_hsotg_hw_cfg(hsotg); s3c_hsotg_init(hsotg); - ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0, + ret = devm_request_irq(dev, irq, s3c_hsotg_irq, 0, dev_name(dev), hsotg); if (ret < 0) { s3c_hsotg_phy_disable(hsotg); @@ -3592,11 +3563,11 @@ static int s3c_hsotg_probe(struct platform_device *pdev) ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); if (ret) { - dev_err(&pdev->dev, "failed to disable supplies: %d\n", ret); + dev_err(dev, "failed to disable supplies: %d\n", ret); goto err_ep_mem; } - ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); + ret = usb_add_gadget_udc(dev, &hsotg->gadget); if (ret) goto err_ep_mem; @@ -3615,25 +3586,24 @@ err_clk: return ret; } +EXPORT_SYMBOL_GPL(dwc2_gadget_init); /** * s3c_hsotg_remove - remove function for hsotg driver * @pdev: The platform information for the driver */ -static int s3c_hsotg_remove(struct platform_device *pdev) +int s3c_hsotg_remove(struct dwc2_hsotg *hsotg) { - struct dwc2_hsotg *hsotg = platform_get_drvdata(pdev); - usb_del_gadget_udc(&hsotg->gadget); s3c_hsotg_delete_debug(hsotg); clk_disable_unprepare(hsotg->clk); return 0; } +EXPORT_SYMBOL_GPL(s3c_hsotg_remove); -static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) +int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg) { - struct dwc2_hsotg *hsotg = platform_get_drvdata(pdev); unsigned long flags; int ret = 0; @@ -3661,10 +3631,10 @@ static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) return ret; } +EXPORT_SYMBOL_GPL(s3c_hsotg_suspend); -static int s3c_hsotg_resume(struct platform_device *pdev) +int s3c_hsotg_resume(struct dwc2_hsotg *hsotg) { - struct dwc2_hsotg *hsotg = platform_get_drvdata(pdev); unsigned long flags; int ret = 0; @@ -3686,31 +3656,4 @@ static int s3c_hsotg_resume(struct platform_device *pdev) return ret; } - -#ifdef CONFIG_OF -static const struct of_device_id s3c_hsotg_of_ids[] = { - { .compatible = "samsung,s3c6400-hsotg", }, - { .compatible = "snps,dwc2", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids); -#endif - -static struct platform_driver s3c_hsotg_driver = { - .driver = { - .name = "s3c-hsotg", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(s3c_hsotg_of_ids), - }, - .probe = s3c_hsotg_probe, - .remove = s3c_hsotg_remove, - .suspend = s3c_hsotg_suspend, - .resume = s3c_hsotg_resume, -}; - -module_platform_driver(s3c_hsotg_driver); - -MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c-hsotg"); +EXPORT_SYMBOL_GPL(s3c_hsotg_resume); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 7480078..e377f58 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2905,7 +2905,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, hcd->has_tt = 1; - spin_lock_init(&hsotg->lock); ((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg; hsotg->priv = hcd; diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index a12bb15..e69a843 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -668,9 +668,6 @@ extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg); */ extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); -extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg); -extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg); - /** * dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host, * and 0 otherwise @@ -680,13 +677,6 @@ extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg); extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); /** - * dwc2_hcd_get_frame_number() - Returns current frame number - * - * @hsotg: The DWC2 HCD - */ -extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg); - -/** * dwc2_hcd_dump_state() - Dumps hsotg state * * @hsotg: The DWC2 HCD diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c index c291fca..6d33ecf 100644 --- a/drivers/usb/dwc2/pci.c +++ b/drivers/usb/dwc2/pci.c @@ -141,6 +141,7 @@ static int dwc2_driver_probe(struct pci_dev *dev, pci_set_master(dev); + spin_lock_init(&hsotg->lock); retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params); if (retval) { pci_disable_device(dev); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 121dbda..eeba8a4 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -121,6 +121,7 @@ static int dwc2_driver_remove(struct platform_device *dev) struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); dwc2_hcd_remove(hsotg); + s3c_hsotg_remove(hsotg); return 0; } @@ -129,6 +130,7 @@ static const struct of_device_id dwc2_of_match_table[] = { { .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 }, { .compatible = "rockchip,rk3066-usb", .data = ¶ms_rk3066 }, { .compatible = "snps,dwc2", .data = NULL }, + { .compatible = "samsung,s3c6400-hsotg", .data = NULL}, {}, }; MODULE_DEVICE_TABLE(of, dwc2_of_match_table); @@ -204,6 +206,10 @@ static int dwc2_driver_probe(struct platform_device *dev) hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node); + spin_lock_init(&hsotg->lock); + retval = dwc2_gadget_init(hsotg, irq); + if (retval) + return retval; retval = dwc2_hcd_init(hsotg, irq, params); if (retval) return retval; @@ -213,6 +219,26 @@ static int dwc2_driver_probe(struct platform_device *dev) return retval; } +static int dwc2_suspend(struct platform_device *dev, pm_message_t state) +{ + struct dwc2_hsotg *dwc2 = platform_get_drvdata(dev); + int ret = 0; + + if (dwc2_is_device_mode(dwc2)) + ret = s3c_hsotg_suspend(dwc2); + return ret; +} + +static int dwc2_resume(struct platform_device *dev) +{ + struct dwc2_hsotg *dwc2 = platform_get_drvdata(dev); + int ret = 0; + + if (dwc2_is_device_mode(dwc2)) + ret = s3c_hsotg_resume(dwc2); + return ret; +} + static struct platform_driver dwc2_platform_driver = { .driver = { .name = dwc2_driver_name, @@ -220,6 +246,8 @@ static struct platform_driver dwc2_platform_driver = { }, .probe = dwc2_driver_probe, .remove = dwc2_driver_remove, + .suspend = dwc2_suspend, + .resume = dwc2_resume, }; module_platform_driver(dwc2_platform_driver); -- cgit v0.10.2 From bcc06078ba4da9a8b92342e7005c65ba4c06bdb9 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:35 -0600 Subject: usb: dwc2: convert to use dev_pm_ops API Update suspend/resume to use dev_pm_ops API. Acked-by: Paul Zimmerman Signed-off-by: Dinh Nguyen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index eeba8a4..b94867b 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -219,9 +219,9 @@ static int dwc2_driver_probe(struct platform_device *dev) return retval; } -static int dwc2_suspend(struct platform_device *dev, pm_message_t state) +static int dwc2_suspend(struct device *dev) { - struct dwc2_hsotg *dwc2 = platform_get_drvdata(dev); + struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; if (dwc2_is_device_mode(dwc2)) @@ -229,9 +229,9 @@ static int dwc2_suspend(struct platform_device *dev, pm_message_t state) return ret; } -static int dwc2_resume(struct platform_device *dev) +static int dwc2_resume(struct device *dev) { - struct dwc2_hsotg *dwc2 = platform_get_drvdata(dev); + struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; if (dwc2_is_device_mode(dwc2)) @@ -239,15 +239,18 @@ static int dwc2_resume(struct platform_device *dev) return ret; } +static const struct dev_pm_ops dwc2_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc2_suspend, dwc2_resume) +}; + static struct platform_driver dwc2_platform_driver = { .driver = { .name = dwc2_driver_name, .of_match_table = dwc2_of_match_table, + .pm = &dwc2_dev_pm_ops, }, .probe = dwc2_driver_probe, .remove = dwc2_driver_remove, - .suspend = dwc2_suspend, - .resume = dwc2_resume, }; module_platform_driver(dwc2_platform_driver); -- cgit v0.10.2 From 510ffaa48eac2587a4df9ec7668e3274e5f96ee3 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:36 -0600 Subject: usb: dwc2: Initialize the USB core for peripheral mode Initialize the USB driver to peripheral mode when a B-Device connector is attached. Signed-off-by: Dinh Nguyen Acked-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 4905d88..4710935 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -966,6 +966,8 @@ extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg); extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2); extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2); extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); +extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2); +extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg); #else static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2) { return 0; } @@ -975,6 +977,8 @@ static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2) { return 0; } static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) { return 0; } +static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {} +static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {} #endif #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 9caea51..ec85340 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2125,7 +2125,7 @@ static int s3c_hsotg_corereset(struct dwc2_hsotg *hsotg) * * Issue a soft reset to the core, and await the core finishing it. */ -static void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg) +void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg) { s3c_hsotg_corereset(hsotg); @@ -2257,7 +2257,7 @@ static void s3c_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); } -static void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) +void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) { /* remove the soft-disconnect and let's go */ __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index e377f58..1a6dea3 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -1371,6 +1371,8 @@ static void dwc2_conn_id_status_change(struct work_struct *work) hsotg->op_state = OTG_STATE_B_PERIPHERAL; dwc2_core_init(hsotg, false, -1); dwc2_enable_global_interrupts(hsotg); + s3c_hsotg_core_init_disconnected(hsotg); + s3c_hsotg_core_connect(hsotg); } else { /* A-Device connector (Host Mode) */ dev_dbg(hsotg->dev, "connId A\n"); -- cgit v0.10.2 From db8178c33dbe9aba5e2c5d323625f9e6da55d7e6 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:37 -0600 Subject: usb: dwc2: Update common interrupt handler to call gadget interrupt handler Make dwc2_handle_common_intr call the gadget interrupt function when operating in peripheral mode. Remove the spinlock functions in s3c_hsotg_irq as dwc2_handle_common_intr() already has the spinlocks. Move the registeration of the IRQ to common code for platform and PCI. Remove duplicate interrupt conditions that was in gadget, as those are handled by dwc2 common interrupt handler. Acked-by: Paul Zimmerman Signed-off-by: Dinh Nguyen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index d926945..7605850b 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -458,16 +458,6 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq) /* Clear the SRP success bit for FS-I2c */ hsotg->srp_success = 0; - if (irq >= 0) { - dev_dbg(hsotg->dev, "registering common handler for irq%d\n", - irq); - retval = devm_request_irq(hsotg->dev, irq, - dwc2_handle_common_intr, IRQF_SHARED, - dev_name(hsotg->dev), hsotg); - if (retval) - return retval; - } - /* Enable common interrupts */ dwc2_enable_common_interrupts(hsotg); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index ec85340..37c7916 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2285,33 +2285,12 @@ irq_retry: gintsts &= gintmsk; - if (gintsts & GINTSTS_OTGINT) { - u32 otgint = readl(hsotg->regs + GOTGINT); - - dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); - - writel(otgint, hsotg->regs + GOTGINT); - } - - if (gintsts & GINTSTS_SESSREQINT) { - dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); - writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); - } - if (gintsts & GINTSTS_ENUMDONE) { writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); s3c_hsotg_irq_enumdone(hsotg); } - if (gintsts & GINTSTS_CONIDSTSCHNG) { - dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", - readl(hsotg->regs + DSTS), - readl(hsotg->regs + GOTGCTL)); - - writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); - } - if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { u32 daint = readl(hsotg->regs + DAINT); u32 daintmsk = readl(hsotg->regs + DAINTMSK); @@ -2392,25 +2371,6 @@ irq_retry: s3c_hsotg_handle_rx(hsotg); } - if (gintsts & GINTSTS_MODEMIS) { - dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); - writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS); - } - - if (gintsts & GINTSTS_USBSUSP) { - dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); - writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); - - call_gadget(hsotg, suspend); - } - - if (gintsts & GINTSTS_WKUPINT) { - dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); - writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS); - - call_gadget(hsotg, resume); - } - if (gintsts & GINTSTS_ERLYSUSP) { dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); @@ -3510,14 +3470,14 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) s3c_hsotg_hw_cfg(hsotg); s3c_hsotg_init(hsotg); - ret = devm_request_irq(dev, irq, s3c_hsotg_irq, 0, - dev_name(dev), hsotg); + ret = devm_request_irq(hsotg->dev, irq, s3c_hsotg_irq, IRQF_SHARED, + dev_name(hsotg->dev), hsotg); if (ret < 0) { s3c_hsotg_phy_disable(hsotg); clk_disable_unprepare(hsotg->clk); regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - dev_err(dev, "cannot claim IRQ\n"); + dev_err(dev, "cannot claim IRQ for gadget\n"); goto err_clk; } diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c index 6d33ecf..a4e724b 100644 --- a/drivers/usb/dwc2/pci.c +++ b/drivers/usb/dwc2/pci.c @@ -141,6 +141,12 @@ static int dwc2_driver_probe(struct pci_dev *dev, pci_set_master(dev); + retval = devm_request_irq(hsotg->dev, dev->irq, + dwc2_handle_common_intr, IRQF_SHARED, + dev_name(hsotg->dev), hsotg); + if (retval) + return retval; + spin_lock_init(&hsotg->lock); retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params); if (retval) { diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index b94867b..3552602 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -196,6 +196,14 @@ static int dwc2_driver_probe(struct platform_device *dev) return irq; } + dev_dbg(hsotg->dev, "registering common handler for irq%d\n", + irq); + retval = devm_request_irq(hsotg->dev, irq, + dwc2_handle_common_intr, IRQF_SHARED, + dev_name(hsotg->dev), hsotg); + if (retval) + return retval; + res = platform_get_resource(dev, IORESOURCE_MEM, 0); hsotg->regs = devm_ioremap_resource(&dev->dev, res); if (IS_ERR(hsotg->regs)) -- cgit v0.10.2 From 8d736d8a9c44547f14711c52875c88d19d8b287b Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:38 -0600 Subject: usb: dwc2: gadget: Do not fail probe if there isn't a clock node Since the dwc2 hcd driver is currently not looking for a clock node during init, we should not completely fail if there isn't a clock provided. By assigning clk = NULL, this allows the driver, when configured for dual-role mode, to be able to continue loading the host portion of the driver when a clock node is not specified. Acked-by: Paul Zimmerman Signed-off-by: Dinh Nguyen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 37c7916..367689b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3431,6 +3431,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) hsotg->clk = devm_clk_get(dev, "otg"); if (IS_ERR(hsotg->clk)) { + hsotg->clk = NULL; dev_err(dev, "cannot get otg clock\n"); return PTR_ERR(hsotg->clk); } -- cgit v0.10.2 From f5500ecc90a887d7e65274817733fbe477070559 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:39 -0600 Subject: usb: dwc2: move usb_disabled() call to host driver only Since platform.c will get built for both Host and Gadget, if we leave the usb_disabled() call in platform.c, it results in the following build error when (!USB && USB_GADGET) condition is met. ERROR: "usb_disabled" [drivers/usb/dwc2/dwc2_platform.ko] undefined! Since usb_disabled() is mostly used to disable USB host functionality, move the call the host portion for the DWC2 driver. Acked-by: Paul Zimmerman Signed-off-by: Dinh Nguyen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 1a6dea3..a0cd9db 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2846,6 +2846,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, int i, num_channels; int retval; + if (usb_disabled()) + return -ENODEV; + dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n"); /* Detect config values from hardware */ diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 3552602..57eb8a3 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -157,9 +157,6 @@ static int dwc2_driver_probe(struct platform_device *dev) int retval; int irq; - if (usb_disabled()) - return -ENODEV; - match = of_match_device(dwc2_of_match_table, &dev->dev); if (match && match->data) { params = match->data; -- cgit v0.10.2 From 5ee80705a5339270538119d1e8721b365eac5202 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 11 Nov 2014 11:13:40 -0600 Subject: usb: dwc2: Update Kconfig to support dual-role Update DWC2 kconfig and makefile to support dual-role mode. The platform file will always get compiled for the case where the controller is directly connected to the CPU. So for loadable modules, dwc2.ko is built for host, peripheral, and dual-role mode. The PCI bus interface will be called dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko. Signed-off-by: Dinh Nguyen Acked-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index 4d02718..b323c4c 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,5 +1,5 @@ config USB_DWC2 - bool "DesignWare USB2 DRD Core Support" + tristate "DesignWare USB2 DRD Core Support" depends on USB || USB_GADGET help Say Y here if your system has a Dual Role Hi-Speed USB @@ -10,49 +10,61 @@ config USB_DWC2 bus interface module (if you have a PCI bus system) will be called dwc2_pci.ko, and the platform interface module (for controllers directly connected to the CPU) will be called - dwc2_platform.ko. For gadget mode, there will be a single - module called dwc2_gadget.ko. - - NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The - host and gadget drivers are still currently separate drivers. - There are plans to merge the dwc2_gadget driver with the dwc2 - host driver in the near future to create a dual-role driver. + dwc2_platform.ko. For all modes(host, gadget and dual-role), there + will be an additional module named dwc2.ko. if USB_DWC2 +choice + bool "DWC2 Mode Selection" + default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET) + default USB_DWC2_HOST if (USB && !USB_GADGET) + default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET) + config USB_DWC2_HOST - tristate "Host only mode" + bool "Host only mode" depends on USB help The Designware USB2.0 high-speed host controller - integrated into many SoCs. + integrated into many SoCs. Select this option if you want the + driver to operate in Host-only mode. -config USB_DWC2_PLATFORM - bool "DWC2 Platform" - depends on USB_DWC2_HOST - default USB_DWC2_HOST +comment "Gadget/Dual-role mode requires USB Gadget support to be enabled" + +config USB_DWC2_PERIPHERAL + bool "Gadget only mode" + depends on USB_GADGET=y || USB_GADGET=USB_DWC2 + help + The Designware USB2.0 high-speed gadget controller + integrated into many SoCs. Select this option if you want the + driver to operate in Peripheral-only mode. This option requires + USB_GADGET to be enabled. + +config USB_DWC2_DUAL_ROLE + bool "Dual Role mode" + depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2) help - The Designware USB2.0 platform interface module for - controllers directly connected to the CPU. This is only - used for host mode. + Select this option if you want the driver to work in a dual-role + mode. In this mode both host and gadget features are enabled, and + the role will be determined by the cable that gets plugged-in. This + option requires USB_GADGET to be enabled. +endchoice + +config USB_DWC2_PLATFORM + tristate "DWC2 Platform" + default USB_DWC2_HOST || USB_DWC2_PERIPHERAL + help + The Designware USB2.0 platform interface module for + controllers directly connected to the CPU. config USB_DWC2_PCI - bool "DWC2 PCI" + tristate "DWC2 PCI" depends on USB_DWC2_HOST && PCI default USB_DWC2_HOST help The Designware USB2.0 PCI interface module for controllers connected to a PCI bus. This is only used for host mode. -comment "Gadget mode requires USB Gadget support to be enabled" - -config USB_DWC2_PERIPHERAL - tristate "Gadget only mode" - depends on USB_GADGET - help - The Designware USB2.0 high-speed gadget controller - integrated into many SoCs. - config USB_DWC2_DEBUG bool "Enable Debugging Messages" help diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile index b73d2a5..8f75267 100644 --- a/drivers/usb/dwc2/Makefile +++ b/drivers/usb/dwc2/Makefile @@ -1,28 +1,28 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG -obj-$(CONFIG_USB_DWC2_HOST) += dwc2.o +obj-$(CONFIG_USB_DWC2) += dwc2.o dwc2-y := core.o core_intr.o -dwc2-y += hcd.o hcd_intr.o -dwc2-y += hcd_queue.o hcd_ddma.o + +ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),) + dwc2-y += hcd.o hcd_intr.o + dwc2-y += hcd_queue.o hcd_ddma.o +endif + +ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),) + dwc2-y += gadget.o +endif # NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to # this location and renamed gadget.c. When building for dynamically linked -# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode, -# the core module will be dwc2.ko, the PCI bus interface module will called -# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko. -# At present the host and gadget driver will be separate drivers, but there -# are plans in the near future to create a dual-role driver. +# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role +# mode. The PCI bus interface module will called dwc2_pci.ko and the platform +# interface module will be called dwc2_platform.ko. ifneq ($(CONFIG_USB_DWC2_PCI),) - obj-$(CONFIG_USB_DWC2_HOST) += dwc2_pci.o + obj-$(CONFIG_USB_DWC2) += dwc2_pci.o dwc2_pci-y := pci.o endif -ifneq ($(CONFIG_USB_DWC2_PLATFORM),) - obj-$(CONFIG_USB_DWC2_HOST) += dwc2_platform.o - dwc2_platform-y := platform.o -endif - -obj-$(CONFIG_USB_DWC2_PERIPHERAL) += dwc2_gadget.o -dwc2_gadget-y := gadget.o +obj-$(CONFIG_USB_DWC2_PLATFORM) += dwc2_platform.o +dwc2_platform-y := platform.o -- cgit v0.10.2 From efed421a94e62a7ddbc76acba4312b70e4be958f Mon Sep 17 00:00:00 2001 From: Ashwini Pahuja Date: Thu, 13 Nov 2014 10:22:32 -0800 Subject: usb: gadget: Add UDC driver for Broadcom USB3.0 device controller IP BDC This patch adds a UDC driver for Broadcom's USB3.0 Peripheral core named BDC. BDC supports control traffic on ep0 and bulk/Int/Isoch traffic on all other endpoints. [ balbi@ti.com : fix build error on randconfig due to lack of ] Signed-off-by: Ashwini Pahuja Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 217365d..b8e213e 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -241,6 +241,8 @@ config USB_M66592 dynamically linked module called "m66592_udc" and force all gadget drivers to also be dynamically linked. +source "drivers/usb/gadget/udc/bdc/Kconfig" + # # Controllers available only in discrete form (and all PCI controllers) # diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index a7f4491..fba2049 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o obj-$(CONFIG_USB_GR_UDC) += gr_udc.o obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o +obj-$(CONFIG_USB_BDC_UDC) += bdc/ diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig new file mode 100644 index 0000000..0d7b8c9 --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/Kconfig @@ -0,0 +1,21 @@ +config USB_BDC_UDC + tristate "Broadcom USB3.0 device controller IP driver(BDC)" + depends on USB_GADGET && HAS_DMA + + help + BDC is Broadcom's USB3.0 device controller IP. If your SOC has a BDC IP + then select this driver. + + Say "y" here to link the driver statically, or "m" to build a dynamically + linked module called "bdc". + +if USB_BDC_UDC + +comment "Platform Support" +config USB_BDC_PCI + tristate "BDC support for PCIe based platforms" + depends on PCI + default USB_BDC_UDC + help + Enable support for platforms which have BDC connected through PCIe, such as Lego3 FPGA platform. +endif diff --git a/drivers/usb/gadget/udc/bdc/Makefile b/drivers/usb/gadget/udc/bdc/Makefile new file mode 100644 index 0000000..5cf6a3b --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_USB_BDC_UDC) += bdc.o +bdc-y := bdc_core.o bdc_cmd.o bdc_ep.o bdc_udc.o + +ifneq ($(CONFIG_USB_GADGET_VERBOSE),) + bdc-y += bdc_dbg.o +endif + +obj-$(CONFIG_USB_BDC_PCI) += bdc_pci.o diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h new file mode 100644 index 0000000..dc18a20 --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -0,0 +1,490 @@ +/* + * bdc.h - header for the BRCM BDC USB3.0 device controller + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * 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 __LINUX_BDC_H__ +#define __LINUX_BDC_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BRCM_BDC_NAME "bdc_usb3" +#define BRCM_BDC_DESC "BDC device controller driver" + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +/* BDC command operation timeout in usec*/ +#define BDC_CMD_TIMEOUT 1000 +/* BDC controller operation timeout in usec*/ +#define BDC_COP_TIMEOUT 500 + +/* + * Maximum size of ep0 response buffer for ch9 requests, + * the set_sel request uses 6 so far, the max. +*/ +#define EP0_RESPONSE_BUFF 6 +/* Start with SS as default */ +#define EP0_MAX_PKT_SIZE 512 + +/* 64 entries in a SRR */ +#define NUM_SR_ENTRIES 64 + +/* Num of bds per table */ +#define NUM_BDS_PER_TABLE 32 + +/* Num of tables in bd list for control,bulk and Int ep */ +#define NUM_TABLES 2 + +/* Num of tables in bd list for Isoch ep */ +#define NUM_TABLES_ISOCH 6 + +/* U1 Timeout default: 248usec */ +#define U1_TIMEOUT 0xf8 + +/* Interrupt coalescence in usec */ +#define INT_CLS 500 + +/* Register offsets */ +/* Configuration and Capability registers */ +#define BDC_BDCCFG0 0x00 +#define BDC_BDCCFG1 0x04 +#define BDC_BDCCAP0 0x08 +#define BDC_BDCCAP1 0x0c +#define BDC_CMDPAR0 0x10 +#define BDC_CMDPAR1 0x14 +#define BDC_CMDPAR2 0x18 +#define BDC_CMDSC 0x1c +#define BDC_USPC 0x20 +#define BDC_USPPMS 0x28 +#define BDC_USPPM2 0x2c +#define BDC_SPBBAL 0x38 +#define BDC_SPBBAH 0x3c +#define BDC_BDCSC 0x40 +#define BDC_XSFNTF 0x4c + +#define BDC_DVCSA 0x50 +#define BDC_DVCSB 0x54 +#define BDC_EPSTS0(n) (0x60 + (n * 0x10)) +#define BDC_EPSTS1(n) (0x64 + (n * 0x10)) +#define BDC_EPSTS2(n) (0x68 + (n * 0x10)) +#define BDC_EPSTS3(n) (0x6c + (n * 0x10)) +#define BDC_EPSTS4(n) (0x70 + (n * 0x10)) +#define BDC_EPSTS5(n) (0x74 + (n * 0x10)) +#define BDC_EPSTS6(n) (0x78 + (n * 0x10)) +#define BDC_EPSTS7(n) (0x7c + (n * 0x10)) +#define BDC_SRRBAL(n) (0x200 + (n * 0x10)) +#define BDC_SRRBAH(n) (0x204 + (n * 0x10)) +#define BDC_SRRINT(n) (0x208 + (n * 0x10)) +#define BDC_INTCTLS(n) (0x20c + (n * 0x10)) + +/* Extended capability regs */ +#define BDC_FSCNOC 0xcd4 +#define BDC_FSCNIC 0xce4 +#define NUM_NCS(p) (p >> 28) + +/* Register bit fields and Masks */ +/* BDC Configuration 0 */ +#define BDC_PGS(p) (((p) & (0x7 << 8)) >> 8) +#define BDC_SPB(p) (p & 0x7) + +/* BDC Capability1 */ +#define BDC_P64 (1 << 0) + +/* BDC Command register */ +#define BDC_CMD_FH 0xe +#define BDC_CMD_DNC 0x6 +#define BDC_CMD_EPO 0x4 +#define BDC_CMD_BLA 0x3 +#define BDC_CMD_EPC 0x2 +#define BDC_CMD_DVC 0x1 +#define BDC_CMD_CWS (0x1 << 5) +#define BDC_CMD_CST(p) (((p) & (0xf << 6))>>6) +#define BDC_CMD_EPN(p) ((p & 0x1f) << 10) +#define BDC_SUB_CMD_ADD (0x1 << 17) +#define BDC_SUB_CMD_FWK (0x4 << 17) +/* Reset sequence number */ +#define BDC_CMD_EPO_RST_SN (0x1 << 16) +#define BDC_CMD_EP0_XSD (0x1 << 16) +#define BDC_SUB_CMD_ADD_EP (0x1 << 17) +#define BDC_SUB_CMD_DRP_EP (0x2 << 17) +#define BDC_SUB_CMD_EP_STP (0x2 << 17) +#define BDC_SUB_CMD_EP_STL (0x4 << 17) +#define BDC_SUB_CMD_EP_RST (0x1 << 17) +#define BDC_CMD_SRD (1 << 27) + +/* CMD completion status */ +#define BDC_CMDS_SUCC 0x1 +#define BDC_CMDS_PARA 0x3 +#define BDC_CMDS_STAT 0x4 +#define BDC_CMDS_FAIL 0x5 +#define BDC_CMDS_INTL 0x6 +#define BDC_CMDS_BUSY 0xf + +/* CMDSC Param 2 shifts */ +#define EPT_SHIFT 22 +#define MP_SHIFT 10 +#define MB_SHIFT 6 +#define EPM_SHIFT 4 + +/* BDC USPSC */ +#define BDC_VBC (1 << 31) +#define BDC_PRC (1 << 30) +#define BDC_PCE (1 << 29) +#define BDC_CFC (1 << 28) +#define BDC_PCC (1 << 27) +#define BDC_PSC (1 << 26) +#define BDC_VBS (1 << 25) +#define BDC_PRS (1 << 24) +#define BDC_PCS (1 << 23) +#define BDC_PSP(p) (((p) & (0x7 << 20))>>20) +#define BDC_SCN (1 << 8) +#define BDC_SDC (1 << 7) +#define BDC_SWS (1 << 4) + +#define BDC_USPSC_RW (BDC_SCN|BDC_SDC|BDC_SWS|0xf) +#define BDC_PSP(p) (((p) & (0x7 << 20))>>20) + +#define BDC_SPEED_FS 0x1 +#define BDC_SPEED_LS 0x2 +#define BDC_SPEED_HS 0x3 +#define BDC_SPEED_SS 0x4 + +#define BDC_PST(p) (p & 0xf) +#define BDC_PST_MASK 0xf + +/* USPPMS */ +#define BDC_U2E (0x1 << 31) +#define BDC_U1E (0x1 << 30) +#define BDC_U2A (0x1 << 29) +#define BDC_PORT_W1S (0x1 << 17) +#define BDC_U1T(p) ((p) & 0xff) +#define BDC_U2T(p) (((p) & 0xff) << 8) +#define BDC_U1T_MASK 0xff + +/* USBPM2 */ +/* Hardware LPM Enable */ +#define BDC_HLE (1 << 16) + +/* BDC Status and Control */ +#define BDC_COP_RST (1 << 29) +#define BDC_COP_RUN (2 << 29) +#define BDC_COP_STP (4 << 29) + +#define BDC_COP_MASK (BDC_COP_RST|BDC_COP_RUN|BDC_COP_STP) + +#define BDC_COS (1 << 28) +#define BDC_CSTS(p) (((p) & (0x7 << 20)) >> 20) +#define BDC_MASK_MCW (1 << 7) +#define BDC_GIE (1 << 1) +#define BDC_GIP (1 << 0) + +#define BDC_HLT 1 +#define BDC_NOR 2 +#define BDC_OIP 7 + +/* Buffer descriptor and Status report bit fields and masks */ +#define BD_TYPE_BITMASK (0xf) +#define BD_CHAIN 0xf + +#define BD_TFS_SHIFT 4 +#define BD_SOT (1 << 26) +#define BD_EOT (1 << 27) +#define BD_ISP (1 << 29) +#define BD_IOC (1 << 30) +#define BD_SBF (1 << 31) + +#define BD_INTR_TARGET(p) (((p) & 0x1f) << 27) + +#define BDC_SRR_RWS (1 << 4) +#define BDC_SRR_RST (1 << 3) +#define BDC_SRR_ISR (1 << 2) +#define BDC_SRR_IE (1 << 1) +#define BDC_SRR_IP (1 << 0) +#define BDC_SRR_EPI(p) (((p) & (0xff << 24)) >> 24) +#define BDC_SRR_DPI(p) (((p) & (0xff << 16)) >> 16) +#define BDC_SRR_DPI_MASK 0x00ff0000 + +#define MARK_CHAIN_BD (BD_CHAIN|BD_EOT|BD_SOT) + +/* Control transfer BD specific fields */ +#define BD_DIR_IN (1 << 25) + +#define BDC_PTC_MASK 0xf0000000 + +/* status report defines */ +#define SR_XSF 0 +#define SR_USPC 4 +#define SR_BD_LEN(p) (p & 0xffffff) + +#define XSF_SUCC 0x1 +#define XSF_SHORT 0x3 +#define XSF_BABB 0x4 +#define XSF_SETUP_RECV 0x6 +#define XSF_DATA_START 0x7 +#define XSF_STATUS_START 0x8 + +#define XSF_STS(p) (((p) >> 28) & 0xf) + +/* Transfer BD fields */ +#define BD_LEN(p) ((p) & 0x1ffff) +#define BD_LTF (1 << 25) +#define BD_TYPE_DS 0x1 +#define BD_TYPE_SS 0x2 + +#define BDC_EP_ENABLED (1 << 0) +#define BDC_EP_STALL (1 << 1) +#define BDC_EP_STOP (1 << 2) + +/* One BD can transfer max 65536 bytes */ +#define BD_MAX_BUFF_SIZE (1 << 16) +/* Maximum bytes in one XFR, Refer to BDC spec */ +#define MAX_XFR_LEN 16777215 + +/* defines for Force Header command */ +#define DEV_NOTF_TYPE 6 +#define FWK_SUBTYPE 1 +#define TRA_PACKET 4 + +#define to_bdc_ep(e) container_of(e, struct bdc_ep, usb_ep) +#define to_bdc_req(r) container_of(r, struct bdc_req, usb_req) +#define gadget_to_bdc(g) container_of(g, struct bdc, gadget) + +/* FUNCTION WAKE DEV NOTIFICATION interval, USB3 spec table 8.13 */ +#define BDC_TNOTIFY 2500 /*in ms*/ +/* Devstatus bitfields */ +#define REMOTE_WAKEUP_ISSUED (1 << 16) +#define DEVICE_SUSPENDED (1 << 17) +#define FUNC_WAKE_ISSUED (1 << 18) +#define REMOTE_WAKE_ENABLE (1 << USB_DEVICE_REMOTE_WAKEUP) + +/* On disconnect, preserve these bits and clear rest */ +#define DEVSTATUS_CLEAR (1 << USB_DEVICE_SELF_POWERED) +/* Hardware and software Data structures */ + +/* Endpoint bd: buffer descriptor */ +struct bdc_bd { + __le32 offset[4]; +}; + +/* Status report in Status report ring(srr) */ +struct bdc_sr { + __le32 offset[4]; +}; + +/* bd_table: contigous bd's in a table */ +struct bd_table { + struct bdc_bd *start_bd; + /* dma address of start bd of table*/ + dma_addr_t dma; +}; + +/* + * Each endpoint has a bdl(buffer descriptor list), bdl consists of 1 or more bd + * table's chained to each other through a chain bd, every table has equal + * number of bds. the software uses bdi(bd index) to refer to particular bd in + * the list. + */ +struct bd_list { + /* Array of bd table pointers*/ + struct bd_table **bd_table_array; + /* How many tables chained to each other */ + int num_tabs; + /* Max_bdi = num_tabs * num_bds_table - 1 */ + int max_bdi; + /* current enq bdi from sw point of view */ + int eqp_bdi; + /* current deq bdi from sw point of view */ + int hwd_bdi; + /* numbers of bds per table */ + int num_bds_table; +}; + +struct bdc_req; + +/* Representation of a transfer, one transfer can have multiple bd's */ +struct bd_transfer { + struct bdc_req *req; + /* start bd index */ + int start_bdi; + /* this will be the next hw dqp when this transfer completes */ + int next_hwd_bdi; + /* number of bds in this transfer */ + int num_bds; +}; + +/* + * Representation of a gadget request, every gadget request is contained + * by 1 bd_transfer. + */ +struct bdc_req { + struct usb_request usb_req; + struct list_head queue; + struct bdc_ep *ep; + /* only one Transfer per request */ + struct bd_transfer bd_xfr; + int epnum; +}; + +/* scratchpad buffer needed by bdc hardware */ +struct bdc_scratchpad { + dma_addr_t sp_dma; + void *buff; + u32 size; +}; + +/* endpoint representation */ +struct bdc_ep { + struct usb_ep usb_ep; + struct list_head queue; + struct bdc *bdc; + u8 ep_type; + u8 dir; + u8 ep_num; + const struct usb_ss_ep_comp_descriptor *comp_desc; + const struct usb_endpoint_descriptor *desc; + unsigned int flags; + char name[20]; + /* endpoint bd list*/ + struct bd_list bd_list; + /* + * HW generates extra event for multi bd tranfers, this flag helps in + * ignoring the extra event + */ + bool ignore_next_sr; +}; + +/* bdc cmmand parameter structure */ +struct bdc_cmd_params { + u32 param2; + u32 param1; + u32 param0; +}; + +/* status report ring(srr), currently one srr is supported for entire system */ +struct srr { + struct bdc_sr *sr_bds; + u16 eqp_index; + u16 dqp_index; + dma_addr_t dma_addr; +}; + +/* EP0 states */ +enum bdc_ep0_state { + WAIT_FOR_SETUP = 0, + WAIT_FOR_DATA_START, + WAIT_FOR_DATA_XMIT, + WAIT_FOR_STATUS_START, + WAIT_FOR_STATUS_XMIT, + STATUS_PENDING +}; + +/* Link states */ +enum bdc_link_state { + BDC_LINK_STATE_U0 = 0x00, + BDC_LINK_STATE_U3 = 0x03, + BDC_LINK_STATE_RX_DET = 0x05, + BDC_LINK_STATE_RESUME = 0x0f +}; + +/* representation of bdc */ +struct bdc { + struct usb_gadget gadget; + struct usb_gadget_driver *gadget_driver; + struct device *dev; + /* device lock */ + spinlock_t lock; + + /* num of endpoints for a particular instantiation of IP */ + unsigned int num_eps; + /* + * Array of ep's, it uses the same index covention as bdc hw i.e. + * 1 for ep0, 2 for 1out,3 for 1in .... + */ + struct bdc_ep **bdc_ep_array; + void __iomem *regs; + struct bdc_scratchpad scratchpad; + u32 sp_buff_size; + /* current driver supports 1 status ring */ + struct srr srr; + /* Last received setup packet */ + struct usb_ctrlrequest setup_pkt; + struct bdc_req ep0_req; + struct bdc_req status_req; + enum bdc_ep0_state ep0_state; + bool delayed_status; + bool zlp_needed; + bool reinit; + bool pullup; + /* Bits 0-15 are standard and 16-31 for proprietary information */ + u32 devstatus; + int irq; + void *mem; + u32 dev_addr; + /* DMA pools */ + struct dma_pool *bd_table_pool; + u8 test_mode; + /* array of callbacks for various status report handlers */ + void (*sr_handler[2])(struct bdc *, struct bdc_sr *); + /* ep0 callback handlers */ + void (*sr_xsf_ep0[3])(struct bdc *, struct bdc_sr *); + /* ep0 response buffer for ch9 requests like GET_STATUS and SET_SEL */ + unsigned char ep0_response_buff[EP0_RESPONSE_BUFF]; + /* + * Timer to check if host resumed transfer after bdc sent Func wake + * notification packet after a remote wakeup. if not, then resend the + * Func Wake packet every 2.5 secs. Refer to USB3 spec section 8.5.6.4 + */ + struct delayed_work func_wake_notify; +}; + +static inline u32 bdc_readl(void __iomem *base, u32 offset) +{ + return readl(base + offset); +} + +static inline void bdc_writel(void __iomem *base, u32 offset, u32 value) +{ + writel(value, base + offset); +} + +/* Buffer descriptor list operations */ +void bdc_notify_xfr(struct bdc *, u32); +void bdc_softconn(struct bdc *); +void bdc_softdisconn(struct bdc *); +int bdc_run(struct bdc *); +int bdc_stop(struct bdc *); +int bdc_reset(struct bdc *); +int bdc_udc_init(struct bdc *); +void bdc_udc_exit(struct bdc *); +int bdc_reinit(struct bdc *); + +/* Status report handlers */ +/* Upstream port status change sr */ +void bdc_sr_uspc(struct bdc *, struct bdc_sr *); +/* transfer sr */ +void bdc_sr_xsf(struct bdc *, struct bdc_sr *); +/* EP0 XSF handlers */ +void bdc_xsf_ep0_setup_recv(struct bdc *, struct bdc_sr *); +void bdc_xsf_ep0_data_start(struct bdc *, struct bdc_sr *); +void bdc_xsf_ep0_status_start(struct bdc *, struct bdc_sr *); + +#endif /* __LINUX_BDC_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c new file mode 100644 index 0000000..6a4155c --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c @@ -0,0 +1,376 @@ +/* + * bdc_cmd.c - BRCM BDC USB3.0 device controller + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * 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 "bdc.h" +#include "bdc_cmd.h" +#include "bdc_dbg.h" + +/* Issues a cmd to cmd processor and waits for cmd completion */ +static int bdc_issue_cmd(struct bdc *bdc, u32 cmd_sc, u32 param0, + u32 param1, u32 param2) +{ + u32 timeout = BDC_CMD_TIMEOUT; + u32 cmd_status; + u32 temp; + + bdc_writel(bdc->regs, BDC_CMDPAR0, param0); + bdc_writel(bdc->regs, BDC_CMDPAR1, param1); + bdc_writel(bdc->regs, BDC_CMDPAR2, param2); + + /* Issue the cmd */ + /* Make sure the cmd params are written before asking HW to exec cmd */ + wmb(); + bdc_writel(bdc->regs, BDC_CMDSC, cmd_sc | BDC_CMD_CWS | BDC_CMD_SRD); + do { + temp = bdc_readl(bdc->regs, BDC_CMDSC); + dev_dbg_ratelimited(bdc->dev, "cmdsc=%x", temp); + cmd_status = BDC_CMD_CST(temp); + if (cmd_status != BDC_CMDS_BUSY) { + dev_dbg(bdc->dev, + "command completed cmd_sts:%x\n", cmd_status); + return cmd_status; + } + udelay(1); + } while (timeout--); + + dev_err(bdc->dev, + "command operation timedout cmd_status=%d\n", cmd_status); + + return cmd_status; +} + +/* Submits cmd and analyze the return value of bdc_issue_cmd */ +static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc, + u32 param0, u32 param1, u32 param2) +{ + u32 temp, cmd_status; + int reset_bdc = 0; + int ret; + + temp = bdc_readl(bdc->regs, BDC_CMDSC); + dev_dbg(bdc->dev, + "%s:CMDSC:%08x cmdsc:%08x param0=%08x param1=%08x param2=%08x\n", + __func__, temp, cmd_sc, param0, param1, param2); + + cmd_status = BDC_CMD_CST(temp); + if (cmd_status == BDC_CMDS_BUSY) { + dev_err(bdc->dev, "command processor busy: %x\n", cmd_status); + return -EBUSY; + } + ret = bdc_issue_cmd(bdc, cmd_sc, param0, param1, param2); + switch (ret) { + case BDC_CMDS_SUCC: + dev_dbg(bdc->dev, "command completed successfully\n"); + ret = 0; + break; + + case BDC_CMDS_PARA: + dev_err(bdc->dev, "command parameter error\n"); + ret = -EINVAL; + break; + + case BDC_CMDS_STAT: + dev_err(bdc->dev, "Invalid device/ep state\n"); + ret = -EINVAL; + break; + + case BDC_CMDS_FAIL: + dev_err(bdc->dev, "Command failed?\n"); + ret = -EAGAIN; + break; + + case BDC_CMDS_INTL: + dev_err(bdc->dev, "BDC Internal error\n"); + reset_bdc = 1; + ret = -ECONNRESET; + break; + + case BDC_CMDS_BUSY: + dev_err(bdc->dev, + "command timedout waited for %dusec\n", + BDC_CMD_TIMEOUT); + reset_bdc = 1; + ret = -ECONNRESET; + break; + default: + dev_dbg(bdc->dev, "Unknown command completion code:%x\n", ret); + } + + return ret; +} + +/* Deconfigure the endpoint from HW */ +int bdc_dconfig_ep(struct bdc *bdc, struct bdc_ep *ep) +{ + u32 cmd_sc; + + cmd_sc = BDC_SUB_CMD_DRP_EP|BDC_CMD_EPN(ep->ep_num)|BDC_CMD_EPC; + dev_dbg(bdc->dev, "%s ep->ep_num =%d cmd_sc=%x\n", __func__, + ep->ep_num, cmd_sc); + + return bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); +} + +/* Reinitalize the bdlist after config ep command */ +static void ep_bd_list_reinit(struct bdc_ep *ep) +{ + struct bdc *bdc = ep->bdc; + struct bdc_bd *bd; + + ep->bd_list.eqp_bdi = 0; + ep->bd_list.hwd_bdi = 0; + bd = ep->bd_list.bd_table_array[0]->start_bd; + dev_dbg(bdc->dev, "%s ep:%p bd:%p\n", __func__, ep, bd); + memset(bd, 0, sizeof(struct bdc_bd)); + bd->offset[3] |= cpu_to_le32(BD_SBF); +} + +/* Configure an endpoint */ +int bdc_config_ep(struct bdc *bdc, struct bdc_ep *ep) +{ + const struct usb_ss_ep_comp_descriptor *comp_desc; + const struct usb_endpoint_descriptor *desc; + u32 param0, param1, param2, cmd_sc; + u32 mps, mbs, mul, si; + int ret; + + desc = ep->desc; + comp_desc = ep->comp_desc; + cmd_sc = mul = mbs = param2 = 0; + param0 = lower_32_bits(ep->bd_list.bd_table_array[0]->dma); + param1 = upper_32_bits(ep->bd_list.bd_table_array[0]->dma); + cpu_to_le32s(¶m0); + cpu_to_le32s(¶m1); + + dev_dbg(bdc->dev, "%s: param0=%08x param1=%08x", + __func__, param0, param1); + si = desc->bInterval; + si = clamp_val(si, 1, 16) - 1; + + mps = usb_endpoint_maxp(desc); + mps &= 0x7ff; + param2 |= mps << MP_SHIFT; + param2 |= usb_endpoint_type(desc) << EPT_SHIFT; + + switch (bdc->gadget.speed) { + case USB_SPEED_SUPER: + if (usb_endpoint_xfer_int(desc) || + usb_endpoint_xfer_isoc(desc)) { + param2 |= si; + if (usb_endpoint_xfer_isoc(desc) && comp_desc) + mul = comp_desc->bmAttributes; + + } + param2 |= mul << EPM_SHIFT; + if (comp_desc) + mbs = comp_desc->bMaxBurst; + param2 |= mbs << MB_SHIFT; + break; + + case USB_SPEED_HIGH: + if (usb_endpoint_xfer_isoc(desc) || + usb_endpoint_xfer_int(desc)) { + param2 |= si; + + mbs = (usb_endpoint_maxp(desc) & 0x1800) >> 11; + param2 |= mbs << MB_SHIFT; + } + break; + + case USB_SPEED_FULL: + case USB_SPEED_LOW: + /* the hardware accepts SI in 125usec range */ + if (usb_endpoint_xfer_isoc(desc)) + si += 3; + + /* + * FS Int endpoints can have si of 1-255ms but the controller + * accepts 2^bInterval*125usec, so convert ms to nearest power + * of 2 + */ + if (usb_endpoint_xfer_int(desc)) + si = fls(desc->bInterval * 8) - 1; + + param2 |= si; + break; + default: + dev_err(bdc->dev, "UNKNOWN speed ERR\n"); + return -EINVAL; + } + + cmd_sc |= BDC_CMD_EPC|BDC_CMD_EPN(ep->ep_num)|BDC_SUB_CMD_ADD_EP; + + dev_dbg(bdc->dev, "cmd_sc=%x param2=%08x\n", cmd_sc, param2); + ret = bdc_submit_cmd(bdc, cmd_sc, param0, param1, param2); + if (ret) { + dev_err(bdc->dev, "command failed :%x\n", ret); + return ret; + } + ep_bd_list_reinit(ep); + + return ret; +} + +/* + * Change the HW deq pointer, if this command is successful, HW will start + * fetching the next bd from address dma_addr. + */ +int bdc_ep_bla(struct bdc *bdc, struct bdc_ep *ep, dma_addr_t dma_addr) +{ + u32 param0, param1; + u32 cmd_sc = 0; + + dev_dbg(bdc->dev, "%s: add=%08llx\n", __func__, + (unsigned long long)(dma_addr)); + param0 = lower_32_bits(dma_addr); + param1 = upper_32_bits(dma_addr); + cpu_to_le32s(¶m0); + cpu_to_le32s(¶m1); + + cmd_sc |= BDC_CMD_EPN(ep->ep_num)|BDC_CMD_BLA; + dev_dbg(bdc->dev, "cmd_sc=%x\n", cmd_sc); + + return bdc_submit_cmd(bdc, cmd_sc, param0, param1, 0); +} + +/* Set the address sent bu Host in SET_ADD request */ +int bdc_address_device(struct bdc *bdc, u32 add) +{ + u32 cmd_sc = 0; + u32 param2; + + dev_dbg(bdc->dev, "%s: add=%d\n", __func__, add); + cmd_sc |= BDC_SUB_CMD_ADD|BDC_CMD_DVC; + param2 = add & 0x7f; + + return bdc_submit_cmd(bdc, cmd_sc, 0, 0, param2); +} + +/* Send a Function Wake notification packet using FH command */ +int bdc_function_wake_fh(struct bdc *bdc, u8 intf) +{ + u32 param0, param1; + u32 cmd_sc = 0; + + param0 = param1 = 0; + dev_dbg(bdc->dev, "%s intf=%d\n", __func__, intf); + cmd_sc |= BDC_CMD_FH; + param0 |= TRA_PACKET; + param0 |= (bdc->dev_addr << 25); + param1 |= DEV_NOTF_TYPE; + param1 |= (FWK_SUBTYPE<<4); + dev_dbg(bdc->dev, "param0=%08x param1=%08x\n", param0, param1); + + return bdc_submit_cmd(bdc, cmd_sc, param0, param1, 0); +} + +/* Send a Function Wake notification packet using DNC command */ +int bdc_function_wake(struct bdc *bdc, u8 intf) +{ + u32 cmd_sc = 0; + u32 param2 = 0; + + dev_dbg(bdc->dev, "%s intf=%d", __func__, intf); + param2 |= intf; + cmd_sc |= BDC_SUB_CMD_FWK|BDC_CMD_DNC; + + return bdc_submit_cmd(bdc, cmd_sc, 0, 0, param2); +} + +/* Stall the endpoint */ +int bdc_ep_set_stall(struct bdc *bdc, int epnum) +{ + u32 cmd_sc = 0; + + dev_dbg(bdc->dev, "%s epnum=%d\n", __func__, epnum); + /* issue a stall endpoint command */ + cmd_sc |= BDC_SUB_CMD_EP_STL | BDC_CMD_EPN(epnum) | BDC_CMD_EPO; + + return bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); +} + +/* resets the endpoint, called when host sends CLEAR_FEATURE(HALT) */ +int bdc_ep_clear_stall(struct bdc *bdc, int epnum) +{ + struct bdc_ep *ep; + u32 cmd_sc = 0; + int ret; + + dev_dbg(bdc->dev, "%s: epnum=%d\n", __func__, epnum); + ep = bdc->bdc_ep_array[epnum]; + /* + * If we are not in stalled then stall Endpoint and issue clear stall, + * his will reset the seq number for non EP0. + */ + if (epnum != 1) { + /* if the endpoint it not stallled */ + if (!(ep->flags & BDC_EP_STALL)) { + ret = bdc_ep_set_stall(bdc, epnum); + if (ret) + return ret; + } + } + /* Preserve the seq number for ep0 only */ + if (epnum != 1) + cmd_sc |= BDC_CMD_EPO_RST_SN; + + /* issue a reset endpoint command */ + cmd_sc |= BDC_SUB_CMD_EP_RST | BDC_CMD_EPN(epnum) | BDC_CMD_EPO; + + ret = bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); + if (ret) { + dev_err(bdc->dev, "command failed:%x\n", ret); + return ret; + } + bdc_notify_xfr(bdc, epnum); + + return ret; +} + +/* Stop the endpoint, called when software wants to dequeue some request */ +int bdc_stop_ep(struct bdc *bdc, int epnum) +{ + struct bdc_ep *ep; + u32 cmd_sc = 0; + int ret; + + ep = bdc->bdc_ep_array[epnum]; + dev_dbg(bdc->dev, "%s: ep:%s ep->flags:%08x\n", __func__, + ep->name, ep->flags); + /* Endpoint has to be in running state to execute stop ep command */ + if (!(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "stop endpoint called for disabled ep\n"); + return -EINVAL; + } + if ((ep->flags & BDC_EP_STALL) || (ep->flags & BDC_EP_STOP)) + return 0; + + /* issue a stop endpoint command */ + cmd_sc |= BDC_CMD_EP0_XSD | BDC_SUB_CMD_EP_STP + | BDC_CMD_EPN(epnum) | BDC_CMD_EPO; + + ret = bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); + if (ret) { + dev_err(bdc->dev, + "stop endpoint command didn't complete:%d ep:%s\n", + ret, ep->name); + return ret; + } + ep->flags |= BDC_EP_STOP; + bdc_dump_epsts(bdc); + + return ret; +} diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.h b/drivers/usb/gadget/udc/bdc/bdc_cmd.h new file mode 100644 index 0000000..61d0e3b --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.h @@ -0,0 +1,29 @@ +/* + * bdc_cmd.h - header for the BDC debug functions + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * 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 __LINUX_BDC_CMD_H__ +#define __LINUX_BDC_CMD_H__ + +/* Command operations */ +int bdc_address_device(struct bdc *, u32); +int bdc_config_ep(struct bdc *, struct bdc_ep *); +int bdc_dconfig_ep(struct bdc *, struct bdc_ep *); +int bdc_stop_ep(struct bdc *, int); +int bdc_ep_set_stall(struct bdc *, int); +int bdc_ep_clear_stall(struct bdc *, int); +int bdc_ep_set_halt(struct bdc_ep *, u32 , int); +int bdc_ep_bla(struct bdc *, struct bdc_ep *, dma_addr_t); +int bdc_function_wake(struct bdc*, u8); +int bdc_function_wake_fh(struct bdc*, u8); + +#endif /* __LINUX_BDC_CMD_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c new file mode 100644 index 0000000..c6dfef8 --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -0,0 +1,533 @@ +/* + * bdc_core.c - BRCM BDC USB3.0 device controller core operations + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * 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 "bdc.h" +#include "bdc_dbg.h" + +/* Poll till controller status is not OIP */ +static int poll_oip(struct bdc *bdc, int usec) +{ + u32 status; + /* Poll till STS!= OIP */ + while (usec) { + status = bdc_readl(bdc->regs, BDC_BDCSC); + if (BDC_CSTS(status) != BDC_OIP) { + dev_dbg(bdc->dev, + "poll_oip complete status=%d", + BDC_CSTS(status)); + return 0; + } + udelay(10); + usec -= 10; + } + dev_err(bdc->dev, "Err: operation timedout BDCSC: 0x%08x\n", status); + + return -ETIMEDOUT; +} + +/* Stop the BDC controller */ +int bdc_stop(struct bdc *bdc) +{ + int ret; + u32 temp; + + dev_dbg(bdc->dev, "%s ()\n\n", __func__); + temp = bdc_readl(bdc->regs, BDC_BDCSC); + /* Check if BDC is already halted */ + if (BDC_CSTS(temp) == BDC_HLT) { + dev_vdbg(bdc->dev, "BDC already halted\n"); + return 0; + } + temp &= ~BDC_COP_MASK; + temp |= BDC_COS|BDC_COP_STP; + bdc_writel(bdc->regs, BDC_BDCSC, temp); + + ret = poll_oip(bdc, BDC_COP_TIMEOUT); + if (ret) + dev_err(bdc->dev, "bdc stop operation failed"); + + return ret; +} + +/* Issue a reset to BDC controller */ +int bdc_reset(struct bdc *bdc) +{ + u32 temp; + int ret; + + dev_dbg(bdc->dev, "%s ()\n", __func__); + /* First halt the controller */ + ret = bdc_stop(bdc); + if (ret) + return ret; + + temp = bdc_readl(bdc->regs, BDC_BDCSC); + temp &= ~BDC_COP_MASK; + temp |= BDC_COS|BDC_COP_RST; + bdc_writel(bdc->regs, BDC_BDCSC, temp); + ret = poll_oip(bdc, BDC_COP_TIMEOUT); + if (ret) + dev_err(bdc->dev, "bdc reset operation failed"); + + return ret; +} + +/* Run the BDC controller */ +int bdc_run(struct bdc *bdc) +{ + u32 temp; + int ret; + + dev_dbg(bdc->dev, "%s ()\n", __func__); + temp = bdc_readl(bdc->regs, BDC_BDCSC); + /* if BDC is already in running state then do not do anything */ + if (BDC_CSTS(temp) == BDC_NOR) { + dev_warn(bdc->dev, "bdc is already in running state\n"); + return 0; + } + temp &= ~BDC_COP_MASK; + temp |= BDC_COP_RUN; + temp |= BDC_COS; + bdc_writel(bdc->regs, BDC_BDCSC, temp); + ret = poll_oip(bdc, BDC_COP_TIMEOUT); + if (ret) { + dev_err(bdc->dev, "bdc run operation failed:%d", ret); + return ret; + } + temp = bdc_readl(bdc->regs, BDC_BDCSC); + if (BDC_CSTS(temp) != BDC_NOR) { + dev_err(bdc->dev, "bdc not in normal mode after RUN op :%d\n", + BDC_CSTS(temp)); + return -ESHUTDOWN; + } + + return 0; +} + +/* + * Present the termination to the host, typically called from upstream port + * event with Vbus present =1 + */ +void bdc_softconn(struct bdc *bdc) +{ + u32 uspc; + + uspc = bdc_readl(bdc->regs, BDC_USPC); + uspc &= ~BDC_PST_MASK; + uspc |= BDC_LINK_STATE_RX_DET; + uspc |= BDC_SWS; + dev_dbg(bdc->dev, "%s () uspc=%08x\n", __func__, uspc); + bdc_writel(bdc->regs, BDC_USPC, uspc); +} + +/* Remove the termination */ +void bdc_softdisconn(struct bdc *bdc) +{ + u32 uspc; + + uspc = bdc_readl(bdc->regs, BDC_USPC); + uspc |= BDC_SDC; + uspc &= ~BDC_SCN; + dev_dbg(bdc->dev, "%s () uspc=%x\n", __func__, uspc); + bdc_writel(bdc->regs, BDC_USPC, uspc); +} + +/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ +static int scratchpad_setup(struct bdc *bdc) +{ + int sp_buff_size; + u32 low32; + u32 upp32; + + sp_buff_size = BDC_SPB(bdc_readl(bdc->regs, BDC_BDCCFG0)); + dev_dbg(bdc->dev, "%s() sp_buff_size=%d\n", __func__, sp_buff_size); + if (!sp_buff_size) { + dev_dbg(bdc->dev, "Scratchpad buffer not needed\n"); + return 0; + } + /* Refer to BDC spec, Table 4 for description of SPB */ + sp_buff_size = 1 << (sp_buff_size + 5); + dev_dbg(bdc->dev, "Allocating %d bytes for scratchpad\n", sp_buff_size); + bdc->scratchpad.buff = dma_zalloc_coherent(bdc->dev, sp_buff_size, + &bdc->scratchpad.sp_dma, GFP_KERNEL); + + if (!bdc->scratchpad.buff) + goto fail; + + bdc->sp_buff_size = sp_buff_size; + bdc->scratchpad.size = sp_buff_size; + low32 = lower_32_bits(bdc->scratchpad.sp_dma); + upp32 = upper_32_bits(bdc->scratchpad.sp_dma); + cpu_to_le32s(&low32); + cpu_to_le32s(&upp32); + bdc_writel(bdc->regs, BDC_SPBBAL, low32); + bdc_writel(bdc->regs, BDC_SPBBAH, upp32); + return 0; + +fail: + bdc->scratchpad.buff = NULL; + + return -ENOMEM; +} + +/* Allocate the status report ring */ +static int setup_srr(struct bdc *bdc, int interrupter) +{ + dev_dbg(bdc->dev, "%s() NUM_SR_ENTRIES:%d\n", __func__, NUM_SR_ENTRIES); + /* Reset the SRR */ + bdc_writel(bdc->regs, BDC_SRRINT(0), BDC_SRR_RWS | BDC_SRR_RST); + bdc->srr.dqp_index = 0; + /* allocate the status report descriptors */ + bdc->srr.sr_bds = dma_zalloc_coherent( + bdc->dev, + NUM_SR_ENTRIES * sizeof(struct bdc_bd), + &bdc->srr.dma_addr, + GFP_KERNEL); + if (!bdc->srr.sr_bds) + return -ENOMEM; + + return 0; +} + +/* Initialize the HW regs and internal data structures */ +static void bdc_mem_init(struct bdc *bdc, bool reinit) +{ + u8 size = 0; + u32 usb2_pm; + u32 low32; + u32 upp32; + u32 temp; + + dev_dbg(bdc->dev, "%s ()\n", __func__); + bdc->ep0_state = WAIT_FOR_SETUP; + bdc->dev_addr = 0; + bdc->srr.eqp_index = 0; + bdc->srr.dqp_index = 0; + bdc->zlp_needed = false; + bdc->delayed_status = false; + + bdc_writel(bdc->regs, BDC_SPBBAL, bdc->scratchpad.sp_dma); + /* Init the SRR */ + temp = BDC_SRR_RWS | BDC_SRR_RST; + /* Reset the SRR */ + bdc_writel(bdc->regs, BDC_SRRINT(0), temp); + dev_dbg(bdc->dev, "bdc->srr.sr_bds =%p\n", bdc->srr.sr_bds); + temp = lower_32_bits(bdc->srr.dma_addr); + size = fls(NUM_SR_ENTRIES) - 2; + temp |= size; + dev_dbg(bdc->dev, "SRRBAL[0]=%08x NUM_SR_ENTRIES:%d size:%d\n", + temp, NUM_SR_ENTRIES, size); + + low32 = lower_32_bits(temp); + upp32 = upper_32_bits(bdc->srr.dma_addr); + cpu_to_le32s(&low32); + cpu_to_le32s(&upp32); + + /* Write the dma addresses into regs*/ + bdc_writel(bdc->regs, BDC_SRRBAL(0), low32); + bdc_writel(bdc->regs, BDC_SRRBAH(0), upp32); + + temp = bdc_readl(bdc->regs, BDC_SRRINT(0)); + temp |= BDC_SRR_IE; + temp &= ~(BDC_SRR_RST | BDC_SRR_RWS); + bdc_writel(bdc->regs, BDC_SRRINT(0), temp); + + /* Set the Interrupt Coalescence ~500 usec */ + temp = bdc_readl(bdc->regs, BDC_INTCTLS(0)); + temp &= ~0xffff; + temp |= INT_CLS; + bdc_writel(bdc->regs, BDC_INTCTLS(0), temp); + + usb2_pm = bdc_readl(bdc->regs, BDC_USPPM2); + dev_dbg(bdc->dev, "usb2_pm=%08x", usb2_pm); + /* Enable hardware LPM Enable */ + usb2_pm |= BDC_HLE; + bdc_writel(bdc->regs, BDC_USPPM2, usb2_pm); + + /* readback for debug */ + usb2_pm = bdc_readl(bdc->regs, BDC_USPPM2); + dev_dbg(bdc->dev, "usb2_pm=%08x\n", usb2_pm); + + /* Disable any unwanted SR's on SRR */ + temp = bdc_readl(bdc->regs, BDC_BDCSC); + /* We don't want Microframe counter wrap SR */ + temp |= BDC_MASK_MCW; + bdc_writel(bdc->regs, BDC_BDCSC, temp); + + /* + * In some error cases, driver has to reset the entire BDC controller + * in that case reinit is passed as 1 + */ + if (reinit) { + /* Enable interrupts */ + temp = bdc_readl(bdc->regs, BDC_BDCSC); + temp |= BDC_GIE; + bdc_writel(bdc->regs, BDC_BDCSC, temp); + /* Init scratchpad to 0 */ + memset(bdc->scratchpad.buff, 0, bdc->sp_buff_size); + /* Initialize SRR to 0 */ + memset(bdc->srr.sr_bds, 0, + NUM_SR_ENTRIES * sizeof(struct bdc_bd)); + } else { + /* One time initiaization only */ + /* Enable status report function pointers */ + bdc->sr_handler[0] = bdc_sr_xsf; + bdc->sr_handler[1] = bdc_sr_uspc; + + /* EP0 status report function pointers */ + bdc->sr_xsf_ep0[0] = bdc_xsf_ep0_setup_recv; + bdc->sr_xsf_ep0[1] = bdc_xsf_ep0_data_start; + bdc->sr_xsf_ep0[2] = bdc_xsf_ep0_status_start; + } +} + +/* Free the dynamic memory */ +static void bdc_mem_free(struct bdc *bdc) +{ + dev_dbg(bdc->dev, "%s\n", __func__); + /* Free SRR */ + if (bdc->srr.sr_bds) + dma_free_coherent(bdc->dev, + NUM_SR_ENTRIES * sizeof(struct bdc_bd), + bdc->srr.sr_bds, bdc->srr.dma_addr); + + /* Free scratchpad */ + if (bdc->scratchpad.buff) + dma_free_coherent(bdc->dev, bdc->sp_buff_size, + bdc->scratchpad.buff, bdc->scratchpad.sp_dma); + + /* Destroy the dma pools */ + if (bdc->bd_table_pool) + dma_pool_destroy(bdc->bd_table_pool); + + /* Free the bdc_ep array */ + kfree(bdc->bdc_ep_array); + + bdc->srr.sr_bds = NULL; + bdc->scratchpad.buff = NULL; + bdc->bd_table_pool = NULL; + bdc->bdc_ep_array = NULL; +} + +/* + * bdc reinit gives a controller reset and reinitialize the registers, + * called from disconnect/bus reset scenario's, to ensure proper HW cleanup + */ +int bdc_reinit(struct bdc *bdc) +{ + int ret; + + dev_dbg(bdc->dev, "%s\n", __func__); + ret = bdc_stop(bdc); + if (ret) + goto out; + + ret = bdc_reset(bdc); + if (ret) + goto out; + + /* the reinit flag is 1 */ + bdc_mem_init(bdc, true); + ret = bdc_run(bdc); +out: + bdc->reinit = false; + + return ret; +} + +/* Allocate all the dyanmic memory */ +static int bdc_mem_alloc(struct bdc *bdc) +{ + u32 page_size; + unsigned int num_ieps, num_oeps; + + dev_dbg(bdc->dev, + "%s() NUM_BDS_PER_TABLE:%d\n", __func__, + NUM_BDS_PER_TABLE); + page_size = BDC_PGS(bdc_readl(bdc->regs, BDC_BDCCFG0)); + /* page size is 2^pgs KB */ + page_size = 1 << page_size; + /* KB */ + page_size <<= 10; + dev_dbg(bdc->dev, "page_size=%d\n", page_size); + + /* Create a pool of bd tables */ + bdc->bd_table_pool = + dma_pool_create("BDC BD tables", bdc->dev, NUM_BDS_PER_TABLE * 16, + 16, page_size); + + if (!bdc->bd_table_pool) + goto fail; + + if (scratchpad_setup(bdc)) + goto fail; + + /* read from regs */ + num_ieps = NUM_NCS(bdc_readl(bdc->regs, BDC_FSCNIC)); + num_oeps = NUM_NCS(bdc_readl(bdc->regs, BDC_FSCNOC)); + /* +2: 1 for ep0 and the other is rsvd i.e. bdc_ep[0] is rsvd */ + bdc->num_eps = num_ieps + num_oeps + 2; + dev_dbg(bdc->dev, + "ieps:%d eops:%d num_eps:%d\n", + num_ieps, num_oeps, bdc->num_eps); + /* allocate array of ep pointers */ + bdc->bdc_ep_array = kcalloc(bdc->num_eps, sizeof(struct bdc_ep *), + GFP_KERNEL); + if (!bdc->bdc_ep_array) + goto fail; + + dev_dbg(bdc->dev, "Allocating sr report0\n"); + if (setup_srr(bdc, 0)) + goto fail; + + return 0; +fail: + dev_warn(bdc->dev, "Couldn't initialize memory\n"); + bdc_mem_free(bdc); + + return -ENOMEM; +} + +/* opposite to bdc_hw_init */ +static void bdc_hw_exit(struct bdc *bdc) +{ + dev_dbg(bdc->dev, "%s ()\n", __func__); + bdc_mem_free(bdc); +} + +/* Initialize the bdc HW and memory */ +static int bdc_hw_init(struct bdc *bdc) +{ + int ret; + + dev_dbg(bdc->dev, "%s ()\n", __func__); + ret = bdc_reset(bdc); + if (ret) { + dev_err(bdc->dev, "err resetting bdc abort bdc init%d\n", ret); + return ret; + } + ret = bdc_mem_alloc(bdc); + if (ret) { + dev_err(bdc->dev, "Mem alloc failed, aborting\n"); + return -ENOMEM; + } + bdc_mem_init(bdc, 0); + bdc_dbg_regs(bdc); + dev_dbg(bdc->dev, "HW Init done\n"); + + return 0; +} + +static int bdc_probe(struct platform_device *pdev) +{ + struct bdc *bdc; + struct resource *res; + int ret = -ENOMEM; + int irq; + u32 temp; + struct device *dev = &pdev->dev; + + dev_dbg(dev, "%s()\n", __func__); + bdc = devm_kzalloc(dev, sizeof(*bdc), GFP_KERNEL); + if (!bdc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bdc->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(bdc->regs)) { + dev_err(dev, "ioremap error\n"); + return -ENOMEM; + } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "platform_get_irq failed:%d\n", irq); + return irq; + } + spin_lock_init(&bdc->lock); + platform_set_drvdata(pdev, bdc); + bdc->irq = irq; + bdc->dev = dev; + dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); + + temp = bdc_readl(bdc->regs, BDC_BDCSC); + if ((temp & BDC_P64) && + !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { + dev_dbg(bdc->dev, "Using 64-bit address\n"); + } else { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(bdc->dev, "No suitable DMA config available, abort\n"); + return -ENOTSUPP; + } + dev_dbg(bdc->dev, "Using 32-bit address\n"); + } + ret = bdc_hw_init(bdc); + if (ret) { + dev_err(bdc->dev, "BDC init failure:%d\n", ret); + return ret; + } + ret = bdc_udc_init(bdc); + if (ret) { + dev_err(bdc->dev, "BDC Gadget init failure:%d\n", ret); + goto cleanup; + } + return 0; + +cleanup: + bdc_hw_exit(bdc); + + return ret; +} + +static int bdc_remove(struct platform_device *pdev) +{ + struct bdc *bdc; + + bdc = platform_get_drvdata(pdev); + dev_dbg(bdc->dev, "%s ()\n", __func__); + bdc_udc_exit(bdc); + bdc_hw_exit(bdc); + + return 0; +} + +static struct platform_driver bdc_driver = { + .driver = { + .name = BRCM_BDC_NAME, + .owner = THIS_MODULE + }, + .probe = bdc_probe, + .remove = bdc_remove, +}; + +module_platform_driver(bdc_driver); +MODULE_AUTHOR("Ashwini Pahuja "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(BRCM_BDC_DESC); diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.c b/drivers/usb/gadget/udc/bdc/bdc_dbg.c new file mode 100644 index 0000000..5945dbc --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.c @@ -0,0 +1,123 @@ +/* + * bdc_dbg.c - BRCM BDC USB3.0 device controller debug functions + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * 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 "bdc.h" +#include "bdc_dbg.h" + +void bdc_dbg_regs(struct bdc *bdc) +{ + u32 temp; + + dev_vdbg(bdc->dev, "bdc->regs:%p\n", bdc->regs); + temp = bdc_readl(bdc->regs, BDC_BDCCFG0); + dev_vdbg(bdc->dev, "bdccfg0:0x%08x\n", temp); + temp = bdc_readl(bdc->regs, BDC_BDCCFG1); + dev_vdbg(bdc->dev, "bdccfg1:0x%08x\n", temp); + temp = bdc_readl(bdc->regs, BDC_BDCCAP0); + dev_vdbg(bdc->dev, "bdccap0:0x%08x\n", temp); + temp = bdc_readl(bdc->regs, BDC_BDCCAP1); + dev_vdbg(bdc->dev, "bdccap1:0x%08x\n", temp); + temp = bdc_readl(bdc->regs, BDC_USPC); + dev_vdbg(bdc->dev, "uspc:0x%08x\n", temp); + temp = bdc_readl(bdc->regs, BDC_DVCSA); + dev_vdbg(bdc->dev, "dvcsa:0x%08x\n", temp); + temp = bdc_readl(bdc->regs, BDC_DVCSB); + dev_vdbg(bdc->dev, "dvcsb:0x%x08\n", temp); +} + +void bdc_dump_epsts(struct bdc *bdc) +{ + u32 temp; + + temp = bdc_readl(bdc->regs, BDC_EPSTS0(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS0:0x%08x\n", temp); + + temp = bdc_readl(bdc->regs, BDC_EPSTS1(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS1:0x%x\n", temp); + + temp = bdc_readl(bdc->regs, BDC_EPSTS2(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS2:0x%08x\n", temp); + + temp = bdc_readl(bdc->regs, BDC_EPSTS3(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS3:0x%08x\n", temp); + + temp = bdc_readl(bdc->regs, BDC_EPSTS4(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS4:0x%08x\n", temp); + + temp = bdc_readl(bdc->regs, BDC_EPSTS5(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS5:0x%08x\n", temp); + + temp = bdc_readl(bdc->regs, BDC_EPSTS6(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS6:0x%08x\n", temp); + + temp = bdc_readl(bdc->regs, BDC_EPSTS7(0)); + dev_vdbg(bdc->dev, "BDC_EPSTS7:0x%08x\n", temp); +} + +void bdc_dbg_srr(struct bdc *bdc, u32 srr_num) +{ + struct bdc_sr *sr; + dma_addr_t addr; + int i; + + sr = bdc->srr.sr_bds; + addr = bdc->srr.dma_addr; + dev_vdbg(bdc->dev, "bdc_dbg_srr sr:%p dqp_index:%d\n", + sr, bdc->srr.dqp_index); + for (i = 0; i < NUM_SR_ENTRIES; i++) { + sr = &bdc->srr.sr_bds[i]; + dev_vdbg(bdc->dev, "%llx %08x %08x %08x %08x\n", + (unsigned long long)addr, + le32_to_cpu(sr->offset[0]), + le32_to_cpu(sr->offset[1]), + le32_to_cpu(sr->offset[2]), + le32_to_cpu(sr->offset[3])); + addr += sizeof(*sr); + } +} + +void bdc_dbg_bd_list(struct bdc *bdc, struct bdc_ep *ep) +{ + struct bd_list *bd_list = &ep->bd_list; + struct bd_table *bd_table; + struct bdc_bd *bd; + int tbi, bdi, gbdi; + dma_addr_t dma; + + gbdi = 0; + dev_vdbg(bdc->dev, + "Dump bd list for %s epnum:%d\n", + ep->name, ep->ep_num); + + dev_vdbg(bdc->dev, + "tabs:%d max_bdi:%d eqp_bdi:%d hwd_bdi:%d num_bds_table:%d\n", + bd_list->num_tabs, bd_list->max_bdi, bd_list->eqp_bdi, + bd_list->hwd_bdi, bd_list->num_bds_table); + + for (tbi = 0; tbi < bd_list->num_tabs; tbi++) { + bd_table = bd_list->bd_table_array[tbi]; + for (bdi = 0; bdi < bd_list->num_bds_table; bdi++) { + bd = bd_table->start_bd + bdi; + dma = bd_table->dma + (sizeof(struct bdc_bd) * bdi); + dev_vdbg(bdc->dev, + "tbi:%2d bdi:%2d gbdi:%2d virt:%p phys:%llx %08x %08x %08x %08x\n", + tbi, bdi, gbdi++, bd, (unsigned long long)dma, + le32_to_cpu(bd->offset[0]), + le32_to_cpu(bd->offset[1]), + le32_to_cpu(bd->offset[2]), + le32_to_cpu(bd->offset[3])); + } + dev_vdbg(bdc->dev, "\n\n"); + } +} diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.h b/drivers/usb/gadget/udc/bdc/bdc_dbg.h new file mode 100644 index 0000000..338a6c7 --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.h @@ -0,0 +1,37 @@ +/* + * bdc_dbg.h - header for the BDC debug functions + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * 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 __LINUX_BDC_DBG_H__ +#define __LINUX_BDC_DBG_H__ + +#include "bdc.h" + +#ifdef CONFIG_USB_GADGET_VERBOSE +void bdc_dbg_bd_list(struct bdc *, struct bdc_ep*); +void bdc_dbg_srr(struct bdc *, u32); +void bdc_dbg_regs(struct bdc *); +void bdc_dump_epsts(struct bdc *); +#else +static inline void bdc_dbg_regs(struct bdc *bdc) +{ } + +static inline void bdc_dbg_srr(struct bdc *bdc, u32 srr_num) +{ } + +static inline void bdc_dbg_bd_list(struct bdc *bdc, struct bdc_ep *ep) +{ } + +static inline void bdc_dump_epsts(struct bdc *bdc) +{ } +#endif /* CONFIG_USB_GADGET_VERBOSE */ +#endif /* __LINUX_BDC_DBG_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c new file mode 100644 index 0000000..15da5b1 --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -0,0 +1,2023 @@ +/* + * bdc_ep.c - BRCM BDC USB3.0 device controller endpoint related functions + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * Based on drivers under drivers/usb/ + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bdc.h" +#include "bdc_ep.h" +#include "bdc_cmd.h" +#include "bdc_dbg.h" + +static const char * const ep0_state_string[] = { + "WAIT_FOR_SETUP", + "WAIT_FOR_DATA_START", + "WAIT_FOR_DATA_XMIT", + "WAIT_FOR_STATUS_START", + "WAIT_FOR_STATUS_XMIT", + "STATUS_PENDING" +}; + +/* Free the bdl during ep disable */ +static void ep_bd_list_free(struct bdc_ep *ep, u32 num_tabs) +{ + struct bd_list *bd_list = &ep->bd_list; + struct bdc *bdc = ep->bdc; + struct bd_table *bd_table; + int index; + + dev_dbg(bdc->dev, "%s ep:%s num_tabs:%d\n", + __func__, ep->name, num_tabs); + + if (!bd_list->bd_table_array) { + dev_dbg(bdc->dev, "%s already freed\n", ep->name); + return; + } + for (index = 0; index < num_tabs; index++) { + /* + * check if the bd_table struct is allocated ? + * if yes, then check if bd memory has been allocated, then + * free the dma_pool and also the bd_table struct memory + */ + bd_table = bd_list->bd_table_array[index]; + dev_dbg(bdc->dev, "bd_table:%p index:%d\n", bd_table, index); + if (!bd_table) { + dev_dbg(bdc->dev, "bd_table not allocated\n"); + continue; + } + if (!bd_table->start_bd) { + dev_dbg(bdc->dev, "bd dma pool not allocted\n"); + continue; + } + + dev_dbg(bdc->dev, + "Free dma pool start_bd:%p dma:%llx\n", + bd_table->start_bd, + (unsigned long long)bd_table->dma); + + dma_pool_free(bdc->bd_table_pool, + bd_table->start_bd, + bd_table->dma); + /* Free the bd_table structure */ + kfree(bd_table); + } + /* Free the bd table array */ + kfree(ep->bd_list.bd_table_array); +} + +/* + * chain the tables, by insteting a chain bd at the end of prev_table, pointing + * to next_table + */ +static inline void chain_table(struct bd_table *prev_table, + struct bd_table *next_table, + u32 bd_p_tab) +{ + /* Chain the prev table to next table */ + prev_table->start_bd[bd_p_tab-1].offset[0] = + cpu_to_le32(lower_32_bits(next_table->dma)); + + prev_table->start_bd[bd_p_tab-1].offset[1] = + cpu_to_le32(upper_32_bits(next_table->dma)); + + prev_table->start_bd[bd_p_tab-1].offset[2] = + 0x0; + + prev_table->start_bd[bd_p_tab-1].offset[3] = + cpu_to_le32(MARK_CHAIN_BD); +} + +/* Allocate the bdl for ep, during config ep */ +static int ep_bd_list_alloc(struct bdc_ep *ep) +{ + struct bd_table *prev_table = NULL; + int index, num_tabs, bd_p_tab; + struct bdc *bdc = ep->bdc; + struct bd_table *bd_table; + dma_addr_t dma; + + if (usb_endpoint_xfer_isoc(ep->desc)) + num_tabs = NUM_TABLES_ISOCH; + else + num_tabs = NUM_TABLES; + + bd_p_tab = NUM_BDS_PER_TABLE; + /* if there is only 1 table in bd list then loop chain to self */ + dev_dbg(bdc->dev, + "%s ep:%p num_tabs:%d\n", + __func__, ep, num_tabs); + + /* Allocate memory for table array */ + ep->bd_list.bd_table_array = kzalloc( + num_tabs * sizeof(struct bd_table *), + GFP_ATOMIC); + if (!ep->bd_list.bd_table_array) + return -ENOMEM; + + /* Allocate memory for each table */ + for (index = 0; index < num_tabs; index++) { + /* Allocate memory for bd_table structure */ + bd_table = kzalloc(sizeof(struct bd_table), GFP_ATOMIC); + if (!bd_table) + goto fail; + + bd_table->start_bd = dma_pool_alloc(bdc->bd_table_pool, + GFP_ATOMIC, + &dma); + if (!bd_table->start_bd) + goto fail; + + bd_table->dma = dma; + + dev_dbg(bdc->dev, + "index:%d start_bd:%p dma=%08llx prev_table:%p\n", + index, bd_table->start_bd, + (unsigned long long)bd_table->dma, prev_table); + + ep->bd_list.bd_table_array[index] = bd_table; + memset(bd_table->start_bd, 0, bd_p_tab * sizeof(struct bdc_bd)); + if (prev_table) + chain_table(prev_table, bd_table, bd_p_tab); + + prev_table = bd_table; + } + chain_table(prev_table, ep->bd_list.bd_table_array[0], bd_p_tab); + /* Memory allocation is successful, now init the internal fields */ + ep->bd_list.num_tabs = num_tabs; + ep->bd_list.max_bdi = (num_tabs * bd_p_tab) - 1; + ep->bd_list.num_tabs = num_tabs; + ep->bd_list.num_bds_table = bd_p_tab; + ep->bd_list.eqp_bdi = 0; + ep->bd_list.hwd_bdi = 0; + + return 0; +fail: + /* Free the bd_table_array, bd_table struct, bd's */ + ep_bd_list_free(ep, num_tabs); + + return -ENOMEM; +} + +/* returns how many bd's are need for this transfer */ +static inline int bd_needed_req(struct bdc_req *req) +{ + int bd_needed = 0; + int remaining; + + /* 1 bd needed for 0 byte transfer */ + if (req->usb_req.length == 0) + return 1; + + /* remaining bytes after tranfering all max BD size BD's */ + remaining = req->usb_req.length % BD_MAX_BUFF_SIZE; + if (remaining) + bd_needed++; + + /* How many maximum BUFF size BD's ? */ + remaining = req->usb_req.length / BD_MAX_BUFF_SIZE; + bd_needed += remaining; + + return bd_needed; +} + +/* returns the bd index(bdi) corresponding to bd dma address */ +static int bd_add_to_bdi(struct bdc_ep *ep, dma_addr_t bd_dma_addr) +{ + struct bd_list *bd_list = &ep->bd_list; + dma_addr_t dma_first_bd, dma_last_bd; + struct bdc *bdc = ep->bdc; + struct bd_table *bd_table; + bool found = false; + int tbi, bdi; + + dma_first_bd = dma_last_bd = 0; + dev_dbg(bdc->dev, "%s %llx\n", + __func__, (unsigned long long)bd_dma_addr); + /* + * Find in which table this bd_dma_addr belongs?, go through the table + * array and compare addresses of first and last address of bd of each + * table + */ + for (tbi = 0; tbi < bd_list->num_tabs; tbi++) { + bd_table = bd_list->bd_table_array[tbi]; + dma_first_bd = bd_table->dma; + dma_last_bd = bd_table->dma + + (sizeof(struct bdc_bd) * + (bd_list->num_bds_table - 1)); + dev_dbg(bdc->dev, "dma_first_bd:%llx dma_last_bd:%llx\n", + (unsigned long long)dma_first_bd, + (unsigned long long)dma_last_bd); + if (bd_dma_addr >= dma_first_bd && bd_dma_addr <= dma_last_bd) { + found = true; + break; + } + } + if (unlikely(!found)) { + dev_err(bdc->dev, "%s FATAL err, bd not found\n", __func__); + return -EINVAL; + } + /* Now we know the table, find the bdi */ + bdi = (bd_dma_addr - dma_first_bd) / sizeof(struct bdc_bd); + + /* return the global bdi, to compare with ep eqp_bdi */ + return (bdi + (tbi * bd_list->num_bds_table)); +} + +/* returns the table index(tbi) of the given bdi */ +static int bdi_to_tbi(struct bdc_ep *ep, int bdi) +{ + int tbi; + + tbi = bdi / ep->bd_list.num_bds_table; + dev_vdbg(ep->bdc->dev, + "bdi:%d num_bds_table:%d tbi:%d\n", + bdi, ep->bd_list.num_bds_table, tbi); + + return tbi; +} + +/* Find the bdi last bd in the transfer */ +static inline int find_end_bdi(struct bdc_ep *ep, int next_hwd_bdi) +{ + int end_bdi; + + end_bdi = next_hwd_bdi - 1; + if (end_bdi < 0) + end_bdi = ep->bd_list.max_bdi - 1; + else if ((end_bdi % (ep->bd_list.num_bds_table-1)) == 0) + end_bdi--; + + return end_bdi; +} + +/* + * How many transfer bd's are available on this ep bdl, chain bds are not + * counted in available bds + */ +static int bd_available_ep(struct bdc_ep *ep) +{ + struct bd_list *bd_list = &ep->bd_list; + int available1, available2; + struct bdc *bdc = ep->bdc; + int chain_bd1, chain_bd2; + int available_bd = 0; + + available1 = available2 = chain_bd1 = chain_bd2 = 0; + /* if empty then we have all bd's available - number of chain bd's */ + if (bd_list->eqp_bdi == bd_list->hwd_bdi) + return bd_list->max_bdi - bd_list->num_tabs; + + /* + * Depending upon where eqp and dqp pointers are, caculate number + * of avaialble bd's + */ + if (bd_list->hwd_bdi < bd_list->eqp_bdi) { + /* available bd's are from eqp..max_bds + 0..dqp - chain_bds */ + available1 = bd_list->max_bdi - bd_list->eqp_bdi; + available2 = bd_list->hwd_bdi; + chain_bd1 = available1 / bd_list->num_bds_table; + chain_bd2 = available2 / bd_list->num_bds_table; + dev_vdbg(bdc->dev, "chain_bd1:%d chain_bd2:%d\n", + chain_bd1, chain_bd2); + available_bd = available1 + available2 - chain_bd1 - chain_bd2; + } else { + /* available bd's are from eqp..dqp - number of chain bd's */ + available1 = bd_list->hwd_bdi - bd_list->eqp_bdi; + /* if gap between eqp and dqp is less than NUM_BDS_PER_TABLE */ + if ((bd_list->hwd_bdi - bd_list->eqp_bdi) + <= bd_list->num_bds_table) { + /* If there any chain bd in between */ + if (!(bdi_to_tbi(ep, bd_list->hwd_bdi) + == bdi_to_tbi(ep, bd_list->eqp_bdi))) { + available_bd = available1 - 1; + } + } else { + chain_bd1 = available1 / bd_list->num_bds_table; + available_bd = available1 - chain_bd1; + } + } + /* + * we need to keep one extra bd to check if ring is full or empty so + * reduce by 1 + */ + available_bd--; + dev_vdbg(bdc->dev, "available_bd:%d\n", available_bd); + + return available_bd; +} + +/* Notify the hardware after queueing the bd to bdl */ +void bdc_notify_xfr(struct bdc *bdc, u32 epnum) +{ + struct bdc_ep *ep = bdc->bdc_ep_array[epnum]; + + dev_vdbg(bdc->dev, "%s epnum:%d\n", __func__, epnum); + /* + * We don't have anyway to check if ep state is running, + * except the software flags. + */ + if (unlikely(ep->flags & BDC_EP_STOP)) + ep->flags &= ~BDC_EP_STOP; + + bdc_writel(bdc->regs, BDC_XSFNTF, epnum); +} + +/* returns the bd corresponding to bdi */ +static struct bdc_bd *bdi_to_bd(struct bdc_ep *ep, int bdi) +{ + int tbi = bdi_to_tbi(ep, bdi); + int local_bdi = 0; + + local_bdi = bdi - (tbi * ep->bd_list.num_bds_table); + dev_vdbg(ep->bdc->dev, + "%s bdi:%d local_bdi:%d\n", + __func__, bdi, local_bdi); + + return (ep->bd_list.bd_table_array[tbi]->start_bd + local_bdi); +} + +/* Advance the enqueue pointer */ +static void ep_bdlist_eqp_adv(struct bdc_ep *ep) +{ + ep->bd_list.eqp_bdi++; + /* if it's chain bd, then move to next */ + if (((ep->bd_list.eqp_bdi + 1) % ep->bd_list.num_bds_table) == 0) + ep->bd_list.eqp_bdi++; + + /* if the eqp is pointing to last + 1 then move back to 0 */ + if (ep->bd_list.eqp_bdi == (ep->bd_list.max_bdi + 1)) + ep->bd_list.eqp_bdi = 0; +} + +/* Setup the first bd for ep0 transfer */ +static int setup_first_bd_ep0(struct bdc *bdc, struct bdc_req *req, u32 *dword3) +{ + u16 wValue; + u32 req_len; + + req->ep->dir = 0; + req_len = req->usb_req.length; + switch (bdc->ep0_state) { + case WAIT_FOR_DATA_START: + *dword3 |= BD_TYPE_DS; + if (bdc->setup_pkt.bRequestType & USB_DIR_IN) + *dword3 |= BD_DIR_IN; + + /* check if zlp will be needed */ + wValue = le16_to_cpu(bdc->setup_pkt.wValue); + if ((wValue > req_len) && + (req_len % bdc->gadget.ep0->maxpacket == 0)) { + dev_dbg(bdc->dev, "ZLP needed wVal:%d len:%d MaxP:%d\n", + wValue, req_len, + bdc->gadget.ep0->maxpacket); + bdc->zlp_needed = true; + } + break; + + case WAIT_FOR_STATUS_START: + *dword3 |= BD_TYPE_SS; + if (!le16_to_cpu(bdc->setup_pkt.wLength) || + !(bdc->setup_pkt.bRequestType & USB_DIR_IN)) + *dword3 |= BD_DIR_IN; + break; + default: + dev_err(bdc->dev, + "Unknown ep0 state for queueing bd ep0_state:%s\n", + ep0_state_string[bdc->ep0_state]); + return -EINVAL; + } + + return 0; +} + +/* Setup the bd dma descriptor for a given request */ +static int setup_bd_list_xfr(struct bdc *bdc, struct bdc_req *req, int num_bds) +{ + dma_addr_t buf_add = req->usb_req.dma; + u32 maxp, tfs, dword2, dword3; + struct bd_transfer *bd_xfr; + struct bd_list *bd_list; + struct bdc_ep *ep; + struct bdc_bd *bd; + int ret, bdnum; + u32 req_len; + + ep = req->ep; + bd_list = &ep->bd_list; + bd_xfr = &req->bd_xfr; + bd_xfr->req = req; + bd_xfr->start_bdi = bd_list->eqp_bdi; + bd = bdi_to_bd(ep, bd_list->eqp_bdi); + req_len = req->usb_req.length; + maxp = usb_endpoint_maxp(ep->desc) & 0x7ff; + tfs = roundup(req->usb_req.length, maxp); + tfs = tfs/maxp; + dev_vdbg(bdc->dev, "%s ep:%s num_bds:%d tfs:%d r_len:%d bd:%p\n", + __func__, ep->name, num_bds, tfs, req_len, bd); + + for (bdnum = 0; bdnum < num_bds; bdnum++) { + dword2 = dword3 = 0; + /* First bd */ + if (!bdnum) { + dword3 |= BD_SOT|BD_SBF|(tfs<ep_num == 1) + ret = setup_first_bd_ep0(bdc, req, &dword3); + if (ret) + return ret; + } + if (!req->ep->dir) + dword3 |= BD_ISP; + + if (req_len > BD_MAX_BUFF_SIZE) { + dword2 |= BD_MAX_BUFF_SIZE; + req_len -= BD_MAX_BUFF_SIZE; + } else { + /* this should be the last bd */ + dword2 |= req_len; + dword3 |= BD_IOC; + dword3 |= BD_EOT; + } + /* Currently only 1 INT target is supported */ + dword2 |= BD_INTR_TARGET(0); + bd = bdi_to_bd(ep, ep->bd_list.eqp_bdi); + if (unlikely(!bd)) { + dev_err(bdc->dev, "Err bd pointing to wrong addr\n"); + return -EINVAL; + } + /* write bd */ + bd->offset[0] = cpu_to_le32(lower_32_bits(buf_add)); + bd->offset[1] = cpu_to_le32(upper_32_bits(buf_add)); + bd->offset[2] = cpu_to_le32(dword2); + bd->offset[3] = cpu_to_le32(dword3); + /* advance eqp pointer */ + ep_bdlist_eqp_adv(ep); + /* advance the buff pointer */ + buf_add += BD_MAX_BUFF_SIZE; + dev_vdbg(bdc->dev, "buf_add:%08llx req_len:%d bd:%p eqp:%d\n", + (unsigned long long)buf_add, req_len, bd, + ep->bd_list.eqp_bdi); + bd = bdi_to_bd(ep, ep->bd_list.eqp_bdi); + bd->offset[3] = cpu_to_le32(BD_SBF); + } + /* clear the STOP BD fetch bit from the first bd of this xfr */ + bd = bdi_to_bd(ep, bd_xfr->start_bdi); + bd->offset[3] &= cpu_to_le32(~BD_SBF); + /* the new eqp will be next hw dqp */ + bd_xfr->num_bds = num_bds; + bd_xfr->next_hwd_bdi = ep->bd_list.eqp_bdi; + /* everything is written correctly before notifying the HW */ + wmb(); + + return 0; +} + +/* Queue the xfr */ +static int bdc_queue_xfr(struct bdc *bdc, struct bdc_req *req) +{ + int num_bds, bd_available; + struct bdc_ep *ep; + int ret; + + ep = req->ep; + dev_dbg(bdc->dev, "%s req:%p\n", __func__, req); + dev_dbg(bdc->dev, "eqp_bdi:%d hwd_bdi:%d\n", + ep->bd_list.eqp_bdi, ep->bd_list.hwd_bdi); + + num_bds = bd_needed_req(req); + bd_available = bd_available_ep(ep); + + /* how many bd's are avaialble on ep */ + if (num_bds > bd_available) + return -ENOMEM; + + ret = setup_bd_list_xfr(bdc, req, num_bds); + if (ret) + return ret; + list_add_tail(&req->queue, &ep->queue); + bdc_dbg_bd_list(bdc, ep); + bdc_notify_xfr(bdc, ep->ep_num); + + return 0; +} + +/* callback to gadget layer when xfr completes */ +static void bdc_req_complete(struct bdc_ep *ep, struct bdc_req *req, + int status) +{ + struct bdc *bdc = ep->bdc; + + if (req == NULL || &req->queue == NULL || &req->usb_req == NULL) + return; + + dev_dbg(bdc->dev, "%s ep:%s status:%d\n", __func__, ep->name, status); + list_del(&req->queue); + req->usb_req.status = status; + usb_gadget_unmap_request(&bdc->gadget, &req->usb_req, ep->dir); + if (req->usb_req.complete) { + spin_unlock(&bdc->lock); + usb_gadget_giveback_request(&ep->usb_ep, &req->usb_req); + spin_lock(&bdc->lock); + } +} + +/* Disable the endpoint */ +int bdc_ep_disable(struct bdc_ep *ep) +{ + struct bdc_req *req; + struct bdc *bdc; + int ret; + + ret = 0; + bdc = ep->bdc; + dev_dbg(bdc->dev, "%s() ep->ep_num=%d\n", __func__, ep->ep_num); + /* Stop the endpoint */ + ret = bdc_stop_ep(bdc, ep->ep_num); + + /* + * Intentionally don't check the ret value of stop, it can fail in + * disconnect scenarios, continue with dconfig + */ + /* de-queue any pending requests */ + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct bdc_req, + queue); + bdc_req_complete(ep, req, -ESHUTDOWN); + } + /* deconfigure the endpoint */ + ret = bdc_dconfig_ep(bdc, ep); + if (ret) + dev_warn(bdc->dev, + "dconfig fail but continue with memory free"); + + ep->flags = 0; + /* ep0 memory is not freed, but reused on next connect sr */ + if (ep->ep_num == 1) + return 0; + + /* Free the bdl memory */ + ep_bd_list_free(ep, ep->bd_list.num_tabs); + ep->desc = NULL; + ep->comp_desc = NULL; + ep->usb_ep.desc = NULL; + ep->ep_type = 0; + + return ret; +} + +/* Enable the ep */ +int bdc_ep_enable(struct bdc_ep *ep) +{ + struct bdc *bdc; + int ret = 0; + + bdc = ep->bdc; + dev_dbg(bdc->dev, "%s NUM_TABLES:%d %d\n", + __func__, NUM_TABLES, NUM_TABLES_ISOCH); + + ret = ep_bd_list_alloc(ep); + if (ret) { + dev_err(bdc->dev, "ep bd list allocation failed:%d\n", ret); + return -ENOMEM; + } + bdc_dbg_bd_list(bdc, ep); + /* only for ep0: config ep is called for ep0 from connect event */ + ep->flags |= BDC_EP_ENABLED; + if (ep->ep_num == 1) + return ret; + + /* Issue a configure endpoint command */ + ret = bdc_config_ep(bdc, ep); + if (ret) + return ret; + + ep->usb_ep.maxpacket = usb_endpoint_maxp(ep->desc); + ep->usb_ep.desc = ep->desc; + ep->usb_ep.comp_desc = ep->comp_desc; + ep->ep_type = usb_endpoint_type(ep->desc); + ep->flags |= BDC_EP_ENABLED; + + return 0; +} + +/* EP0 related code */ + +/* Queue a status stage BD */ +static int ep0_queue_status_stage(struct bdc *bdc) +{ + struct bdc_req *status_req; + struct bdc_ep *ep; + + status_req = &bdc->status_req; + ep = bdc->bdc_ep_array[1]; + status_req->ep = ep; + status_req->usb_req.length = 0; + status_req->usb_req.status = -EINPROGRESS; + status_req->usb_req.actual = 0; + status_req->usb_req.complete = NULL; + bdc_queue_xfr(bdc, status_req); + + return 0; +} + +/* Queue xfr on ep0 */ +static int ep0_queue(struct bdc_ep *ep, struct bdc_req *req) +{ + struct bdc *bdc; + int ret; + + bdc = ep->bdc; + dev_dbg(bdc->dev, "%s()\n", __func__); + req->usb_req.actual = 0; + req->usb_req.status = -EINPROGRESS; + req->epnum = ep->ep_num; + + if (bdc->delayed_status) { + bdc->delayed_status = false; + /* if status stage was delayed? */ + if (bdc->ep0_state == WAIT_FOR_STATUS_START) { + /* Queue a status stage BD */ + ep0_queue_status_stage(bdc); + bdc->ep0_state = WAIT_FOR_STATUS_XMIT; + return 0; + } + } else { + /* + * if delayed status is false and 0 length transfer is requested + * i.e. for status stage of some setup request, then just + * return from here the status stage is queued independently + */ + if (req->usb_req.length == 0) + return 0; + + } + ret = usb_gadget_map_request(&bdc->gadget, &req->usb_req, ep->dir); + if (ret) { + dev_err(bdc->dev, "dma mapping failed %s\n", ep->name); + return ret; + } + + return bdc_queue_xfr(bdc, req); +} + +/* Queue data stage */ +static int ep0_queue_data_stage(struct bdc *bdc) +{ + struct usb_request *ep0_usb_req; + struct bdc_ep *ep; + + dev_dbg(bdc->dev, "%s\n", __func__); + ep0_usb_req = &bdc->ep0_req.usb_req; + ep = bdc->bdc_ep_array[1]; + bdc->ep0_req.ep = ep; + bdc->ep0_req.usb_req.complete = NULL; + + return ep0_queue(ep, &bdc->ep0_req); +} + +/* Queue req on ep */ +static int ep_queue(struct bdc_ep *ep, struct bdc_req *req) +{ + struct bdc *bdc; + int ret = 0; + + bdc = ep->bdc; + if (!req || !ep || !ep->usb_ep.desc) + return -EINVAL; + + req->usb_req.actual = 0; + req->usb_req.status = -EINPROGRESS; + req->epnum = ep->ep_num; + + ret = usb_gadget_map_request(&bdc->gadget, &req->usb_req, ep->dir); + if (ret) { + dev_err(bdc->dev, "dma mapping failed\n"); + return ret; + } + + return bdc_queue_xfr(bdc, req); +} + +/* Dequeue a request from ep */ +static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) +{ + int start_bdi, end_bdi, tbi, eqp_bdi, curr_hw_dqpi; + bool start_pending, end_pending; + bool first_remove = false; + struct bdc_req *first_req; + struct bdc_bd *bd_start; + struct bd_table *table; + dma_addr_t next_bd_dma; + u64 deq_ptr_64 = 0; + struct bdc *bdc; + u32 tmp_32; + int ret; + + bdc = ep->bdc; + start_pending = end_pending = false; + eqp_bdi = ep->bd_list.eqp_bdi - 1; + + if (eqp_bdi < 0) + eqp_bdi = ep->bd_list.max_bdi; + + start_bdi = req->bd_xfr.start_bdi; + end_bdi = find_end_bdi(ep, req->bd_xfr.next_hwd_bdi); + + dev_dbg(bdc->dev, "%s ep:%s start:%d end:%d\n", + __func__, ep->name, start_bdi, end_bdi); + dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n", + ep, (void *)ep->usb_ep.desc); + /* Stop the ep to see where the HW is ? */ + ret = bdc_stop_ep(bdc, ep->ep_num); + /* if there is an issue with stopping ep, then no need to go further */ + if (ret) + return 0; + + /* + * After endpoint is stopped, there can be 3 cases, the request + * is processed, pending or in the middle of processing + */ + + /* The current hw dequeue pointer */ + tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0)); + deq_ptr_64 = tmp_32; + tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(1)); + deq_ptr_64 |= ((u64)tmp_32 << 32); + + /* we have the dma addr of next bd that will be fetched by hardware */ + curr_hw_dqpi = bd_add_to_bdi(ep, deq_ptr_64); + if (curr_hw_dqpi < 0) + return curr_hw_dqpi; + + /* + * curr_hw_dqpi points to actual dqp of HW and HW owns bd's from + * curr_hw_dqbdi..eqp_bdi. + */ + + /* Check if start_bdi and end_bdi are in range of HW owned BD's */ + if (curr_hw_dqpi > eqp_bdi) { + /* there is a wrap from last to 0 */ + if (start_bdi >= curr_hw_dqpi || start_bdi <= eqp_bdi) { + start_pending = true; + end_pending = true; + } else if (end_bdi >= curr_hw_dqpi || end_bdi <= eqp_bdi) { + end_pending = true; + } + } else { + if (start_bdi >= curr_hw_dqpi) { + start_pending = true; + end_pending = true; + } else if (end_bdi >= curr_hw_dqpi) { + end_pending = true; + } + } + dev_dbg(bdc->dev, + "start_pending:%d end_pending:%d speed:%d\n", + start_pending, end_pending, bdc->gadget.speed); + + /* If both start till end are processes, we cannot deq req */ + if (!start_pending && !end_pending) + return -EINVAL; + + /* + * if ep_dequeue is called after disconnect then just return + * success from here + */ + if (bdc->gadget.speed == USB_SPEED_UNKNOWN) + return 0; + tbi = bdi_to_tbi(ep, req->bd_xfr.next_hwd_bdi); + table = ep->bd_list.bd_table_array[tbi]; + next_bd_dma = table->dma + + sizeof(struct bdc_bd)*(req->bd_xfr.next_hwd_bdi - + tbi * ep->bd_list.num_bds_table); + + first_req = list_first_entry(&ep->queue, struct bdc_req, + queue); + + if (req == first_req) + first_remove = true; + + /* + * Due to HW limitation we need to bypadd chain bd's and issue ep_bla, + * incase if start is pending this is the first request in the list + * then issue ep_bla instead of marking as chain bd + */ + if (start_pending && !first_remove) { + /* + * Mark the start bd as Chain bd, and point the chain + * bd to next_bd_dma + */ + bd_start = bdi_to_bd(ep, start_bdi); + bd_start->offset[0] = cpu_to_le32(lower_32_bits(next_bd_dma)); + bd_start->offset[1] = cpu_to_le32(upper_32_bits(next_bd_dma)); + bd_start->offset[2] = 0x0; + bd_start->offset[3] = cpu_to_le32(MARK_CHAIN_BD); + bdc_dbg_bd_list(bdc, ep); + } else if (end_pending) { + /* + * The transfer is stopped in the middle, move the + * HW deq pointer to next_bd_dma + */ + ret = bdc_ep_bla(bdc, ep, next_bd_dma); + if (ret) { + dev_err(bdc->dev, "error in ep_bla:%d\n", ret); + return ret; + } + } + + return 0; +} + +/* Halt/Clear the ep based on value */ +static int ep_set_halt(struct bdc_ep *ep, u32 value) +{ + struct bdc *bdc; + int ret; + + bdc = ep->bdc; + dev_dbg(bdc->dev, "%s ep:%s value=%d\n", __func__, ep->name, value); + + if (value) { + dev_dbg(bdc->dev, "Halt\n"); + if (ep->ep_num == 1) + bdc->ep0_state = WAIT_FOR_SETUP; + + ret = bdc_ep_set_stall(bdc, ep->ep_num); + if (ret) + dev_err(bdc->dev, "failed to %s STALL on %s\n", + value ? "set" : "clear", ep->name); + else + ep->flags |= BDC_EP_STALL; + } else { + /* Clear */ + dev_dbg(bdc->dev, "Before Clear\n"); + ret = bdc_ep_clear_stall(bdc, ep->ep_num); + if (ret) + dev_err(bdc->dev, "failed to %s STALL on %s\n", + value ? "set" : "clear", ep->name); + else + ep->flags &= ~BDC_EP_STALL; + dev_dbg(bdc->dev, "After Clear\n"); + } + + return ret; +} + +/* Free all the ep */ +void bdc_free_ep(struct bdc *bdc) +{ + struct bdc_ep *ep; + u8 epnum; + + dev_dbg(bdc->dev, "%s\n", __func__); + for (epnum = 1; epnum < bdc->num_eps; epnum++) { + ep = bdc->bdc_ep_array[epnum]; + if (!ep) + continue; + + if (ep->flags & BDC_EP_ENABLED) + ep_bd_list_free(ep, ep->bd_list.num_tabs); + + /* ep0 is not in this gadget list */ + if (epnum != 1) + list_del(&ep->usb_ep.ep_list); + + kfree(ep); + } +} + +/* USB2 spec, section 7.1.20 */ +static int bdc_set_test_mode(struct bdc *bdc) +{ + u32 usb2_pm; + + usb2_pm = bdc_readl(bdc->regs, BDC_USPPM2); + usb2_pm &= ~BDC_PTC_MASK; + dev_dbg(bdc->dev, "%s\n", __func__); + switch (bdc->test_mode) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + usb2_pm |= bdc->test_mode << 28; + break; + default: + return -EINVAL; + } + dev_dbg(bdc->dev, "usb2_pm=%08x", usb2_pm); + bdc_writel(bdc->regs, BDC_USPPM2, usb2_pm); + + return 0; +} + +/* + * Helper function to handle Transfer status report with status as either + * success or short + */ +static void handle_xsr_succ_status(struct bdc *bdc, struct bdc_ep *ep, + struct bdc_sr *sreport) +{ + int short_bdi, start_bdi, end_bdi, max_len_bds, chain_bds; + struct bd_list *bd_list = &ep->bd_list; + int actual_length, length_short; + struct bd_transfer *bd_xfr; + struct bdc_bd *short_bd; + struct bdc_req *req; + u64 deq_ptr_64 = 0; + int status = 0; + int sr_status; + u32 tmp_32; + + dev_dbg(bdc->dev, "%s ep:%p\n", __func__, ep); + bdc_dbg_srr(bdc, 0); + /* do not process thie sr if ignore flag is set */ + if (ep->ignore_next_sr) { + ep->ignore_next_sr = false; + return; + } + + if (unlikely(list_empty(&ep->queue))) { + dev_warn(bdc->dev, "xfr srr with no BD's queued\n"); + return; + } + req = list_entry(ep->queue.next, struct bdc_req, + queue); + + bd_xfr = &req->bd_xfr; + sr_status = XSF_STS(le32_to_cpu(sreport->offset[3])); + + /* + * sr_status is short and this transfer has more than 1 bd then it needs + * special handling, this is only applicable for bulk and ctrl + */ + if (sr_status == XSF_SHORT && bd_xfr->num_bds > 1) { + /* + * This is multi bd xfr, lets see which bd + * caused short transfer and how many bytes have been + * transferred so far. + */ + tmp_32 = le32_to_cpu(sreport->offset[0]); + deq_ptr_64 = tmp_32; + tmp_32 = le32_to_cpu(sreport->offset[1]); + deq_ptr_64 |= ((u64)tmp_32 << 32); + short_bdi = bd_add_to_bdi(ep, deq_ptr_64); + if (unlikely(short_bdi < 0)) + dev_warn(bdc->dev, "bd doesn't exist?\n"); + + start_bdi = bd_xfr->start_bdi; + /* + * We know the start_bdi and short_bdi, how many xfr + * bds in between + */ + if (start_bdi <= short_bdi) { + max_len_bds = short_bdi - start_bdi; + if (max_len_bds <= bd_list->num_bds_table) { + if (!(bdi_to_tbi(ep, start_bdi) == + bdi_to_tbi(ep, short_bdi))) + max_len_bds--; + } else { + chain_bds = max_len_bds/bd_list->num_bds_table; + max_len_bds -= chain_bds; + } + } else { + /* there is a wrap in the ring within a xfr */ + chain_bds = (bd_list->max_bdi - start_bdi)/ + bd_list->num_bds_table; + chain_bds += short_bdi/bd_list->num_bds_table; + max_len_bds = bd_list->max_bdi - start_bdi; + max_len_bds += short_bdi; + max_len_bds -= chain_bds; + } + /* max_len_bds is the number of full length bds */ + end_bdi = find_end_bdi(ep, bd_xfr->next_hwd_bdi); + if (!(end_bdi == short_bdi)) + ep->ignore_next_sr = true; + + actual_length = max_len_bds * BD_MAX_BUFF_SIZE; + short_bd = bdi_to_bd(ep, short_bdi); + /* length queued */ + length_short = le32_to_cpu(short_bd->offset[2]) & 0x1FFFFF; + /* actual length trensfered */ + length_short -= SR_BD_LEN(le32_to_cpu(sreport->offset[2])); + actual_length += length_short; + req->usb_req.actual = actual_length; + } else { + req->usb_req.actual = req->usb_req.length - + SR_BD_LEN(le32_to_cpu(sreport->offset[2])); + dev_dbg(bdc->dev, + "len=%d actual=%d bd_xfr->next_hwd_bdi:%d\n", + req->usb_req.length, req->usb_req.actual, + bd_xfr->next_hwd_bdi); + } + + /* Update the dequeue pointer */ + ep->bd_list.hwd_bdi = bd_xfr->next_hwd_bdi; + if (req->usb_req.actual < req->usb_req.length) { + dev_dbg(bdc->dev, "short xfr on %d\n", ep->ep_num); + if (req->usb_req.short_not_ok) + status = -EREMOTEIO; + } + bdc_req_complete(ep, bd_xfr->req, status); +} + +/* EP0 setup related packet handlers */ + +/* + * Setup packet received, just store the packet and process on next DS or SS + * started SR + */ +void bdc_xsf_ep0_setup_recv(struct bdc *bdc, struct bdc_sr *sreport) +{ + struct usb_ctrlrequest *setup_pkt; + u32 len; + + dev_dbg(bdc->dev, + "%s ep0_state:%s\n", + __func__, ep0_state_string[bdc->ep0_state]); + /* Store received setup packet */ + setup_pkt = &bdc->setup_pkt; + memcpy(setup_pkt, &sreport->offset[0], sizeof(*setup_pkt)); + len = le16_to_cpu(setup_pkt->wLength); + if (!len) + bdc->ep0_state = WAIT_FOR_STATUS_START; + else + bdc->ep0_state = WAIT_FOR_DATA_START; + + + dev_dbg(bdc->dev, + "%s exit ep0_state:%s\n", + __func__, ep0_state_string[bdc->ep0_state]); +} + +/* Stall ep0 */ +static void ep0_stall(struct bdc *bdc) +{ + struct bdc_ep *ep = bdc->bdc_ep_array[1]; + struct bdc_req *req; + + dev_dbg(bdc->dev, "%s\n", __func__); + bdc->delayed_status = false; + ep_set_halt(ep, 1); + + /* de-queue any pendig requests */ + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct bdc_req, + queue); + bdc_req_complete(ep, req, -ESHUTDOWN); + } +} + +/* SET_ADD handlers */ +static int ep0_set_address(struct bdc *bdc, struct usb_ctrlrequest *ctrl) +{ + enum usb_device_state state = bdc->gadget.state; + int ret = 0; + u32 addr; + + addr = le16_to_cpu(ctrl->wValue); + dev_dbg(bdc->dev, + "%s addr:%d dev state:%d\n", + __func__, addr, state); + + if (addr > 127) + return -EINVAL; + + switch (state) { + case USB_STATE_DEFAULT: + case USB_STATE_ADDRESS: + /* Issue Address device command */ + ret = bdc_address_device(bdc, addr); + if (ret) + return ret; + + if (addr) + usb_gadget_set_state(&bdc->gadget, USB_STATE_ADDRESS); + else + usb_gadget_set_state(&bdc->gadget, USB_STATE_DEFAULT); + + bdc->dev_addr = addr; + break; + default: + dev_warn(bdc->dev, + "SET Address in wrong device state %d\n", + state); + ret = -EINVAL; + } + + return ret; +} + +/* Handler for SET/CLEAR FEATURE requests for device */ +static int ep0_handle_feature_dev(struct bdc *bdc, u16 wValue, + u16 wIndex, bool set) +{ + enum usb_device_state state = bdc->gadget.state; + u32 usppms = 0; + + dev_dbg(bdc->dev, "%s set:%d dev state:%d\n", + __func__, set, state); + switch (wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + dev_dbg(bdc->dev, "USB_DEVICE_REMOTE_WAKEUP\n"); + if (set) + bdc->devstatus |= REMOTE_WAKE_ENABLE; + else + bdc->devstatus &= ~REMOTE_WAKE_ENABLE; + break; + + case USB_DEVICE_TEST_MODE: + dev_dbg(bdc->dev, "USB_DEVICE_TEST_MODE\n"); + if ((wIndex & 0xFF) || + (bdc->gadget.speed != USB_SPEED_HIGH) || !set) + return -EINVAL; + + bdc->test_mode = wIndex >> 8; + break; + + case USB_DEVICE_U1_ENABLE: + dev_dbg(bdc->dev, "USB_DEVICE_U1_ENABLE\n"); + + if (bdc->gadget.speed != USB_SPEED_SUPER || + state != USB_STATE_CONFIGURED) + return -EINVAL; + + usppms = bdc_readl(bdc->regs, BDC_USPPMS); + if (set) { + /* clear previous u1t */ + usppms &= ~BDC_U1T(BDC_U1T_MASK); + usppms |= BDC_U1T(U1_TIMEOUT); + usppms |= BDC_U1E | BDC_PORT_W1S; + bdc->devstatus |= (1 << USB_DEV_STAT_U1_ENABLED); + } else { + usppms &= ~BDC_U1E; + usppms |= BDC_PORT_W1S; + bdc->devstatus &= ~(1 << USB_DEV_STAT_U1_ENABLED); + } + bdc_writel(bdc->regs, BDC_USPPMS, usppms); + break; + + case USB_DEVICE_U2_ENABLE: + dev_dbg(bdc->dev, "USB_DEVICE_U2_ENABLE\n"); + + if (bdc->gadget.speed != USB_SPEED_SUPER || + state != USB_STATE_CONFIGURED) + return -EINVAL; + + usppms = bdc_readl(bdc->regs, BDC_USPPMS); + if (set) { + usppms |= BDC_U2E; + usppms |= BDC_U2A; + bdc->devstatus |= (1 << USB_DEV_STAT_U2_ENABLED); + } else { + usppms &= ~BDC_U2E; + usppms &= ~BDC_U2A; + bdc->devstatus &= ~(1 << USB_DEV_STAT_U2_ENABLED); + } + bdc_writel(bdc->regs, BDC_USPPMS, usppms); + break; + + case USB_DEVICE_LTM_ENABLE: + dev_dbg(bdc->dev, "USB_DEVICE_LTM_ENABLE?\n"); + if (bdc->gadget.speed != USB_SPEED_SUPER || + state != USB_STATE_CONFIGURED) + return -EINVAL; + break; + default: + dev_err(bdc->dev, "Unknown wValue:%d\n", wValue); + return -EOPNOTSUPP; + } /* USB_RECIP_DEVICE end */ + + return 0; +} + +/* SET/CLEAR FEATURE handler */ +static int ep0_handle_feature(struct bdc *bdc, + struct usb_ctrlrequest *setup_pkt, bool set) +{ + enum usb_device_state state = bdc->gadget.state; + struct bdc_ep *ep; + u16 wValue; + u16 wIndex; + int epnum; + + wValue = le16_to_cpu(setup_pkt->wValue); + wIndex = le16_to_cpu(setup_pkt->wIndex); + + dev_dbg(bdc->dev, + "%s wValue=%d wIndex=%d devstate=%08x speed=%d set=%d", + __func__, wValue, wIndex, state, + bdc->gadget.speed, set); + + switch (setup_pkt->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + return ep0_handle_feature_dev(bdc, wValue, wIndex, set); + case USB_RECIP_INTERFACE: + dev_dbg(bdc->dev, "USB_RECIP_INTERFACE\n"); + /* USB3 spec, sec 9.4.9 */ + if (wValue != USB_INTRF_FUNC_SUSPEND) + return -EINVAL; + /* USB3 spec, Table 9-8 */ + if (set) { + if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) { + dev_dbg(bdc->dev, "SET REMOTE_WAKEUP\n"); + bdc->devstatus |= REMOTE_WAKE_ENABLE; + } else { + dev_dbg(bdc->dev, "CLEAR REMOTE_WAKEUP\n"); + bdc->devstatus &= ~REMOTE_WAKE_ENABLE; + } + } + break; + + case USB_RECIP_ENDPOINT: + dev_dbg(bdc->dev, "USB_RECIP_ENDPOINT\n"); + if (wValue != USB_ENDPOINT_HALT) + return -EINVAL; + + epnum = wIndex & USB_ENDPOINT_NUMBER_MASK; + if (epnum) { + if ((wIndex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + epnum = epnum * 2 + 1; + else + epnum *= 2; + } else { + epnum = 1; /*EP0*/ + } + /* + * If CLEAR_FEATURE on ep0 then don't do anything as the stall + * condition on ep0 has already been cleared when SETUP packet + * was received. + */ + if (epnum == 1 && !set) { + dev_dbg(bdc->dev, "ep0 stall already cleared\n"); + return 0; + } + dev_dbg(bdc->dev, "epnum=%d\n", epnum); + ep = bdc->bdc_ep_array[epnum]; + if (!ep) + return -EINVAL; + + return ep_set_halt(ep, set); + default: + dev_err(bdc->dev, "Unknown recipient\n"); + return -EINVAL; + } + + return 0; +} + +/* GET_STATUS request handler */ +static int ep0_handle_status(struct bdc *bdc, + struct usb_ctrlrequest *setup_pkt) +{ + enum usb_device_state state = bdc->gadget.state; + struct bdc_ep *ep; + u16 usb_status = 0; + u32 epnum; + u16 wIndex; + + /* USB2.0 spec sec 9.4.5 */ + if (state == USB_STATE_DEFAULT) + return -EINVAL; + wIndex = le16_to_cpu(setup_pkt->wIndex); + dev_dbg(bdc->dev, "%s\n", __func__); + usb_status = bdc->devstatus; + switch (setup_pkt->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + dev_dbg(bdc->dev, + "USB_RECIP_DEVICE devstatus:%08x\n", + bdc->devstatus); + /* USB3 spec, sec 9.4.5 */ + if (bdc->gadget.speed == USB_SPEED_SUPER) + usb_status &= ~REMOTE_WAKE_ENABLE; + break; + + case USB_RECIP_INTERFACE: + dev_dbg(bdc->dev, "USB_RECIP_INTERFACE\n"); + if (bdc->gadget.speed == USB_SPEED_SUPER) { + /* + * This should come from func for Func remote wkup + * usb_status |=1; + */ + if (bdc->devstatus & REMOTE_WAKE_ENABLE) + usb_status |= REMOTE_WAKE_ENABLE; + } else { + usb_status = 0; + } + + break; + + case USB_RECIP_ENDPOINT: + dev_dbg(bdc->dev, "USB_RECIP_ENDPOINT\n"); + epnum = wIndex & USB_ENDPOINT_NUMBER_MASK; + if (epnum) { + if ((wIndex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + epnum = epnum*2 + 1; + else + epnum *= 2; + } else { + epnum = 1; /* EP0 */ + } + + ep = bdc->bdc_ep_array[epnum]; + if (!ep) { + dev_err(bdc->dev, "ISSUE, GET_STATUS for invalid EP ?"); + return -EINVAL; + } + if (ep->flags & BDC_EP_STALL) + usb_status |= 1 << USB_ENDPOINT_HALT; + + break; + default: + dev_err(bdc->dev, "Unknown recipient for get_status\n"); + return -EINVAL; + } + /* prepare a data stage for GET_STATUS */ + dev_dbg(bdc->dev, "usb_status=%08x\n", usb_status); + *(__le16 *)bdc->ep0_response_buff = cpu_to_le16(usb_status); + bdc->ep0_req.usb_req.length = 2; + bdc->ep0_req.usb_req.buf = &bdc->ep0_response_buff; + ep0_queue_data_stage(bdc); + + return 0; +} + +static void ep0_set_sel_cmpl(struct usb_ep *_ep, struct usb_request *_req) +{ + /* ep0_set_sel_cmpl */ +} + +/* Queue data stage to handle 6 byte SET_SEL request */ +static int ep0_set_sel(struct bdc *bdc, + struct usb_ctrlrequest *setup_pkt) +{ + struct bdc_ep *ep; + u16 wLength; + u16 wValue; + + dev_dbg(bdc->dev, "%s\n", __func__); + wValue = le16_to_cpu(setup_pkt->wValue); + wLength = le16_to_cpu(setup_pkt->wLength); + if (unlikely(wLength != 6)) { + dev_err(bdc->dev, "%s Wrong wLength:%d\n", __func__, wLength); + return -EINVAL; + } + ep = bdc->bdc_ep_array[1]; + bdc->ep0_req.ep = ep; + bdc->ep0_req.usb_req.length = 6; + bdc->ep0_req.usb_req.buf = bdc->ep0_response_buff; + bdc->ep0_req.usb_req.complete = ep0_set_sel_cmpl; + ep0_queue_data_stage(bdc); + + return 0; +} + +/* + * Queue a 0 byte bd only if wLength is more than the length and and length is + * a multiple of MaxPacket then queue 0 byte BD + */ +static int ep0_queue_zlp(struct bdc *bdc) +{ + int ret; + + dev_dbg(bdc->dev, "%s\n", __func__); + bdc->ep0_req.ep = bdc->bdc_ep_array[1]; + bdc->ep0_req.usb_req.length = 0; + bdc->ep0_req.usb_req.complete = NULL; + bdc->ep0_state = WAIT_FOR_DATA_START; + ret = bdc_queue_xfr(bdc, &bdc->ep0_req); + if (ret) { + dev_err(bdc->dev, "err queueing zlp :%d\n", ret); + return ret; + } + bdc->ep0_state = WAIT_FOR_DATA_XMIT; + + return 0; +} + +/* Control request handler */ +static int handle_control_request(struct bdc *bdc) +{ + enum usb_device_state state = bdc->gadget.state; + struct usb_ctrlrequest *setup_pkt; + int delegate_setup = 0; + int ret = 0; + int config = 0; + + setup_pkt = &bdc->setup_pkt; + dev_dbg(bdc->dev, "%s\n", __func__); + if ((setup_pkt->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + switch (setup_pkt->bRequest) { + case USB_REQ_SET_ADDRESS: + dev_dbg(bdc->dev, "USB_REQ_SET_ADDRESS\n"); + ret = ep0_set_address(bdc, setup_pkt); + bdc->devstatus &= DEVSTATUS_CLEAR; + break; + + case USB_REQ_SET_CONFIGURATION: + dev_dbg(bdc->dev, "USB_REQ_SET_CONFIGURATION\n"); + if (state == USB_STATE_ADDRESS) { + usb_gadget_set_state(&bdc->gadget, + USB_STATE_CONFIGURED); + } else if (state == USB_STATE_CONFIGURED) { + /* + * USB2 spec sec 9.4.7, if wValue is 0 then dev + * is moved to addressed state + */ + config = le16_to_cpu(setup_pkt->wValue); + if (!config) + usb_gadget_set_state( + &bdc->gadget, + USB_STATE_ADDRESS); + } + delegate_setup = 1; + break; + + case USB_REQ_SET_FEATURE: + dev_dbg(bdc->dev, "USB_REQ_SET_FEATURE\n"); + ret = ep0_handle_feature(bdc, setup_pkt, 1); + break; + + case USB_REQ_CLEAR_FEATURE: + dev_dbg(bdc->dev, "USB_REQ_CLEAR_FEATURE\n"); + ret = ep0_handle_feature(bdc, setup_pkt, 0); + break; + + case USB_REQ_GET_STATUS: + dev_dbg(bdc->dev, "USB_REQ_GET_STATUS\n"); + ret = ep0_handle_status(bdc, setup_pkt); + break; + + case USB_REQ_SET_SEL: + dev_dbg(bdc->dev, "USB_REQ_SET_SEL\n"); + ret = ep0_set_sel(bdc, setup_pkt); + break; + + case USB_REQ_SET_ISOCH_DELAY: + dev_warn(bdc->dev, + "USB_REQ_SET_ISOCH_DELAY not handled\n"); + ret = 0; + break; + default: + delegate_setup = 1; + } + } else { + delegate_setup = 1; + } + + if (delegate_setup) { + spin_unlock(&bdc->lock); + ret = bdc->gadget_driver->setup(&bdc->gadget, setup_pkt); + spin_lock(&bdc->lock); + } + + return ret; +} + +/* EP0: Data stage started */ +void bdc_xsf_ep0_data_start(struct bdc *bdc, struct bdc_sr *sreport) +{ + struct bdc_ep *ep; + int ret = 0; + + dev_dbg(bdc->dev, "%s\n", __func__); + ep = bdc->bdc_ep_array[1]; + /* If ep0 was stalled, the clear it first */ + if (ep->flags & BDC_EP_STALL) { + ret = ep_set_halt(ep, 0); + if (ret) + goto err; + } + if (bdc->ep0_state != WAIT_FOR_DATA_START) + dev_warn(bdc->dev, + "Data stage not expected ep0_state:%s\n", + ep0_state_string[bdc->ep0_state]); + + ret = handle_control_request(bdc); + if (ret == USB_GADGET_DELAYED_STATUS) { + /* + * The ep0 state will remain WAIT_FOR_DATA_START till + * we received ep_queue on ep0 + */ + bdc->delayed_status = true; + return; + } + if (!ret) { + bdc->ep0_state = WAIT_FOR_DATA_XMIT; + dev_dbg(bdc->dev, + "ep0_state:%s", ep0_state_string[bdc->ep0_state]); + return; + } +err: + ep0_stall(bdc); +} + +/* EP0: status stage started */ +void bdc_xsf_ep0_status_start(struct bdc *bdc, struct bdc_sr *sreport) +{ + struct usb_ctrlrequest *setup_pkt; + struct bdc_ep *ep; + int ret = 0; + + dev_dbg(bdc->dev, + "%s ep0_state:%s", + __func__, ep0_state_string[bdc->ep0_state]); + ep = bdc->bdc_ep_array[1]; + + /* check if ZLP was queued? */ + if (bdc->zlp_needed) + bdc->zlp_needed = false; + + if (ep->flags & BDC_EP_STALL) { + ret = ep_set_halt(ep, 0); + if (ret) + goto err; + } + + if ((bdc->ep0_state != WAIT_FOR_STATUS_START) && + (bdc->ep0_state != WAIT_FOR_DATA_XMIT)) + dev_err(bdc->dev, + "Status stage recv but ep0_state:%s\n", + ep0_state_string[bdc->ep0_state]); + + /* check if data stage is in progress ? */ + if (bdc->ep0_state == WAIT_FOR_DATA_XMIT) { + bdc->ep0_state = STATUS_PENDING; + /* Status stage will be queued upon Data stage transmit event */ + dev_dbg(bdc->dev, + "status started but data not transmitted yet\n"); + return; + } + setup_pkt = &bdc->setup_pkt; + + /* + * 2 stage setup then only process the setup, for 3 stage setup the date + * stage is already handled + */ + if (!le16_to_cpu(setup_pkt->wLength)) { + ret = handle_control_request(bdc); + if (ret == USB_GADGET_DELAYED_STATUS) { + bdc->delayed_status = true; + /* ep0_state will remain WAIT_FOR_STATUS_START */ + return; + } + } + if (!ret) { + /* Queue a status stage BD */ + ep0_queue_status_stage(bdc); + bdc->ep0_state = WAIT_FOR_STATUS_XMIT; + dev_dbg(bdc->dev, + "ep0_state:%s", ep0_state_string[bdc->ep0_state]); + return; + } +err: + ep0_stall(bdc); +} + +/* Helper function to update ep0 upon SR with xsf_succ or xsf_short */ +static void ep0_xsf_complete(struct bdc *bdc, struct bdc_sr *sreport) +{ + dev_dbg(bdc->dev, "%s\n", __func__); + switch (bdc->ep0_state) { + case WAIT_FOR_DATA_XMIT: + bdc->ep0_state = WAIT_FOR_STATUS_START; + break; + case WAIT_FOR_STATUS_XMIT: + bdc->ep0_state = WAIT_FOR_SETUP; + if (bdc->test_mode) { + int ret; + + dev_dbg(bdc->dev, "test_mode:%d\n", bdc->test_mode); + ret = bdc_set_test_mode(bdc); + if (ret < 0) { + dev_err(bdc->dev, "Err in setting Test mode\n"); + return; + } + bdc->test_mode = 0; + } + break; + case STATUS_PENDING: + bdc_xsf_ep0_status_start(bdc, sreport); + break; + + default: + dev_err(bdc->dev, + "Unknown ep0_state:%s\n", + ep0_state_string[bdc->ep0_state]); + + } +} + +/* xfr completion status report handler */ +void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) +{ + struct bdc_ep *ep; + u32 sr_status; + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); + return; + } + /* + * check if this transfer is after link went from U3->U0 due + * to remote wakeup + */ + if (bdc->devstatus & FUNC_WAKE_ISSUED) { + bdc->devstatus &= ~(FUNC_WAKE_ISSUED); + dev_dbg(bdc->dev, "%s clearing FUNC_WAKE_ISSUED flag\n", + __func__); + } + sr_status = XSF_STS(le32_to_cpu(sreport->offset[3])); + dev_dbg_ratelimited(bdc->dev, "%s sr_status=%d ep:%s\n", + __func__, sr_status, ep->name); + + switch (sr_status) { + case XSF_SUCC: + case XSF_SHORT: + handle_xsr_succ_status(bdc, ep, sreport); + if (ep_num == 1) + ep0_xsf_complete(bdc, sreport); + break; + + case XSF_SETUP_RECV: + case XSF_DATA_START: + case XSF_STATUS_START: + if (ep_num != 1) { + dev_err(bdc->dev, + "ep0 related packets on non ep0 endpoint"); + return; + } + bdc->sr_xsf_ep0[sr_status - XSF_SETUP_RECV](bdc, sreport); + break; + + case XSF_BABB: + if (ep_num == 1) { + dev_dbg(bdc->dev, "Babble on ep0 zlp_need:%d\n", + bdc->zlp_needed); + /* + * If the last completed transfer had wLength >Data Len, + * and Len is multiple of MaxPacket,then queue ZLP + */ + if (bdc->zlp_needed) { + /* queue 0 length bd */ + ep0_queue_zlp(bdc); + return; + } + } + dev_warn(bdc->dev, "Babble on ep not handled\n"); + break; + default: + dev_warn(bdc->dev, "sr status not handled:%x\n", sr_status); + break; + } +} + +static int bdc_gadget_ep_queue(struct usb_ep *_ep, + struct usb_request *_req, gfp_t gfp_flags) +{ + struct bdc_req *req; + unsigned long flags; + struct bdc_ep *ep; + struct bdc *bdc; + int ret; + + if (!_ep || !_ep->desc) + return -ESHUTDOWN; + + if (!_req || !_req->complete || !_req->buf) + return -EINVAL; + + ep = to_bdc_ep(_ep); + req = to_bdc_req(_req); + bdc = ep->bdc; + dev_dbg(bdc->dev, "%s ep:%p req:%p\n", __func__, ep, req); + dev_dbg(bdc->dev, "queuing request %p to %s length %d zero:%d\n", + _req, ep->name, _req->length, _req->zero); + + if (!ep->usb_ep.desc) { + dev_warn(bdc->dev, + "trying to queue req %p to disabled %s\n", + _req, ep->name); + return -ESHUTDOWN; + } + + if (_req->length > MAX_XFR_LEN) { + dev_warn(bdc->dev, + "req length > supported MAX:%d requested:%d\n", + MAX_XFR_LEN, _req->length); + return -EOPNOTSUPP; + } + spin_lock_irqsave(&bdc->lock, flags); + if (ep == bdc->bdc_ep_array[1]) + ret = ep0_queue(ep, req); + else + ret = ep_queue(ep, req); + + spin_unlock_irqrestore(&bdc->lock, flags); + + return ret; +} + +static int bdc_gadget_ep_dequeue(struct usb_ep *_ep, + struct usb_request *_req) +{ + struct bdc_req *req; + unsigned long flags; + struct bdc_ep *ep; + struct bdc *bdc; + int ret; + + if (!_ep || !_req) + return -EINVAL; + + ep = to_bdc_ep(_ep); + req = to_bdc_req(_req); + bdc = ep->bdc; + dev_dbg(bdc->dev, "%s ep:%s req:%p\n", __func__, ep->name, req); + bdc_dbg_bd_list(bdc, ep); + spin_lock_irqsave(&bdc->lock, flags); + /* make sure it's still queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->usb_req == _req) + break; + } + if (&req->usb_req != _req) { + spin_unlock_irqrestore(&bdc->lock, flags); + dev_err(bdc->dev, "usb_req !=req n"); + return -EINVAL; + } + ret = ep_dequeue(ep, req); + if (ret) { + ret = -EOPNOTSUPP; + goto err; + } + bdc_req_complete(ep, req, -ECONNRESET); + +err: + bdc_dbg_bd_list(bdc, ep); + spin_unlock_irqrestore(&bdc->lock, flags); + + return ret; +} + +static int bdc_gadget_ep_set_halt(struct usb_ep *_ep, int value) +{ + unsigned long flags; + struct bdc_ep *ep; + struct bdc *bdc; + int ret; + + ep = to_bdc_ep(_ep); + bdc = ep->bdc; + dev_dbg(bdc->dev, "%s ep:%s value=%d\n", __func__, ep->name, value); + spin_lock_irqsave(&bdc->lock, flags); + if (usb_endpoint_xfer_isoc(ep->usb_ep.desc)) + ret = -EINVAL; + else if (!list_empty(&ep->queue)) + ret = -EAGAIN; + else + ret = ep_set_halt(ep, value); + + spin_unlock_irqrestore(&bdc->lock, flags); + + return ret; +} + +static struct usb_request *bdc_gadget_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct bdc_req *req; + struct bdc_ep *ep; + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + ep = to_bdc_ep(_ep); + req->ep = ep; + req->epnum = ep->ep_num; + req->usb_req.dma = DMA_ADDR_INVALID; + dev_dbg(ep->bdc->dev, "%s ep:%s req:%p\n", __func__, ep->name, req); + + return &req->usb_req; +} + +static void bdc_gadget_free_request(struct usb_ep *_ep, + struct usb_request *_req) +{ + struct bdc_req *req; + + req = to_bdc_req(_req); + kfree(req); +} + +/* endpoint operations */ + +/* configure endpoint and also allocate resources */ +static int bdc_gadget_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + unsigned long flags; + struct bdc_ep *ep; + struct bdc *bdc; + int ret; + + if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { + pr_debug("bdc_gadget_ep_enable invalid parameters\n"); + return -EINVAL; + } + + if (!desc->wMaxPacketSize) { + pr_debug("bdc_gadget_ep_enable missing wMaxPacketSize\n"); + return -EINVAL; + } + + ep = to_bdc_ep(_ep); + bdc = ep->bdc; + + /* Sanity check, upper layer will not send enable for ep0 */ + if (ep == bdc->bdc_ep_array[1]) + return -EINVAL; + + if (!bdc->gadget_driver + || bdc->gadget.speed == USB_SPEED_UNKNOWN) { + return -ESHUTDOWN; + } + + dev_dbg(bdc->dev, "%s Enabling %s\n", __func__, ep->name); + spin_lock_irqsave(&bdc->lock, flags); + ep->desc = desc; + ep->comp_desc = _ep->comp_desc; + ret = bdc_ep_enable(ep); + spin_unlock_irqrestore(&bdc->lock, flags); + + return ret; +} + +static int bdc_gadget_ep_disable(struct usb_ep *_ep) +{ + unsigned long flags; + struct bdc_ep *ep; + struct bdc *bdc; + int ret; + + if (!_ep) { + pr_debug("bdc: invalid parameters\n"); + return -EINVAL; + } + ep = to_bdc_ep(_ep); + bdc = ep->bdc; + + /* Upper layer will not call this for ep0, but do a sanity check */ + if (ep == bdc->bdc_ep_array[1]) { + dev_warn(bdc->dev, "%s called for ep0\n", __func__); + return -EINVAL; + } + dev_dbg(bdc->dev, + "%s() ep:%s ep->flags:%08x\n", + __func__, ep->name, ep->flags); + + if (!(ep->flags & BDC_EP_ENABLED)) { + dev_warn(bdc->dev, "%s is already disabled\n", ep->name); + return 0; + } + spin_lock_irqsave(&bdc->lock, flags); + ret = bdc_ep_disable(ep); + spin_unlock_irqrestore(&bdc->lock, flags); + + return ret; +} + +static const struct usb_ep_ops bdc_gadget_ep_ops = { + .enable = bdc_gadget_ep_enable, + .disable = bdc_gadget_ep_disable, + .alloc_request = bdc_gadget_alloc_request, + .free_request = bdc_gadget_free_request, + .queue = bdc_gadget_ep_queue, + .dequeue = bdc_gadget_ep_dequeue, + .set_halt = bdc_gadget_ep_set_halt +}; + +/* dir = 1 is IN */ +static int init_ep(struct bdc *bdc, u32 epnum, u32 dir) +{ + struct bdc_ep *ep; + + dev_dbg(bdc->dev, "%s epnum=%d dir=%d\n", __func__, epnum, dir); + ep = kzalloc(sizeof(*ep), GFP_KERNEL); + if (!ep) + return -ENOMEM; + + ep->bdc = bdc; + ep->dir = dir; + + /* ep->ep_num is the index inside bdc_ep */ + if (epnum == 1) { + ep->ep_num = 1; + bdc->bdc_ep_array[ep->ep_num] = ep; + snprintf(ep->name, sizeof(ep->name), "ep%d", epnum - 1); + usb_ep_set_maxpacket_limit(&ep->usb_ep, EP0_MAX_PKT_SIZE); + ep->comp_desc = NULL; + bdc->gadget.ep0 = &ep->usb_ep; + } else { + if (dir) + ep->ep_num = epnum * 2 - 1; + else + ep->ep_num = epnum * 2 - 2; + + bdc->bdc_ep_array[ep->ep_num] = ep; + snprintf(ep->name, sizeof(ep->name), "ep%d%s", epnum - 1, + dir & 1 ? "in" : "out"); + + usb_ep_set_maxpacket_limit(&ep->usb_ep, 1024); + ep->usb_ep.max_streams = 0; + list_add_tail(&ep->usb_ep.ep_list, &bdc->gadget.ep_list); + } + ep->usb_ep.ops = &bdc_gadget_ep_ops; + ep->usb_ep.name = ep->name; + ep->flags = 0; + ep->ignore_next_sr = false; + dev_dbg(bdc->dev, "ep=%p ep->usb_ep.name=%s epnum=%d ep->epnum=%d\n", + ep, ep->usb_ep.name, epnum, ep->ep_num); + + INIT_LIST_HEAD(&ep->queue); + + return 0; +} + +/* Init all ep */ +int bdc_init_ep(struct bdc *bdc) +{ + u8 epnum; + int ret; + + dev_dbg(bdc->dev, "%s()\n", __func__); + INIT_LIST_HEAD(&bdc->gadget.ep_list); + /* init ep0 */ + ret = init_ep(bdc, 1, 0); + if (ret) { + dev_err(bdc->dev, "init ep ep0 fail %d\n", ret); + return ret; + } + + for (epnum = 2; epnum <= bdc->num_eps / 2; epnum++) { + /* OUT */ + ret = init_ep(bdc, epnum, 0); + if (ret) { + dev_err(bdc->dev, + "init ep failed for:%d error: %d\n", + epnum, ret); + return ret; + } + + /* IN */ + ret = init_ep(bdc, epnum, 1); + if (ret) { + dev_err(bdc->dev, + "init ep failed for:%d error: %d\n", + epnum, ret); + return ret; + } + } + + return 0; +} diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.h b/drivers/usb/gadget/udc/bdc/bdc_ep.h new file mode 100644 index 0000000..8a6b36c --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.h @@ -0,0 +1,22 @@ +/* + * bdc_ep.h - header for the BDC debug functions + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * 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 __LINUX_BDC_EP_H__ +#define __LINUX_BDC_EP_H__ + +int bdc_init_ep(struct bdc *); +int bdc_ep_disable(struct bdc_ep *); +int bdc_ep_enable(struct bdc_ep *); +void bdc_free_ep(struct bdc *); + +#endif /* __LINUX_BDC_EP_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_pci.c b/drivers/usb/gadget/udc/bdc/bdc_pci.c new file mode 100644 index 0000000..0296884 --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_pci.c @@ -0,0 +1,132 @@ +/* + * bdc_pci.c - BRCM BDC USB3.0 device controller PCI interface file. + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * Based on drivers under drivers/usb/ + * + * 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 "bdc.h" + +#define BDC_PCI_PID 0x1570 + +struct bdc_pci { + struct device *dev; + struct platform_device *bdc; +}; + +static int bdc_setup_msi(struct pci_dev *pci) +{ + int ret; + + ret = pci_enable_msi(pci); + if (ret) { + pr_err("failed to allocate MSI entry\n"); + return ret; + } + + return ret; +} + +static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) +{ + struct resource res[2]; + struct platform_device *bdc; + struct bdc_pci *glue; + int ret = -ENOMEM; + + glue = devm_kzalloc(&pci->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + glue->dev = &pci->dev; + ret = pci_enable_device(pci); + if (ret) { + dev_err(&pci->dev, "failed to enable pci device\n"); + return -ENODEV; + } + pci_set_master(pci); + + bdc = platform_device_alloc(BRCM_BDC_NAME, PLATFORM_DEVID_AUTO); + if (!bdc) + return -ENOMEM; + + memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); + bdc_setup_msi(pci); + + res[0].start = pci_resource_start(pci, 0); + res[0].end = pci_resource_end(pci, 0); + res[0].name = BRCM_BDC_NAME; + res[0].flags = IORESOURCE_MEM; + + res[1].start = pci->irq; + res[1].name = BRCM_BDC_NAME; + res[1].flags = IORESOURCE_IRQ; + + ret = platform_device_add_resources(bdc, res, ARRAY_SIZE(res)); + if (ret) { + dev_err(&pci->dev, + "couldn't add resources to bdc device\n"); + return ret; + } + + pci_set_drvdata(pci, glue); + + dma_set_coherent_mask(&bdc->dev, pci->dev.coherent_dma_mask); + + bdc->dev.dma_mask = pci->dev.dma_mask; + bdc->dev.dma_parms = pci->dev.dma_parms; + bdc->dev.parent = &pci->dev; + glue->bdc = bdc; + + ret = platform_device_add(bdc); + if (ret) { + dev_err(&pci->dev, "failed to register bdc device\n"); + platform_device_put(bdc); + return ret; + } + + return 0; +} + +static void bdc_pci_remove(struct pci_dev *pci) +{ + struct bdc_pci *glue = pci_get_drvdata(pci); + + platform_device_unregister(glue->bdc); + pci_disable_msi(pci); +} + +static struct pci_device_id bdc_pci_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, BDC_PCI_PID), }, + {} /* Terminating Entry */ +}; + +MODULE_DEVICE_TABLE(pci, bdc_pci_id_table); + +static struct pci_driver bdc_pci_driver = { + .name = "bdc-pci", + .id_table = bdc_pci_id_table, + .probe = bdc_pci_probe, + .remove = bdc_pci_remove, +}; + +MODULE_AUTHOR("Ashwini Pahuja "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("BRCM BDC USB3 PCI Glue layer"); +module_pci_driver(bdc_pci_driver); diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c new file mode 100644 index 0000000..3700ce7 --- /dev/null +++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c @@ -0,0 +1,587 @@ +/* + * bdc_udc.c - BRCM BDC USB3.0 device controller gagdet ops + * + * Copyright (C) 2014 Broadcom Corporation + * + * Author: Ashwini Pahuja + * + * Based on drivers under drivers/usb/gadget/udc/ + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "bdc.h" +#include "bdc_ep.h" +#include "bdc_cmd.h" +#include "bdc_dbg.h" + +static const struct usb_gadget_ops bdc_gadget_ops; + +static const char * const conn_speed_str[] = { + "Not connected", + "Full Speed", + "Low Speed", + "High Speed", + "Super Speed", +}; + +/* EP0 initial descripror */ +static struct usb_endpoint_descriptor bdc_gadget_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .bEndpointAddress = 0, + .wMaxPacketSize = cpu_to_le16(EP0_MAX_PKT_SIZE), +}; + +/* Advance the srr dqp maintained by SW */ +static void srr_dqp_index_advc(struct bdc *bdc, u32 srr_num) +{ + struct srr *srr; + + srr = &bdc->srr; + dev_dbg_ratelimited(bdc->dev, "srr->dqp_index:%d\n", srr->dqp_index); + srr->dqp_index++; + /* rollback to 0 if we are past the last */ + if (srr->dqp_index == NUM_SR_ENTRIES) + srr->dqp_index = 0; +} + +/* connect sr */ +static void bdc_uspc_connected(struct bdc *bdc) +{ + u32 speed, temp; + u32 usppms; + int ret; + + temp = bdc_readl(bdc->regs, BDC_USPC); + speed = BDC_PSP(temp); + dev_dbg(bdc->dev, "%s speed=%x\n", __func__, speed); + switch (speed) { + case BDC_SPEED_SS: + bdc_gadget_ep0_desc.wMaxPacketSize = + cpu_to_le16(EP0_MAX_PKT_SIZE); + bdc->gadget.ep0->maxpacket = EP0_MAX_PKT_SIZE; + bdc->gadget.speed = USB_SPEED_SUPER; + /* Enable U1T in SS mode */ + usppms = bdc_readl(bdc->regs, BDC_USPPMS); + usppms &= ~BDC_U1T(0xff); + usppms |= BDC_U1T(U1_TIMEOUT); + usppms |= BDC_PORT_W1S; + bdc_writel(bdc->regs, BDC_USPPMS, usppms); + break; + + case BDC_SPEED_HS: + bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); + bdc->gadget.ep0->maxpacket = 64; + bdc->gadget.speed = USB_SPEED_HIGH; + break; + + case BDC_SPEED_FS: + bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); + bdc->gadget.ep0->maxpacket = 64; + bdc->gadget.speed = USB_SPEED_FULL; + break; + + case BDC_SPEED_LS: + bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8); + bdc->gadget.ep0->maxpacket = 8; + bdc->gadget.speed = USB_SPEED_LOW; + break; + default: + dev_err(bdc->dev, "UNDEFINED SPEED\n"); + return; + } + dev_dbg(bdc->dev, "connected at %s\n", conn_speed_str[speed]); + /* Now we know the speed, configure ep0 */ + bdc->bdc_ep_array[1]->desc = &bdc_gadget_ep0_desc; + ret = bdc_config_ep(bdc, bdc->bdc_ep_array[1]); + if (ret) + dev_err(bdc->dev, "EP0 config failed\n"); + bdc->bdc_ep_array[1]->usb_ep.desc = &bdc_gadget_ep0_desc; + bdc->bdc_ep_array[1]->flags |= BDC_EP_ENABLED; + usb_gadget_set_state(&bdc->gadget, USB_STATE_DEFAULT); +} + +/* device got disconnected */ +static void bdc_uspc_disconnected(struct bdc *bdc, bool reinit) +{ + struct bdc_ep *ep; + + dev_dbg(bdc->dev, "%s\n", __func__); + /* + * Only stop ep0 from here, rest of the endpoints will be disabled + * from gadget_disconnect + */ + ep = bdc->bdc_ep_array[1]; + if (ep && (ep->flags & BDC_EP_ENABLED)) + /* if enabled then stop and remove requests */ + bdc_ep_disable(ep); + + if (bdc->gadget_driver && bdc->gadget_driver->disconnect) { + spin_unlock(&bdc->lock); + bdc->gadget_driver->disconnect(&bdc->gadget); + spin_lock(&bdc->lock); + } + /* Set Unknown speed */ + bdc->gadget.speed = USB_SPEED_UNKNOWN; + bdc->devstatus &= DEVSTATUS_CLEAR; + bdc->delayed_status = false; + bdc->reinit = reinit; + bdc->test_mode = false; +} + +/* TNotify wkaeup timer */ +static void bdc_func_wake_timer(struct work_struct *work) +{ + struct bdc *bdc = container_of(work, struct bdc, func_wake_notify.work); + unsigned long flags; + + dev_dbg(bdc->dev, "%s\n", __func__); + spin_lock_irqsave(&bdc->lock, flags); + /* + * Check if host has started transferring on endpoints + * FUNC_WAKE_ISSUED is cleared when transfer has started after resume + */ + if (bdc->devstatus & FUNC_WAKE_ISSUED) { + dev_dbg(bdc->dev, "FUNC_WAKE_ISSUED FLAG IS STILL SET\n"); + /* flag is still set, so again send func wake */ + bdc_function_wake_fh(bdc, 0); + schedule_delayed_work(&bdc->func_wake_notify, + msecs_to_jiffies(BDC_TNOTIFY)); + } + spin_unlock_irqrestore(&bdc->lock, flags); +} + +/* handler for Link state change condition */ +static void handle_link_state_change(struct bdc *bdc, u32 uspc) +{ + u32 link_state; + + dev_dbg(bdc->dev, "Link state change"); + link_state = BDC_PST(uspc); + switch (link_state) { + case BDC_LINK_STATE_U3: + if ((bdc->gadget.speed != USB_SPEED_UNKNOWN) && + bdc->gadget_driver->suspend) { + dev_dbg(bdc->dev, "Entered Suspend mode\n"); + spin_unlock(&bdc->lock); + bdc->devstatus |= DEVICE_SUSPENDED; + bdc->gadget_driver->suspend(&bdc->gadget); + spin_lock(&bdc->lock); + } + break; + case BDC_LINK_STATE_U0: + if (bdc->devstatus & REMOTE_WAKEUP_ISSUED) { + bdc->devstatus &= ~REMOTE_WAKEUP_ISSUED; + if (bdc->gadget.speed == USB_SPEED_SUPER) { + bdc_function_wake_fh(bdc, 0); + bdc->devstatus |= FUNC_WAKE_ISSUED; + /* + * Start a Notification timer and check if the + * Host transferred anything on any of the EPs, + * if not then send function wake again every + * TNotification secs until host initiates + * transfer to BDC, USB3 spec Table 8.13 + */ + schedule_delayed_work( + &bdc->func_wake_notify, + msecs_to_jiffies(BDC_TNOTIFY)); + dev_dbg(bdc->dev, "sched func_wake_notify\n"); + } + } + break; + + case BDC_LINK_STATE_RESUME: + dev_dbg(bdc->dev, "Resumed from Suspend\n"); + if (bdc->devstatus & DEVICE_SUSPENDED) { + bdc->gadget_driver->resume(&bdc->gadget); + bdc->devstatus &= ~DEVICE_SUSPENDED; + } + break; + default: + dev_dbg(bdc->dev, "link state:%d\n", link_state); + } +} + +/* something changes on upstream port, handle it here */ +void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport) +{ + u32 clear_flags = 0; + u32 uspc; + bool connected = false; + bool disconn = false; + + uspc = bdc_readl(bdc->regs, BDC_USPC); + dev_dbg(bdc->dev, "%s uspc=0x%08x\n", __func__, uspc); + + /* Port connect changed */ + if (uspc & BDC_PCC) { + /* Vbus not present, and not connected to Downstream port */ + if ((uspc & BDC_VBC) && !(uspc & BDC_VBS) && !(uspc & BDC_PCS)) + disconn = true; + else if ((uspc & BDC_PCS) && !BDC_PST(uspc)) + connected = true; + } + + /* Change in VBus and VBus is present */ + if ((uspc & BDC_VBC) && (uspc & BDC_VBS)) { + if (bdc->pullup) { + dev_dbg(bdc->dev, "Do a softconnect\n"); + /* Attached state, do a softconnect */ + bdc_softconn(bdc); + usb_gadget_set_state(&bdc->gadget, USB_STATE_POWERED); + } + clear_flags = BDC_VBC; + } else if ((uspc & BDC_PRS) || (uspc & BDC_PRC) || disconn) { + /* Hot reset, warm reset, 2.0 bus reset or disconn */ + dev_dbg(bdc->dev, "Port reset or disconn\n"); + bdc_uspc_disconnected(bdc, disconn); + clear_flags = BDC_PCC|BDC_PCS|BDC_PRS|BDC_PRC; + } else if ((uspc & BDC_PSC) && (uspc & BDC_PCS)) { + /* Change in Link state */ + handle_link_state_change(bdc, uspc); + clear_flags = BDC_PSC|BDC_PCS; + } + + /* + * In SS we might not have PRC bit set before connection, but in 2.0 + * the PRC bit is set before connection, so moving this condition out + * of bus reset to handle both SS/2.0 speeds. + */ + if (connected) { + /* This is the connect event for U0/L0 */ + dev_dbg(bdc->dev, "Connected\n"); + bdc_uspc_connected(bdc); + bdc->devstatus &= ~(DEVICE_SUSPENDED); + } + uspc = bdc_readl(bdc->regs, BDC_USPC); + uspc &= (~BDC_USPSC_RW); + dev_dbg(bdc->dev, "uspc=%x\n", uspc); + bdc_writel(bdc->regs, BDC_USPC, clear_flags); +} + +/* Main interrupt handler for bdc */ +static irqreturn_t bdc_udc_interrupt(int irq, void *_bdc) +{ + u32 eqp_index, dqp_index, sr_type, srr_int; + struct bdc_sr *sreport; + struct bdc *bdc = _bdc; + u32 status; + int ret; + + spin_lock(&bdc->lock); + status = bdc_readl(bdc->regs, BDC_BDCSC); + if (!(status & BDC_GIP)) { + spin_unlock(&bdc->lock); + return IRQ_NONE; + } + srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0)); + /* Check if the SRR IP bit it set? */ + if (!(srr_int & BDC_SRR_IP)) { + dev_warn(bdc->dev, "Global irq pending but SRR IP is 0\n"); + spin_unlock(&bdc->lock); + return IRQ_NONE; + } + eqp_index = BDC_SRR_EPI(srr_int); + dqp_index = BDC_SRR_DPI(srr_int); + dev_dbg(bdc->dev, + "%s eqp_index=%d dqp_index=%d srr.dqp_index=%d\n\n", + __func__, eqp_index, dqp_index, bdc->srr.dqp_index); + + /* check for ring empty condition */ + if (eqp_index == dqp_index) { + dev_dbg(bdc->dev, "SRR empty?\n"); + spin_unlock(&bdc->lock); + return IRQ_HANDLED; + } + + while (bdc->srr.dqp_index != eqp_index) { + sreport = &bdc->srr.sr_bds[bdc->srr.dqp_index]; + /* sreport is read before using it */ + rmb(); + sr_type = le32_to_cpu(sreport->offset[3]) & BD_TYPE_BITMASK; + dev_dbg_ratelimited(bdc->dev, "sr_type=%d\n", sr_type); + switch (sr_type) { + case SR_XSF: + bdc->sr_handler[0](bdc, sreport); + break; + + case SR_USPC: + bdc->sr_handler[1](bdc, sreport); + break; + default: + dev_warn(bdc->dev, "SR:%d not handled\n", sr_type); + } + /* Advance the srr dqp index */ + srr_dqp_index_advc(bdc, 0); + } + /* update the hw dequeue pointer */ + srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0)); + srr_int &= ~BDC_SRR_DPI_MASK; + srr_int &= ~(BDC_SRR_RWS|BDC_SRR_RST|BDC_SRR_ISR); + srr_int |= ((bdc->srr.dqp_index) << 16); + srr_int |= BDC_SRR_IP; + bdc_writel(bdc->regs, BDC_SRRINT(0), srr_int); + srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0)); + if (bdc->reinit) { + ret = bdc_reinit(bdc); + if (ret) + dev_err(bdc->dev, "err in bdc reinit\n"); + } + + spin_unlock(&bdc->lock); + + return IRQ_HANDLED; +} + +/* Gadget ops */ +static int bdc_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct bdc *bdc = gadget_to_bdc(gadget); + unsigned long flags; + int ret = 0; + + dev_dbg(bdc->dev, "%s()\n", __func__); + spin_lock_irqsave(&bdc->lock, flags); + if (bdc->gadget_driver) { + dev_err(bdc->dev, "%s is already bound to %s\n", + bdc->gadget.name, + bdc->gadget_driver->driver.name); + ret = -EBUSY; + goto err; + } + /* + * Run the controller from here and when BDC is connected to + * Host then driver will receive a USPC SR with VBUS present + * and then driver will do a softconnect. + */ + ret = bdc_run(bdc); + if (ret) { + dev_err(bdc->dev, "%s bdc run fail\n", __func__); + goto err; + } + bdc->gadget_driver = driver; + bdc->gadget.dev.driver = &driver->driver; +err: + spin_unlock_irqrestore(&bdc->lock, flags); + + return ret; +} + +static int bdc_udc_stop(struct usb_gadget *gadget) +{ + struct bdc *bdc = gadget_to_bdc(gadget); + unsigned long flags; + + dev_dbg(bdc->dev, "%s()\n", __func__); + spin_lock_irqsave(&bdc->lock, flags); + bdc_stop(bdc); + bdc->gadget_driver = NULL; + bdc->gadget.dev.driver = NULL; + spin_unlock_irqrestore(&bdc->lock, flags); + + return 0; +} + +static int bdc_udc_pullup(struct usb_gadget *gadget, int is_on) +{ + struct bdc *bdc = gadget_to_bdc(gadget); + unsigned long flags; + u32 uspc; + + dev_dbg(bdc->dev, "%s() is_on:%d\n", __func__, is_on); + if (!gadget) + return -EINVAL; + + spin_lock_irqsave(&bdc->lock, flags); + if (!is_on) { + bdc_softdisconn(bdc); + bdc->pullup = false; + } else { + /* + * For a self powered device, we need to wait till we receive + * a VBUS change and Vbus present event, then if pullup flag + * is set, then only we present the Termintation. + */ + bdc->pullup = true; + /* + * Check if BDC is already connected to Host i.e Vbus=1, + * if yes, then present TERM now, this is typical for bus + * powered devices. + */ + uspc = bdc_readl(bdc->regs, BDC_USPC); + if (uspc & BDC_VBS) + bdc_softconn(bdc); + } + spin_unlock_irqrestore(&bdc->lock, flags); + + return 0; +} + +static int bdc_udc_set_selfpowered(struct usb_gadget *gadget, + int is_self) +{ + struct bdc *bdc = gadget_to_bdc(gadget); + unsigned long flags; + + dev_dbg(bdc->dev, "%s()\n", __func__); + spin_lock_irqsave(&bdc->lock, flags); + if (!is_self) + bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; + else + bdc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + + spin_unlock_irqrestore(&bdc->lock, flags); + + return 0; +} + +static int bdc_udc_wakeup(struct usb_gadget *gadget) +{ + struct bdc *bdc = gadget_to_bdc(gadget); + unsigned long flags; + u8 link_state; + u32 uspc; + int ret = 0; + + dev_dbg(bdc->dev, + "%s() bdc->devstatus=%08x\n", + __func__, bdc->devstatus); + + if (!(bdc->devstatus & REMOTE_WAKE_ENABLE)) + return -EOPNOTSUPP; + + spin_lock_irqsave(&bdc->lock, flags); + uspc = bdc_readl(bdc->regs, BDC_USPC); + link_state = BDC_PST(uspc); + dev_dbg(bdc->dev, "link_state =%d portsc=%x", link_state, uspc); + if (link_state != BDC_LINK_STATE_U3) { + dev_warn(bdc->dev, + "can't wakeup from link state %d\n", + link_state); + ret = -EINVAL; + goto out; + } + if (bdc->gadget.speed == USB_SPEED_SUPER) + bdc->devstatus |= REMOTE_WAKEUP_ISSUED; + + uspc &= ~BDC_PST_MASK; + uspc &= (~BDC_USPSC_RW); + uspc |= BDC_PST(BDC_LINK_STATE_U0); + uspc |= BDC_SWS; + bdc_writel(bdc->regs, BDC_USPC, uspc); + uspc = bdc_readl(bdc->regs, BDC_USPC); + link_state = BDC_PST(uspc); + dev_dbg(bdc->dev, "link_state =%d portsc=%x", link_state, uspc); +out: + spin_unlock_irqrestore(&bdc->lock, flags); + + return ret; +} + +static const struct usb_gadget_ops bdc_gadget_ops = { + .wakeup = bdc_udc_wakeup, + .set_selfpowered = bdc_udc_set_selfpowered, + .pullup = bdc_udc_pullup, + .udc_start = bdc_udc_start, + .udc_stop = bdc_udc_stop, +}; + +/* Init the gadget interface and register the udc */ +int bdc_udc_init(struct bdc *bdc) +{ + u32 temp; + int ret; + + dev_dbg(bdc->dev, "%s()\n", __func__); + bdc->gadget.ops = &bdc_gadget_ops; + bdc->gadget.max_speed = USB_SPEED_SUPER; + bdc->gadget.speed = USB_SPEED_UNKNOWN; + bdc->gadget.dev.parent = bdc->dev; + + bdc->gadget.sg_supported = false; + + + bdc->gadget.name = BRCM_BDC_NAME; + ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt, + IRQF_SHARED , BRCM_BDC_NAME, bdc); + if (ret) { + dev_err(bdc->dev, + "failed to request irq #%d %d\n", + bdc->irq, ret); + return ret; + } + + ret = bdc_init_ep(bdc); + if (ret) { + dev_err(bdc->dev, "bdc init ep fail: %d\n", ret); + return ret; + } + + ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget); + if (ret) { + dev_err(bdc->dev, "failed to register udc\n"); + goto err0; + } + usb_gadget_set_state(&bdc->gadget, USB_STATE_NOTATTACHED); + bdc->bdc_ep_array[1]->desc = &bdc_gadget_ep0_desc; + /* + * Allocate bd list for ep0 only, ep0 will be enabled on connect + * status report when the speed is known + */ + ret = bdc_ep_enable(bdc->bdc_ep_array[1]); + if (ret) { + dev_err(bdc->dev, "fail to enable %s\n", + bdc->bdc_ep_array[1]->name); + goto err1; + } + INIT_DELAYED_WORK(&bdc->func_wake_notify, bdc_func_wake_timer); + /* Enable Interrupts */ + temp = bdc_readl(bdc->regs, BDC_BDCSC); + temp |= BDC_GIE; + bdc_writel(bdc->regs, BDC_BDCSC, temp); + return 0; +err1: + usb_del_gadget_udc(&bdc->gadget); +err0: + bdc_free_ep(bdc); + + return ret; +} + +void bdc_udc_exit(struct bdc *bdc) +{ + dev_dbg(bdc->dev, "%s()\n", __func__); + bdc_ep_disable(bdc->bdc_ep_array[1]); + usb_del_gadget_udc(&bdc->gadget); + bdc_free_ep(bdc); +} -- cgit v0.10.2 From 828f6148e89ec051c2540400773655c0174ccaa3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Nov 2014 09:19:47 +0300 Subject: usb: gadget: f_hid: use after free in hidg_alloc_inst() We free "opts" on the error path and then dereference it. Fixes: 21a9476a7ba8 ('usb: gadget: hid: add configfs support') Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 7d18f41..f0545f8 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -875,6 +875,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) kfree(opts); if (idr_is_empty(&hidg_ida.idr)) ghid_cleanup(); + goto unlock; } config_group_init_type_name(&opts->func_inst.group, "", &hid_func_type); -- cgit v0.10.2 From 0448d38c1e8cd64fb2fa88f44cbc7c3dcf75ed6c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Nov 2014 09:20:59 +0300 Subject: usb: gadget: f_hid: fix error handling in ghid_setup() There were a two issues here. 1) We returned PTR_ERR(NULL) which means success if class_create() failed. 2) If alloc_chrdev_region() failed then we should clean up before returning. Also kernel style is to have "error handling" as opposed to "success handling". In the original code checking for "if (!status) " is confusing and this bad style is what lead to bug #2. Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index f0545f8..488ac66 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -972,17 +972,22 @@ int ghid_setup(struct usb_gadget *g, int count) hidg_class = class_create(THIS_MODULE, "hidg"); if (IS_ERR(hidg_class)) { + status = PTR_ERR(hidg_class); hidg_class = NULL; - return PTR_ERR(hidg_class); + return status; } status = alloc_chrdev_region(&dev, 0, count, "hidg"); - if (!status) { - major = MAJOR(dev); - minors = count; + if (status) { + class_destroy(hidg_class); + hidg_class = NULL; + return status; } - return status; + major = MAJOR(dev); + minors = count; + + return 0; } void ghid_cleanup(void) -- cgit v0.10.2 From a1fc1920aaaaeadc7cf9d80fc16e6b8eca722b44 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 13 Nov 2014 18:33:08 +0100 Subject: usb: musb: core: make sure musb is in RPM_ACTIVE on resume On am335x-evm with musb in host mode and using it as a wakeup source the following happens once the CPU comes out of suspend to ram: |PM: Wakeup source MPU_WAKE |PM: noirq resume of devices complete after 15.453 msecs |PM: early resume of devices complete after 2.222 msecs |PM: resume of devices complete after 507.351 msecs |Restarting tasks ... |------------[ cut here ]------------ |WARNING: CPU: 0 PID: 322 at drivers/usb/core/urb.c:339 usb_submit_urb+0x494/0x4c8() |URB cc0db380 submitted while active |[] (usb_submit_urb) from [] (hub_activate+0x2b8/0x49c) |[] (hub_activate) from [] (hub_resume+0x14/0x1c) |[] (hub_resume) from [] (usb_resume_interface.isra.4+0xdc/0x110) |[] (usb_resume_interface.isra.4) from [] (usb_resume_both+0x6c/0x13c) |[] (usb_resume_both) from [] (usb_runtime_resume+0x10/0x14) |[] (usb_runtime_resume) from [] (__rpm_callback+0x2c/0x60) |[] (__rpm_callback) from [] (rpm_callback+0x20/0x74) |[] (rpm_callback) from [] (rpm_resume+0x380/0x548) |[] (rpm_resume) from [] (rpm_resume+0x238/0x548) |[] (rpm_resume) from [] (__pm_runtime_resume+0x64/0x94) |[] (__pm_runtime_resume) from [] (usb_autopm_get_interface+0x18/0x5c) |[] (usb_autopm_get_interface) from [] (hub_thread+0x10c/0x115c) |[] (hub_thread) from [] (kthread+0xbc/0xd8) |---[ end trace 036aa5fe78203142 ]--- |hub 1-0:1.0: activate --> -16 |hub 2-0:1.0: activate --> -16 The reason for this backtrace is the attempt of the USB code to resume the HUB twice and thus enqueue the status URB twice. Alan Stern was a great help by explaining how the USB code supposed to work and what is most likely the problem. The root problem is that after resume the musb runtime-suspend state remains RPM_SUSPENDED. According to git log it RPM was added for the omap2430 platform. If I understand it correct the omap2430 invokes a get on musb once a cable is connected and a put once the cable is gone. In between the device could go auto-idle/off. Not sure what happens when the device goes into suspend but then I guess it was gadget only. On DSPS I see only a get in probe and put in remove function. This would forbid RPM from working but then the devices enterns suspended state anyway :) To get rid of this warning, I set the device state to RPM_ACTIVE which the expected state. Cc: Alan Stern Cc: Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 3345c94..f1dfe53 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2321,6 +2321,14 @@ static int musb_resume(struct device *dev) schedule_delayed_work(&musb->finish_resume_work, msecs_to_jiffies(20)); } + + /* + * The USB HUB code expects the device to be in RPM_ACTIVE once it came + * out of suspend + */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); return 0; } -- cgit v0.10.2 From c2365ce5d5a0531f24ee488bf846acda4ecbe2aa Mon Sep 17 00:00:00 2001 From: Roman Byshko Date: Mon, 10 Nov 2014 21:53:32 +0100 Subject: usb: musb: replace hard coded registers with defines musb registers can be dumped using the file regdump which is created in debugfs. Up to now hard coded register addresses are used for that. Different glue layers however have different register addresses. The patch addresses this issue by substituting bare register addresses with defines. Signed-off-by: Roman Byshko Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 4c21679..ad3701a 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -49,33 +49,36 @@ struct musb_register_map { }; static const struct musb_register_map musb_regmap[] = { - { "FAddr", 0x00, 8 }, - { "Power", 0x01, 8 }, - { "Frame", 0x0c, 16 }, - { "Index", 0x0e, 8 }, - { "Testmode", 0x0f, 8 }, - { "TxMaxPp", 0x10, 16 }, - { "TxCSRp", 0x12, 16 }, - { "RxMaxPp", 0x14, 16 }, - { "RxCSR", 0x16, 16 }, - { "RxCount", 0x18, 16 }, - { "ConfigData", 0x1f, 8 }, - { "DevCtl", 0x60, 8 }, - { "MISC", 0x61, 8 }, - { "TxFIFOsz", 0x62, 8 }, - { "RxFIFOsz", 0x63, 8 }, - { "TxFIFOadd", 0x64, 16 }, - { "RxFIFOadd", 0x66, 16 }, - { "VControl", 0x68, 32 }, - { "HWVers", 0x6C, 16 }, - { "EPInfo", 0x78, 8 }, - { "RAMInfo", 0x79, 8 }, - { "LinkInfo", 0x7A, 8 }, - { "VPLen", 0x7B, 8 }, - { "HS_EOF1", 0x7C, 8 }, - { "FS_EOF1", 0x7D, 8 }, - { "LS_EOF1", 0x7E, 8 }, - { "SOFT_RST", 0x7F, 8 }, + { "FAddr", MUSB_FADDR, 8 }, + { "Power", MUSB_POWER, 8 }, + { "Frame", MUSB_FRAME, 16 }, + { "Index", MUSB_INDEX, 8 }, + { "Testmode", MUSB_TESTMODE, 8 }, + { "TxMaxPp", MUSB_TXMAXP, 16 }, + { "TxCSRp", MUSB_TXCSR, 16 }, + { "RxMaxPp", MUSB_RXMAXP, 16 }, + { "RxCSR", MUSB_RXCSR, 16 }, + { "RxCount", MUSB_RXCOUNT, 16 }, + { "ConfigData", MUSB_CONFIGDATA,8 }, + { "IntrRxE", MUSB_INTRRXE, 16 }, + { "IntrTxE", MUSB_INTRTXE, 16 }, + { "IntrUsbE", MUSB_INTRUSBE, 8 }, + { "DevCtl", MUSB_DEVCTL, 8 }, + { "BabbleCtl", MUSB_BABBLE_CTL,8 }, + { "TxFIFOsz", MUSB_TXFIFOSZ, 8 }, + { "RxFIFOsz", MUSB_RXFIFOSZ, 8 }, + { "TxFIFOadd", MUSB_TXFIFOADD, 16 }, + { "RxFIFOadd", MUSB_RXFIFOADD, 16 }, + { "VControl", 0x68, 32 }, + { "HWVers", 0x69, 16 }, + { "EPInfo", MUSB_EPINFO, 8 }, + { "RAMInfo", MUSB_RAMINFO, 8 }, + { "LinkInfo", MUSB_LINKINFO, 8 }, + { "VPLen", MUSB_VPLEN, 8 }, + { "HS_EOF1", MUSB_HS_EOF1, 8 }, + { "FS_EOF1", MUSB_FS_EOF1, 8 }, + { "LS_EOF1", MUSB_LS_EOF1, 8 }, + { "SOFT_RST", 0x7F, 8 }, { "DMA_CNTLch0", 0x204, 16 }, { "DMA_ADDRch0", 0x208, 32 }, { "DMA_COUNTch0", 0x20C, 32 }, -- cgit v0.10.2 From 1eec34e9f25664cf71e05321329d128e0565beae Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 13 Nov 2014 18:28:47 +0100 Subject: usb: musb: musb_cppi41: recognize HS devices in hostmode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a poll loop for max 25us for HS devices. Now guess what, I tested it in gadget mode and forgot about the little detail. Nobody seem to have it noticed… This patch adds the missing logic for hostmode so it is recognized in host and device mode properly. Fixes: 50aea6fca771 ("usb: musb: cppi41: fire hrtimer according to programmed channel length") Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 5a9b977..f64fd96 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -253,6 +253,7 @@ static void cppi41_dma_callback(void *private_data) cppi41_trans_done(cppi41_channel); } else { struct cppi41_dma_controller *controller; + int is_hs = 0; /* * On AM335x it has been observed that the TX interrupt fires * too early that means the TXFIFO is not yet empty but the DMA @@ -265,7 +266,14 @@ static void cppi41_dma_callback(void *private_data) */ controller = cppi41_channel->controller; - if (musb->g.speed == USB_SPEED_HIGH) { + if (is_host_active(musb)) { + if (musb->port1_status & USB_PORT_STAT_HIGH_SPEED) + is_hs = 1; + } else { + if (musb->g.speed == USB_SPEED_HIGH) + is_hs = 1; + } + if (is_hs) { unsigned wait = 25; do { -- cgit v0.10.2 From f905bc68833b37b2274dc269fd35edb19e67aed7 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Fri, 14 Nov 2014 13:54:46 +0530 Subject: usb: musb: core: Disable the Interrupts till BABBLE is fully handled Disable the MUSB interrupts till MUSB is recovered fully from BABBLE condition. There are chances that we could get multiple interrupts till the time the babble recover work gets scheduled. Sometimes this could even end up in an endless loop making MUSB itself unusable. Reported-by: Felipe Balbi Signed-off-by: George Cherian Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f1dfe53..5257928 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -423,6 +423,7 @@ void musb_hnp_stop(struct musb *musb) musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16); } +static void musb_generic_disable(struct musb *musb); /* * Interrupt Service Routine to record USB "global" interrupts. * Since these do not happen often and signify things of @@ -846,9 +847,11 @@ b_host: } /* handle babble condition */ - if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) + if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) { + musb_generic_disable(musb); schedule_delayed_work(&musb->recover_work, msecs_to_jiffies(100)); + } #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or -- cgit v0.10.2 From e7181d005e84b15fe3121a8d22840adc3395d496 Mon Sep 17 00:00:00 2001 From: Martin Hauke Date: Sun, 16 Nov 2014 21:17:30 +0100 Subject: USB: qcserial: Add support for HP lt4112 LTE/HSPA+ Gobi 4G Modem Added new device layout "DEVICE_HWI" and also added the USB VID/PID for the HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) Signed-off-by: Martin Hauke Cc: stable Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index b2aa003..cb3e147 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -27,12 +27,15 @@ enum qcserial_layouts { QCSERIAL_G2K = 0, /* Gobi 2000 */ QCSERIAL_G1K = 1, /* Gobi 1000 */ QCSERIAL_SWI = 2, /* Sierra Wireless */ + QCSERIAL_HWI = 3, /* Huawei */ }; #define DEVICE_G1K(v, p) \ USB_DEVICE(v, p), .driver_info = QCSERIAL_G1K #define DEVICE_SWI(v, p) \ USB_DEVICE(v, p), .driver_info = QCSERIAL_SWI +#define DEVICE_HWI(v, p) \ + USB_DEVICE(v, p), .driver_info = QCSERIAL_HWI static const struct usb_device_id id_table[] = { /* Gobi 1000 devices */ @@ -157,6 +160,9 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + /* Huawei devices */ + {DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */ + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); @@ -287,6 +293,33 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) break; } break; + case QCSERIAL_HWI: + /* + * Huawei layout: + * 0: AT-capable modem port + * 1: DM/DIAG + * 2: AT-capable modem port + * 3: CCID-compatible PCSC interface + * 4: QMI/net + * 5: NMEA + */ + switch (ifnum) { + case 0: + case 2: + dev_dbg(dev, "Modem port found\n"); + break; + case 1: + dev_dbg(dev, "DM/DIAG interface found\n"); + break; + case 5: + dev_dbg(dev, "NMEA GPS interface found\n"); + break; + default: + /* don't claim any unsupported interface */ + altsetting = -1; + break; + } + break; default: dev_err(dev, "unsupported device layout type: %lu\n", id->driver_info); -- cgit v0.10.2 From a4722fd3f2d3590af5200890b61dbbdf87480abb Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 20 Nov 2014 10:12:32 -0600 Subject: usb: dwc3: trace: don't save pointers There was another instance where we were holding pointers which could be long gone. Fix that by caching only values pointed to by such pointer. Because no crash has been observed, this patch will be sent on v3.19 merge window, instead of -rc. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 7a9d780..9fc20b3 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -175,17 +175,21 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd, TP_STRUCT__entry( __dynamic_array(char, name, DWC3_MSG_MAX) __field(unsigned int, cmd) - __field(struct dwc3_gadget_ep_cmd_params *, params) + __field(u32, param0) + __field(u32, param1) + __field(u32, param2) ), TP_fast_assign( snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name); __entry->cmd = cmd; - __entry->params = params; + __entry->param0 = params->param0; + __entry->param1 = params->param1; + __entry->param2 = params->param2; ), TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x", __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd), - __entry->cmd, __entry->params->param0, - __entry->params->param1, __entry->params->param2 + __entry->cmd, __entry->param0, + __entry->param1, __entry->param2 ) ); -- cgit v0.10.2 From 62c606978aa028260f88d0dcb9834bbb7a42b048 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 20 Nov 2014 18:33:58 +0100 Subject: usb: dwc3: keystone: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index dd8d2df..fe3b933 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -123,6 +123,7 @@ static int kdwc3_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "missing irq\n"); + error = irq; goto err_irq; } -- cgit v0.10.2 From 1290a958d48e30d60262a33acb5f068e87834ce4 Mon Sep 17 00:00:00 2001 From: Arjun Sreedharan Date: Thu, 20 Nov 2014 21:23:36 +0530 Subject: usb: phy: propagate __of_usb_find_phy()'s error on failure When __of_usb_find_phy() fails, it returns -ENODEV - its error code has to be returned by devm_usb_get_phy_by_phandle(). Only when the former function succeeds and try_module_get() fails should -EPROBE_DEFER be returned. [ balbi@ti.com : remove trailing whitespace ] Signed-off-by: Arjun Sreedharan Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 045cd30..e6bf801 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -191,7 +191,9 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, phy = __of_usb_find_phy(node); if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { - phy = ERR_PTR(-EPROBE_DEFER); + if (!IS_ERR(phy)) + phy = ERR_PTR(-EPROBE_DEFER); + devres_free(ptr); goto err1; } -- cgit v0.10.2 From 74df41b40ab0222903dcc9681e9076c2604741d8 Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Tue, 18 Nov 2014 15:11:54 -0500 Subject: usb: gadget: add USB3 support to the printer driver Add SS descriptors to support the capabilities provided by USB3 controller drivers; unit tests run using a PLX 3380 [max transfer speed measured of 1Gbps] This driver shall fallback to lower operating modes when the higher ones are not available. Signed-off-by: Jorge Ramirez-Ortiz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 6474081..e0cf1b0 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -208,6 +208,43 @@ static struct usb_descriptor_header *hs_printer_function[] = { NULL }; +/* + * Added endpoint descriptors for 3.0 devices + */ + +static struct usb_endpoint_descriptor ss_ep_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = { + .bLength = sizeof(ss_ep_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_endpoint_descriptor ss_ep_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = { + .bLength = sizeof(ss_ep_out_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *ss_printer_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &ss_ep_in_desc, + (struct usb_descriptor_header *) &ss_ep_in_comp_desc, + (struct usb_descriptor_header *) &ss_ep_out_desc, + (struct usb_descriptor_header *) &ss_ep_out_comp_desc, + NULL +}; + static struct usb_otg_descriptor otg_descriptor = { .bLength = sizeof otg_descriptor, .bDescriptorType = USB_DT_OTG, @@ -220,7 +257,20 @@ static const struct usb_descriptor_header *otg_desc[] = { }; /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) +static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *ss) +{ + switch (gadget->speed) { + case USB_SPEED_SUPER: + return ss; + case USB_SPEED_HIGH: + return hs; + default: + return fs; + } +} /*-------------------------------------------------------------------------*/ @@ -793,11 +843,12 @@ set_printer_interface(struct printer_dev *dev) { int result = 0; - dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); + dev->in_ep->desc = ep_desc(dev->gadget, &fs_ep_in_desc, &hs_ep_in_desc, + &ss_ep_in_desc); dev->in_ep->driver_data = dev; - dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc, - &fs_ep_out_desc); + dev->out_ep->desc = ep_desc(dev->gadget, &fs_ep_out_desc, + &hs_ep_out_desc, &ss_ep_out_desc); dev->out_ep->driver_data = dev; result = usb_ep_enable(dev->in_ep); @@ -1016,9 +1067,11 @@ autoconf_fail: /* assumes that all endpoints are dual-speed */ hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; + ss_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; + ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; ret = usb_assign_descriptors(f, fs_printer_function, - hs_printer_function, NULL); + hs_printer_function, ss_printer_function); if (ret) return ret; @@ -1253,7 +1306,7 @@ static __refdata struct usb_composite_driver printer_driver = { .name = shortname, .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .bind = printer_bind, .unbind = printer_unbind, }; -- cgit v0.10.2 From ba7cc772e77d30943833b7d38a861203dcb8c881 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 19 Nov 2014 17:19:05 +0800 Subject: usb: gadget: at91_udc: remove unused release function As the driver call usb_add_gadget_udc --> usb_add_gadget_udc_release with NULL as release parameter, so it will use usb_udc_no_release. So, the release in driver won't used, remove it. And at the same time, in the usb_add_gadget_udc_release will set the gadget name, so remove it also in driver. Signed-off-by: Bo Shen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 753e93b..fe0534c 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1537,20 +1537,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) /*-------------------------------------------------------------------------*/ -static void nop_release(struct device *dev) -{ - /* nothing to free */ -} - static struct at91_udc controller = { .gadget = { .ops = &at91_udc_ops, .ep0 = &controller.ep[0].ep, .name = driver_name, - .dev = { - .init_name = "gadget", - .release = nop_release, - } }, .ep[0] = { .ep = { -- cgit v0.10.2 From cf0b1d1309790fbae27e7276ae4cb30c38ac9fc8 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 19 Nov 2014 17:19:06 +0800 Subject: usb: gadget: atmel_usba_udc: remove release function As the driver call usb_add_gadget_udc --> usb_add_gadget_udc_release with NULL as release parameter, so it will use usb_udc_no_release. So, the release in driver won't used, remove it. And at the same time, in the usb_add_gadget_udc_release will set the gadget name, so remove it also in driver. Signed-off-by: Bo Shen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 990b26f..b317479 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1007,19 +1007,10 @@ static struct usb_endpoint_descriptor usba_ep0_desc = { .bInterval = 1, }; -static void nop_release(struct device *dev) -{ - -} - static struct usb_gadget usba_gadget_template = { .ops = &usba_udc_ops, .max_speed = USB_SPEED_HIGH, .name = "atmel_usba_udc", - .dev = { - .init_name = "gadget", - .release = nop_release, - }, }; /* -- cgit v0.10.2 From b2ba27a5c56ff7204d8a8684893d64d4afe2cee5 Mon Sep 17 00:00:00 2001 From: Ronald Wahl Date: Wed, 19 Nov 2014 16:37:27 +0100 Subject: usb: gadget: at91_udc: move prepare clk into process context Commit 7628083227b6bc4a7e33d7c381d7a4e558424b6b (usb: gadget: at91_udc: prepare clk before calling enable) added clock preparation in interrupt context. This is not allowed as it might sleep. Also setting the clock rate is unsafe to call from there for the same reason. Move clock preparation and setting clock rate into process context (at91udc_probe). Signed-off-by: Ronald Wahl Acked-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre Cc: Felipe Balbi Cc: # v3.17+ Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index fe0534c..eb2999c 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -895,12 +895,10 @@ static void clk_on(struct at91_udc *udc) return; udc->clocked = 1; - if (IS_ENABLED(CONFIG_COMMON_CLK)) { - clk_set_rate(udc->uclk, 48000000); - clk_prepare_enable(udc->uclk); - } - clk_prepare_enable(udc->iclk); - clk_prepare_enable(udc->fclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_enable(udc->uclk); + clk_enable(udc->iclk); + clk_enable(udc->fclk); } static void clk_off(struct at91_udc *udc) @@ -909,10 +907,10 @@ static void clk_off(struct at91_udc *udc) return; udc->clocked = 0; udc->gadget.speed = USB_SPEED_UNKNOWN; - clk_disable_unprepare(udc->fclk); - clk_disable_unprepare(udc->iclk); + clk_disable(udc->fclk); + clk_disable(udc->iclk); if (IS_ENABLED(CONFIG_COMMON_CLK)) - clk_disable_unprepare(udc->uclk); + clk_disable(udc->uclk); } /* @@ -1793,14 +1791,24 @@ static int at91udc_probe(struct platform_device *pdev) } /* don't do anything until we have both gadget driver and VBUS */ + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + clk_set_rate(udc->uclk, 48000000); + retval = clk_prepare(udc->uclk); + if (retval) + goto fail1; + } + retval = clk_prepare(udc->fclk); + if (retval) + goto fail1a; + retval = clk_prepare_enable(udc->iclk); if (retval) - goto fail1; + goto fail1b; at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); /* Clear all pending interrupts - UDP may be used by bootloader. */ at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); - clk_disable_unprepare(udc->iclk); + clk_disable(udc->iclk); /* request UDC and maybe VBUS irqs */ udc->udp_irq = platform_get_irq(pdev, 0); @@ -1808,7 +1816,7 @@ static int at91udc_probe(struct platform_device *pdev) 0, driver_name, udc); if (retval < 0) { DBG("request irq %d failed\n", udc->udp_irq); - goto fail1; + goto fail1c; } if (gpio_is_valid(udc->board.vbus_pin)) { retval = gpio_request(udc->board.vbus_pin, "udc_vbus"); @@ -1861,6 +1869,13 @@ fail3: gpio_free(udc->board.vbus_pin); fail2: free_irq(udc->udp_irq, udc); +fail1c: + clk_unprepare(udc->iclk); +fail1b: + clk_unprepare(udc->fclk); +fail1a: + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_unprepare(udc->uclk); fail1: if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk)) clk_put(udc->uclk); @@ -1909,6 +1924,11 @@ static int __exit at91udc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_unprepare(udc->uclk); + clk_unprepare(udc->fclk); + clk_unprepare(udc->iclk); + clk_put(udc->iclk); clk_put(udc->fclk); if (IS_ENABLED(CONFIG_COMMON_CLK)) -- cgit v0.10.2 From 18a4e65f229aec8ac23a036ff734864eefe4b89d Mon Sep 17 00:00:00 2001 From: Mario Schuknecht Date: Sun, 16 Nov 2014 21:21:45 +0100 Subject: usb: gadget: net2280: Fix superspeed dma_done() Parameter three in function call dma_done() is incorrect. Move use of variable 'tmp' after if-condition. Signed-off-by: Mario Schuknecht Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index c491794..d6411e0 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1118,10 +1118,10 @@ static void scan_dma_completions(struct net2280_ep *ep) break; } else if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { - tmp = readl(&ep->regs->ep_stat); if (ep->dev->quirks & PLX_SUPERSPEED) return dma_done(ep, req, tmp, 0); + tmp = readl(&ep->regs->ep_stat); /* AVOID TROUBLE HERE by not issuing short reads from * your gadget driver. That helps avoids errata 0121, * 0122, and 0124; not all cases trigger the warning. -- cgit v0.10.2 From 13ebb68cb5a227abe2437094f99a699736e39e0a Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 20 Nov 2014 22:53:25 +0100 Subject: phy: add the Berlin USB PHY driver Add the driver driving the Marvell Berlin USB PHY. This allows to initialize the PHY and to use it from the USB driver later. Signed-off-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index cfaced9..4144d25 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -15,6 +15,13 @@ config GENERIC_PHY phy users can obtain reference to the PHY. All the users of this framework should select this config. +config PHY_BERLIN_USB + tristate "Marvell Berlin USB PHY Driver" + depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF + select GENERIC_PHY + help + Enable this to support the USB PHY on Marvell Berlin SoCs. + config PHY_BERLIN_SATA tristate "Marvell Berlin SATA PHY driver" depends on ARCH_BERLIN && HAS_IOMEM && OF diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 30d90a8..68022f6 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_GENERIC_PHY) += phy-core.o +obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c new file mode 100644 index 0000000..f9f1306 --- /dev/null +++ b/drivers/phy/phy-berlin-usb.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2014 Marvell Technology Group Ltd. + * + * Antoine Tenart + * Jisheng Zhang + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB_PHY_PLL 0x04 +#define USB_PHY_PLL_CONTROL 0x08 +#define USB_PHY_TX_CTRL0 0x10 +#define USB_PHY_TX_CTRL1 0x14 +#define USB_PHY_TX_CTRL2 0x18 +#define USB_PHY_RX_CTRL 0x20 +#define USB_PHY_ANALOG 0x34 + +/* USB_PHY_PLL */ +#define CLK_REF_DIV(x) ((x) << 4) +#define FEEDBACK_CLK_DIV(x) ((x) << 8) + +/* USB_PHY_PLL_CONTROL */ +#define CLK_STABLE BIT(0) +#define PLL_CTRL_PIN BIT(1) +#define PLL_CTRL_REG BIT(2) +#define PLL_ON BIT(3) +#define PHASE_OFF_TOL_125 (0x0 << 5) +#define PHASE_OFF_TOL_250 BIT(5) +#define KVC0_CALIB (0x0 << 9) +#define KVC0_REG_CTRL BIT(9) +#define KVC0_HIGH (0x0 << 10) +#define KVC0_LOW (0x3 << 10) +#define CLK_BLK_EN BIT(13) + +/* USB_PHY_TX_CTRL0 */ +#define EXT_HS_RCAL_EN BIT(3) +#define EXT_FS_RCAL_EN BIT(4) +#define IMPCAL_VTH_DIV(x) ((x) << 5) +#define EXT_RS_RCAL_DIV(x) ((x) << 8) +#define EXT_FS_RCAL_DIV(x) ((x) << 12) + +/* USB_PHY_TX_CTRL1 */ +#define TX_VDD15_14 (0x0 << 4) +#define TX_VDD15_15 BIT(4) +#define TX_VDD15_16 (0x2 << 4) +#define TX_VDD15_17 (0x3 << 4) +#define TX_VDD12_VDD (0x0 << 6) +#define TX_VDD12_11 BIT(6) +#define TX_VDD12_12 (0x2 << 6) +#define TX_VDD12_13 (0x3 << 6) +#define LOW_VDD_EN BIT(8) +#define TX_OUT_AMP(x) ((x) << 9) + +/* USB_PHY_TX_CTRL2 */ +#define TX_CHAN_CTRL_REG(x) ((x) << 0) +#define DRV_SLEWRATE(x) ((x) << 4) +#define IMP_CAL_FS_HS_DLY_0 (0x0 << 6) +#define IMP_CAL_FS_HS_DLY_1 BIT(6) +#define IMP_CAL_FS_HS_DLY_2 (0x2 << 6) +#define IMP_CAL_FS_HS_DLY_3 (0x3 << 6) +#define FS_DRV_EN_MASK(x) ((x) << 8) +#define HS_DRV_EN_MASK(x) ((x) << 12) + +/* USB_PHY_RX_CTRL */ +#define PHASE_FREEZE_DLY_2_CL (0x0 << 0) +#define PHASE_FREEZE_DLY_4_CL BIT(0) +#define ACK_LENGTH_8_CL (0x0 << 2) +#define ACK_LENGTH_12_CL BIT(2) +#define ACK_LENGTH_16_CL (0x2 << 2) +#define ACK_LENGTH_20_CL (0x3 << 2) +#define SQ_LENGTH_3 (0x0 << 4) +#define SQ_LENGTH_6 BIT(4) +#define SQ_LENGTH_9 (0x2 << 4) +#define SQ_LENGTH_12 (0x3 << 4) +#define DISCON_THRESHOLD_260 (0x0 << 6) +#define DISCON_THRESHOLD_270 BIT(6) +#define DISCON_THRESHOLD_280 (0x2 << 6) +#define DISCON_THRESHOLD_290 (0x3 << 6) +#define SQ_THRESHOLD(x) ((x) << 8) +#define LPF_COEF(x) ((x) << 12) +#define INTPL_CUR_10 (0x0 << 14) +#define INTPL_CUR_20 BIT(14) +#define INTPL_CUR_30 (0x2 << 14) +#define INTPL_CUR_40 (0x3 << 14) + +/* USB_PHY_ANALOG */ +#define ANA_PWR_UP BIT(1) +#define ANA_PWR_DOWN BIT(2) +#define V2I_VCO_RATIO(x) ((x) << 7) +#define R_ROTATE_90 (0x0 << 10) +#define R_ROTATE_0 BIT(10) +#define MODE_TEST_EN BIT(11) +#define ANA_TEST_DC_CTRL(x) ((x) << 12) + +#define to_phy_berlin_usb_priv(p) \ + container_of((p), struct phy_berlin_usb_priv, phy) + +static const u32 phy_berlin_pll_dividers[] = { + /* Berlin 2 */ + CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54), + /* Berlin 2CD */ + CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55), +}; + +struct phy_berlin_usb_priv { + void __iomem *base; + struct phy *phy; + struct reset_control *rst_ctrl; + u32 pll_divider; +}; + +static int phy_berlin_usb_power_on(struct phy *phy) +{ + struct phy_berlin_usb_priv *priv = dev_get_drvdata(phy->dev.parent); + + reset_control_reset(priv->rst_ctrl); + + writel(priv->pll_divider, + priv->base + USB_PHY_PLL); + writel(CLK_STABLE | PLL_CTRL_REG | PHASE_OFF_TOL_250 | KVC0_REG_CTRL | + CLK_BLK_EN, priv->base + USB_PHY_PLL_CONTROL); + writel(V2I_VCO_RATIO(0x5) | R_ROTATE_0 | ANA_TEST_DC_CTRL(0x5), + priv->base + USB_PHY_ANALOG); + writel(PHASE_FREEZE_DLY_4_CL | ACK_LENGTH_16_CL | SQ_LENGTH_12 | + DISCON_THRESHOLD_260 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) | + INTPL_CUR_30, priv->base + USB_PHY_RX_CTRL); + + writel(TX_VDD12_13 | TX_OUT_AMP(0x3), priv->base + USB_PHY_TX_CTRL1); + writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4), + priv->base + USB_PHY_TX_CTRL0); + + writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4) | + EXT_FS_RCAL_DIV(0x2), priv->base + USB_PHY_TX_CTRL0); + + writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4), + priv->base + USB_PHY_TX_CTRL0); + writel(TX_CHAN_CTRL_REG(0xf) | DRV_SLEWRATE(0x3) | IMP_CAL_FS_HS_DLY_3 | + FS_DRV_EN_MASK(0xd), priv->base + USB_PHY_TX_CTRL2); + + return 0; +} + +static struct phy_ops phy_berlin_usb_ops = { + .power_on = phy_berlin_usb_power_on, + .owner = THIS_MODULE, +}; + +static const struct of_device_id phy_berlin_sata_of_match[] = { + { + .compatible = "marvell,berlin2-usb-phy", + .data = &phy_berlin_pll_dividers[0], + }, + { + .compatible = "marvell,berlin2cd-usb-phy", + .data = &phy_berlin_pll_dividers[1], + }, + { }, +}; +MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match); + +static int phy_berlin_usb_probe(struct platform_device *pdev) +{ + const struct of_device_id *match = + of_match_device(phy_berlin_sata_of_match, &pdev->dev); + struct phy_berlin_usb_priv *priv; + struct resource *res; + struct phy_provider *phy_provider; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->rst_ctrl = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(priv->rst_ctrl)) + return PTR_ERR(priv->rst_ctrl); + + priv->pll_divider = *((u32 *)match->data); + + priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops, + NULL); + if (IS_ERR(priv->phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(priv->phy); + } + + platform_set_drvdata(pdev, priv); + + phy_provider = + devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + return 0; +} + +static struct platform_driver phy_berlin_usb_driver = { + .probe = phy_berlin_usb_probe, + .driver = { + .name = "phy-berlin-usb", + .owner = THIS_MODULE, + .of_match_table = phy_berlin_sata_of_match, + }, +}; +module_platform_driver(phy_berlin_usb_driver); + +MODULE_AUTHOR("Antoine Tenart "); +MODULE_DESCRIPTION("Marvell Berlin PHY driver for USB"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 2f3fa3a0e5672f87f5b972910737a2ef60941b62 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 20 Nov 2014 22:53:26 +0100 Subject: Documentation: bindings: add doc for the Berlin USB PHY Document the bindings of the Marvell Berlin USB PHY driver. Signed-off-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt b/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt new file mode 100644 index 0000000..be33780 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt @@ -0,0 +1,16 @@ +* Marvell Berlin USB PHY + +Required properties: +- compatible: "marvell,berlin2-usb-phy" or "marvell,berlin2cd-usb-phy" +- reg: base address and length of the registers +- #phys-cells: should be 0 +- resets: reference to the reset controller + +Example: + + usb-phy@f774000 { + compatible = "marvell,berlin2-usb-phy"; + reg = <0xf774000 0x128>; + #phy-cells = <0>; + resets = <&chip 0x104 14>; + }; -- cgit v0.10.2 From d451057464a7ea2fe400e56c8a7e004c875f2a84 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 19 Nov 2014 17:28:17 +0200 Subject: phy: safer to_phy() macro This makes to_phy() macro work with other variable names besides "dev". Signed-off-by: Heikki Krogerus Tested-by: Vivek Gautam Acked-by: Felipe Balbi Signed-off-by: Kishon Vijay Abraham I diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 8cb6f81..9fda683 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -110,7 +110,7 @@ struct phy_init_data { .port = _port, \ } -#define to_phy(dev) (container_of((dev), struct phy, dev)) +#define to_phy(a) (container_of((a), struct phy, dev)) #define of_phy_provider_register(dev, xlate) \ __of_phy_provider_register((dev), THIS_MODULE, (xlate)) -- cgit v0.10.2 From b7bc15b98e843926d01eb03b9c0e196d8ddbadeb Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 19 Nov 2014 17:28:18 +0200 Subject: phy: improved lookup method Separates registration of the phy and the lookup. The method is copied from clkdev.c, Signed-off-by: Heikki Krogerus Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/phy.txt b/Documentation/phy.txt index c6594af..371361c 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt @@ -54,18 +54,14 @@ The PHY driver should create the PHY in order for other peripheral controllers to make use of it. The PHY framework provides 2 APIs to create the PHY. struct phy *phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data); + const struct phy_ops *ops); struct phy *devm_phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data); + const struct phy_ops *ops); The PHY drivers can use one of the above 2 APIs to create the PHY by passing -the device pointer, phy ops and init_data. +the device pointer and phy ops. phy_ops is a set of function pointers for performing PHY operations such as -init, exit, power_on and power_off. *init_data* is mandatory to get a reference -to the PHY in the case of non-dt boot. See section *Board File Initialization* -on how init_data should be used. +init, exit, power_on and power_off. Inorder to dereference the private data (in phy_ops), the phy provider driver can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in @@ -137,42 +133,18 @@ There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync, phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and phy_pm_runtime_forbid for performing PM operations. -8. Board File Initialization - -Certain board file initialization is necessary in order to get a reference -to the PHY in the case of non-dt boot. -Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe, -then in the board file the following initialization should be done. - -struct phy_consumer consumers[] = { - PHY_CONSUMER("dwc3.0", "usb"), - PHY_CONSUMER("pcie.0", "pcie"), - PHY_CONSUMER("sata.0", "sata"), -}; -PHY_CONSUMER takes 2 parameters, first is the device name of the controller -(PHY consumer) and second is the port name. - -struct phy_init_data init_data = { - .consumers = consumers, - .num_consumers = ARRAY_SIZE(consumers), -}; - -static const struct platform_device pipe3_phy_dev = { - .name = "pipe3-phy", - .id = -1, - .dev = { - .platform_data = { - .init_data = &init_data, - }, - }, -}; - -then, while doing phy_create, the PHY driver should pass this init_data - phy_create(dev, ops, pdata->init_data); - -and the controller driver (phy consumer) should pass the port name along with -the device to get a reference to the PHY - phy_get(dev, "pcie"); +8. PHY Mappings + +In order to get reference to a PHY without help from DeviceTree, the framework +offers lookups which can be compared to clkdev that allow clk structures to be +bound to devices. A lookup can be made be made during runtime when a handle to +the struct phy already exists. + +The framework offers the following API for registering and unregistering the +lookups. + +int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id); +void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id); 9. DeviceTree Binding diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 1606ce9..bc83077 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -26,6 +26,7 @@ static struct class *phy_class; static DEFINE_MUTEX(phy_provider_mutex); static LIST_HEAD(phy_provider_list); +static LIST_HEAD(phys); static DEFINE_IDA(phy_ida); static void devm_phy_release(struct device *dev, void *res) @@ -84,6 +85,87 @@ static struct phy *phy_lookup(struct device *device, const char *port) return ERR_PTR(-ENODEV); } +/** + * phy_create_lookup() - allocate and register PHY/device association + * @phy: the phy of the association + * @con_id: connection ID string on device + * @dev_id: the device of the association + * + * Creates and registers phy_lookup entry. + */ +int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id) +{ + struct phy_lookup *pl; + + if (!phy || !dev_id || !con_id) + return -EINVAL; + + pl = kzalloc(sizeof(*pl), GFP_KERNEL); + if (!pl) + return -ENOMEM; + + pl->dev_id = dev_id; + pl->con_id = con_id; + pl->phy = phy; + + mutex_lock(&phy_provider_mutex); + list_add_tail(&pl->node, &phys); + mutex_unlock(&phy_provider_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(phy_create_lookup); + +/** + * phy_remove_lookup() - find and remove PHY/device association + * @phy: the phy of the association + * @con_id: connection ID string on device + * @dev_id: the device of the association + * + * Finds and unregisters phy_lookup entry that was created with + * phy_create_lookup(). + */ +void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id) +{ + struct phy_lookup *pl; + + if (!phy || !dev_id || !con_id) + return; + + mutex_lock(&phy_provider_mutex); + list_for_each_entry(pl, &phys, node) + if (pl->phy == phy && !strcmp(pl->dev_id, dev_id) && + !strcmp(pl->con_id, con_id)) { + list_del(&pl->node); + kfree(pl); + break; + } + mutex_unlock(&phy_provider_mutex); +} +EXPORT_SYMBOL_GPL(phy_remove_lookup); + +static struct phy *phy_find(struct device *dev, const char *con_id) +{ + const char *dev_id = dev_name(dev); + struct phy_lookup *p, *pl = NULL; + struct phy *phy; + + mutex_lock(&phy_provider_mutex); + list_for_each_entry(p, &phys, node) + if (!strcmp(p->dev_id, dev_id) && !strcmp(p->con_id, con_id)) { + pl = p; + break; + } + mutex_unlock(&phy_provider_mutex); + + phy = pl ? pl->phy : ERR_PTR(-ENODEV); + + /* fall-back to the old lookup method for now */ + if (IS_ERR(phy)) + phy = phy_lookup(dev, con_id); + return phy; +} + static struct phy_provider *of_phy_provider_lookup(struct device_node *node) { struct phy_provider *phy_provider; @@ -455,7 +537,7 @@ struct phy *phy_get(struct device *dev, const char *string) string); phy = _of_phy_get(dev->of_node, index); } else { - phy = phy_lookup(dev, string); + phy = phy_find(dev, string); } if (IS_ERR(phy)) return phy; diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 9fda683..849284e 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -110,6 +110,13 @@ struct phy_init_data { .port = _port, \ } +struct phy_lookup { + struct list_head node; + const char *dev_id; + const char *con_id; + struct phy *phy; +}; + #define to_phy(a) (container_of((a), struct phy, dev)) #define of_phy_provider_register(dev, xlate) \ @@ -174,6 +181,8 @@ struct phy_provider *__devm_of_phy_provider_register(struct device *dev, void of_phy_provider_unregister(struct phy_provider *phy_provider); void devm_of_phy_provider_unregister(struct device *dev, struct phy_provider *phy_provider); +int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id); +void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id); #else static inline int phy_pm_runtime_get(struct phy *phy) { @@ -345,6 +354,13 @@ static inline void devm_of_phy_provider_unregister(struct device *dev, struct phy_provider *phy_provider) { } +static inline int +phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id) +{ + return 0; +} +static inline void phy_remove_lookup(struct phy *phy, const char *con_id, + const char *dev_id) { } #endif #endif /* __DRIVERS_PHY_H */ -- cgit v0.10.2 From df9f7b311db1edae7ec5e2c78aa92fce7b9dd34d Mon Sep 17 00:00:00 2001 From: Kiran Raparthy Date: Fri, 21 Nov 2014 11:31:20 +0530 Subject: usb: phy: introduce usb_phy_set_event interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHY drivers require a generic interface to handle per-PHY events. usb_phy_set_event interface sets event to phy event. PHY drivers call this interface for each phy event. Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org Cc: linux-usb@vger.kernel.org Cc: Android Kernel Team Cc: John Stultz Cc: Sumit Semwal Cc: Arve Hj�nnev�g Cc: Benoit Goby [Original patch in Android from Todd] Cc: Todd Poynor Signed-off-by: Kiran Raparthy Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index e6bf801..b4066a0 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -446,3 +446,15 @@ int usb_bind_phy(const char *dev_name, u8 index, return 0; } EXPORT_SYMBOL_GPL(usb_bind_phy); + +/** + * usb_phy_set_event - set event to phy event + * @x: the phy returned by usb_get_phy(); + * + * This sets event to phy event + */ +void usb_phy_set_event(struct usb_phy *x, unsigned long event) +{ + x->last_event = event; +} +EXPORT_SYMBOL_GPL(usb_phy_set_event); diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index ac7d791..f499c23 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -209,6 +209,7 @@ extern void usb_put_phy(struct usb_phy *); extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); extern int usb_bind_phy(const char *dev_name, u8 index, const char *phy_dev_name); +extern void usb_phy_set_event(struct usb_phy *x, unsigned long event); #else static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) { @@ -250,6 +251,10 @@ static inline int usb_bind_phy(const char *dev_name, u8 index, { return -EOPNOTSUPP; } + +static inline void usb_phy_set_event(struct usb_phy *x, unsigned long event) +{ +} #endif static inline int -- cgit v0.10.2 From c1a3acaadde7eb260f4fd4ec87cb87d3ffeed979 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:45 +0530 Subject: usb: dwc3: exynos: Remove local variable for clock from probe There's no need to keep one local variable for clock, and then assign the same to 'clk' member of dwc3_exynos. Just cleaning it up. Signed-off-by: Vivek Gautam Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 4369c66..14f85a0 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -105,7 +105,6 @@ static int dwc3_exynos_remove_child(struct device *dev, void *unused) static int dwc3_exynos_probe(struct platform_device *pdev) { struct dwc3_exynos *exynos; - struct clk *clk; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; @@ -132,15 +131,13 @@ static int dwc3_exynos_probe(struct platform_device *pdev) return ret; } - clk = devm_clk_get(dev, "usbdrd30"); - if (IS_ERR(clk)) { + exynos->dev = dev; + + exynos->clk = devm_clk_get(dev, "usbdrd30"); + if (IS_ERR(exynos->clk)) { dev_err(dev, "couldn't get clock\n"); return -EINVAL; } - - exynos->dev = dev; - exynos->clk = clk; - clk_prepare_enable(exynos->clk); exynos->vdd33 = devm_regulator_get(dev, "vdd33"); @@ -184,7 +181,7 @@ err4: err3: regulator_disable(exynos->vdd33); err2: - clk_disable_unprepare(clk); + clk_disable_unprepare(exynos->clk); return ret; } -- cgit v0.10.2 From 72d996fc7a01c2e4d581a15db7d001e2799ffb29 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:46 +0530 Subject: usb: dwc3: exynos: Add provision for suspend clock DWC3 controller on Exynos SoC series have separate control for suspend clock which replaces pipe3_rx_pclk as clock source to a small part of DWC3 core that operates when SS PHY is in its lowest power state (P3) in states SS.disabled and U3. Suggested-by: Anton Tikhomirov Signed-off-by: Vivek Gautam Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 14f85a0..a1782d8 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -34,6 +34,8 @@ struct dwc3_exynos { struct device *dev; struct clk *clk; + struct clk *susp_clk; + struct regulator *vdd33; struct regulator *vdd10; }; @@ -140,6 +142,13 @@ static int dwc3_exynos_probe(struct platform_device *pdev) } clk_prepare_enable(exynos->clk); + exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); + if (IS_ERR(exynos->susp_clk)) { + dev_dbg(dev, "no suspend clk specified\n"); + exynos->susp_clk = NULL; + } + clk_prepare_enable(exynos->susp_clk); + exynos->vdd33 = devm_regulator_get(dev, "vdd33"); if (IS_ERR(exynos->vdd33)) { ret = PTR_ERR(exynos->vdd33); @@ -181,6 +190,7 @@ err4: err3: regulator_disable(exynos->vdd33); err2: + clk_disable_unprepare(exynos->susp_clk); clk_disable_unprepare(exynos->clk); return ret; } @@ -193,6 +203,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev) platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb3_phy); + clk_disable_unprepare(exynos->susp_clk); clk_disable_unprepare(exynos->clk); regulator_disable(exynos->vdd33); -- cgit v0.10.2 From ed692a99f31c92ec649ee2f7a0ecb4aa0f69d853 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:47 +0530 Subject: usb: dwc3: exynos: Add provision for AXI UpScaler clock on exynos7 DWC3 controller on Exynos7 SoC has separate control for AXI UpScaler which connects DWC3 DRD controller to AXI bus. Get the gate clock for the same to control it across power cycles. Suggested-by: Anton Tikhomirov Signed-off-by: Vivek Gautam Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index a3b5990..9b4dbe3 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -82,8 +82,10 @@ Example: DWC3 Required properties: - - compatible: should be "samsung,exynos5250-dwusb3" for USB 3.0 DWC3 - controller. + - compatible: should be one of the following - + "samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on + Exynos5250/5420. + "samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7. - #address-cells, #size-cells : should be '1' if the device has sub-nodes with 'reg' property. - ranges: allows valid 1:1 translation between child's address space and diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index a1782d8..7bd0a95 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -35,6 +35,7 @@ struct dwc3_exynos { struct clk *clk; struct clk *susp_clk; + struct clk *axius_clk; struct regulator *vdd33; struct regulator *vdd10; @@ -149,6 +150,17 @@ static int dwc3_exynos_probe(struct platform_device *pdev) } clk_prepare_enable(exynos->susp_clk); + if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) { + exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk"); + if (IS_ERR(exynos->axius_clk)) { + dev_err(dev, "no AXI UpScaler clk specified\n"); + return -ENODEV; + } + clk_prepare_enable(exynos->axius_clk); + } else { + exynos->axius_clk = NULL; + } + exynos->vdd33 = devm_regulator_get(dev, "vdd33"); if (IS_ERR(exynos->vdd33)) { ret = PTR_ERR(exynos->vdd33); @@ -190,6 +202,7 @@ err4: err3: regulator_disable(exynos->vdd33); err2: + clk_disable_unprepare(exynos->axius_clk); clk_disable_unprepare(exynos->susp_clk); clk_disable_unprepare(exynos->clk); return ret; @@ -203,6 +216,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev) platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb3_phy); + clk_disable_unprepare(exynos->axius_clk); clk_disable_unprepare(exynos->susp_clk); clk_disable_unprepare(exynos->clk); @@ -214,6 +228,7 @@ static int dwc3_exynos_remove(struct platform_device *pdev) static const struct of_device_id exynos_dwc3_match[] = { { .compatible = "samsung,exynos5250-dwusb3" }, + { .compatible = "samsung,exynos7-dwusb3" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_dwc3_match); @@ -223,6 +238,7 @@ static int dwc3_exynos_suspend(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); + clk_disable(exynos->axius_clk); clk_disable(exynos->clk); regulator_disable(exynos->vdd33); @@ -248,6 +264,7 @@ static int dwc3_exynos_resume(struct device *dev) } clk_enable(exynos->clk); + clk_enable(exynos->axius_clk); /* runtime set active to reflect active state. */ pm_runtime_disable(dev); -- cgit v0.10.2 From 4ace06e8b3c32d6a601474af31580bbc1027fa9f Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 21 Nov 2014 15:14:47 +0100 Subject: usb: dwc2: gadget: rework disconnect event handling This patch adds a call to s3c_hsotg_disconnect() from 'end session' interrupt (GOTGINT_SES_END_DET) to correctly notify gadget subsystem about unplugged usb cable. DISCONNINT interrupt cannot be used for this purpose, because it is asserted only in host mode. To avoid reporting disconnect event more than once, a disconnect call has been moved from USB_REQ_SET_ADDRESS handling function to SESSREQINT interrupt. This way driver ensures that disconnect event is reported either when usb cable is unplugged or every time the host starts a new session. To handle devices which has been synthesized without SRP support, connected state is set in ENUMDONE interrupt. Signed-off-by: Marek Szyprowski Acked-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 4710935..2cb0ac3 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -687,6 +687,7 @@ struct dwc2_hsotg { u8 ctrl_buff[8]; struct usb_gadget gadget; + unsigned int connected:1; unsigned int setup; unsigned long last_rst; struct s3c_hsotg_ep *eps; @@ -968,6 +969,7 @@ extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2); extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2); extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg); +extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2); #else static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2) { return 0; } @@ -979,6 +981,7 @@ static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) { return 0; } static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {} static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {} +static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {} #endif #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index b176c2f..ad43c5b 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -128,6 +128,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) dwc2_op_state_str(hsotg)); gotgctl = readl(hsotg->regs + GOTGCTL); + if (dwc2_is_device_mode(hsotg)) + s3c_hsotg_disconnect(hsotg); + if (hsotg->op_state == OTG_STATE_B_HOST) { hsotg->op_state = OTG_STATE_B_PERIPHERAL; } else { @@ -314,6 +317,12 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) /* Clear interrupt */ writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); + + /* + * Report disconnect if there is any previous session established + */ + if (dwc2_is_device_mode(hsotg)) + s3c_hsotg_disconnect(hsotg); } /* diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 367689b..3cd7891 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1030,7 +1030,6 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, } static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); -static void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg); /** * s3c_hsotg_stall_ep0 - stall ep0 @@ -1108,7 +1107,6 @@ static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg, if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (ctrl->bRequest) { case USB_REQ_SET_ADDRESS: - s3c_hsotg_disconnect(hsotg); dcfg = readl(hsotg->regs + DCFG); dcfg &= ~DCFG_DEVADDR_MASK; dcfg |= (le16_to_cpu(ctrl->wValue) << @@ -2028,15 +2026,20 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, * transactions and signal the gadget driver that this * has happened. */ -static void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg) +void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg) { unsigned ep; + if (!hsotg->connected) + return; + + hsotg->connected = 0; for (ep = 0; ep < hsotg->num_of_eps; ep++) kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); call_gadget(hsotg, disconnect); } +EXPORT_SYMBOL_GPL(s3c_hsotg_disconnect); /** * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler @@ -2289,6 +2292,7 @@ irq_retry: writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); s3c_hsotg_irq_enumdone(hsotg); + hsotg->connected = 1; } if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { -- cgit v0.10.2 From 7ad8096edfe0529eabb3ad466184c8fbd6134e1a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 21 Nov 2014 15:14:48 +0100 Subject: usb: dwc2: gadget: add mutex to serialize init/deinit calls This patch adds mutex, which protects initialization and deinitialization procedures against suspend/resume methods. This mutex will be needed by the updated suspend/resume calls, which tracks gadget state. Signed-off-by: Marek Szyprowski Acked-by: Paul Zimmerman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 2cb0ac3..6b19755 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -576,6 +576,7 @@ struct dwc2_hsotg { struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; spinlock_t lock; + struct mutex init_mutex; void *priv; int irq; struct clk *clk; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 3cd7891..6517334 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2866,6 +2867,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, return -EINVAL; } + mutex_lock(&hsotg->init_mutex); WARN_ON(hsotg->driver); driver->driver.bus = NULL; @@ -2891,9 +2893,12 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); + mutex_unlock(&hsotg->init_mutex); + return 0; err: + mutex_unlock(&hsotg->init_mutex); hsotg->driver = NULL; return ret; } @@ -2914,6 +2919,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) if (!hsotg) return -ENODEV; + mutex_lock(&hsotg->init_mutex); + /* all endpoints should be shutdown */ for (ep = 1; ep < hsotg->num_of_eps; ep++) s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); @@ -2931,6 +2938,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) clk_disable(hsotg->clk); + mutex_unlock(&hsotg->init_mutex); + return 0; } @@ -2959,6 +2968,7 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) dev_dbg(hsotg->dev, "%s: is_on: %d\n", __func__, is_on); + mutex_lock(&hsotg->init_mutex); spin_lock_irqsave(&hsotg->lock, flags); if (is_on) { clk_enable(hsotg->clk); @@ -2970,6 +2980,7 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) hsotg->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock_irqrestore(&hsotg->lock, flags); + mutex_unlock(&hsotg->init_mutex); return 0; } @@ -3572,6 +3583,8 @@ int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg) unsigned long flags; int ret = 0; + mutex_lock(&hsotg->init_mutex); + if (hsotg->driver) dev_info(hsotg->dev, "suspending usb gadget %s\n", hsotg->driver->driver.name); @@ -3594,6 +3607,8 @@ int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg) clk_disable(hsotg->clk); } + mutex_unlock(&hsotg->init_mutex); + return ret; } EXPORT_SYMBOL_GPL(s3c_hsotg_suspend); @@ -3603,6 +3618,8 @@ int s3c_hsotg_resume(struct dwc2_hsotg *hsotg) unsigned long flags; int ret = 0; + mutex_lock(&hsotg->init_mutex); + if (hsotg->driver) { dev_info(hsotg->dev, "resuming usb gadget %s\n", hsotg->driver->driver.name); @@ -3619,6 +3636,8 @@ int s3c_hsotg_resume(struct dwc2_hsotg *hsotg) s3c_hsotg_core_connect(hsotg); spin_unlock_irqrestore(&hsotg->lock, flags); + mutex_unlock(&hsotg->init_mutex); + return ret; } EXPORT_SYMBOL_GPL(s3c_hsotg_resume); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 57eb8a3..ec5658a 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -212,6 +213,7 @@ static int dwc2_driver_probe(struct platform_device *dev) hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node); spin_lock_init(&hsotg->lock); + mutex_init(&hsotg->init_mutex); retval = dwc2_gadget_init(hsotg, irq); if (retval) return retval; -- cgit v0.10.2 From dc6e69e603e58200df806afcfb9b71ef94e58847 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 21 Nov 2014 15:14:49 +0100 Subject: usb: dwc2: gadget: rework suspend/resume code to correctly restore gadget state Suspend/resume code assumed that the gadget was always started and enabled to connect to usb bus. This means that the actual state of the gadget (started/stopped or connected/disconnected) was not correctly preserved on suspend/resume cycle. This patch fixes this issue. Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 6b19755..7a70a13 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -688,8 +688,9 @@ struct dwc2_hsotg { u8 ctrl_buff[8]; struct usb_gadget gadget; + unsigned int enabled:1; unsigned int connected:1; - unsigned int setup; + unsigned int setup:1; unsigned long last_rst; struct s3c_hsotg_ep *eps; #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 6517334..05b0522 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2889,6 +2889,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, spin_lock_irqsave(&hsotg->lock, flags); s3c_hsotg_init(hsotg); s3c_hsotg_core_init_disconnected(hsotg); + hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); @@ -2929,6 +2930,7 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) hsotg->driver = NULL; hsotg->gadget.speed = USB_SPEED_UNKNOWN; + hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); @@ -2972,9 +2974,11 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) spin_lock_irqsave(&hsotg->lock, flags); if (is_on) { clk_enable(hsotg->clk); + hsotg->enabled = 1; s3c_hsotg_core_connect(hsotg); } else { s3c_hsotg_core_disconnect(hsotg); + hsotg->enabled = 0; clk_disable(hsotg->clk); } @@ -3585,20 +3589,21 @@ int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg) mutex_lock(&hsotg->init_mutex); - if (hsotg->driver) + if (hsotg->driver) { + int ep; + dev_info(hsotg->dev, "suspending usb gadget %s\n", hsotg->driver->driver.name); - spin_lock_irqsave(&hsotg->lock, flags); - s3c_hsotg_core_disconnect(hsotg); - s3c_hsotg_disconnect(hsotg); - hsotg->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock_irqrestore(&hsotg->lock, flags); + spin_lock_irqsave(&hsotg->lock, flags); + if (hsotg->enabled) + s3c_hsotg_core_disconnect(hsotg); + s3c_hsotg_disconnect(hsotg); + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock_irqrestore(&hsotg->lock, flags); - s3c_hsotg_phy_disable(hsotg); + s3c_hsotg_phy_disable(hsotg); - if (hsotg->driver) { - int ep; for (ep = 0; ep < hsotg->num_of_eps; ep++) s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); @@ -3626,16 +3631,16 @@ int s3c_hsotg_resume(struct dwc2_hsotg *hsotg) clk_enable(hsotg->clk); ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), - hsotg->supplies); - } - - s3c_hsotg_phy_enable(hsotg); + hsotg->supplies); - spin_lock_irqsave(&hsotg->lock, flags); - s3c_hsotg_core_init_disconnected(hsotg); - s3c_hsotg_core_connect(hsotg); - spin_unlock_irqrestore(&hsotg->lock, flags); + s3c_hsotg_phy_enable(hsotg); + spin_lock_irqsave(&hsotg->lock, flags); + s3c_hsotg_core_init_disconnected(hsotg); + if (hsotg->enabled) + s3c_hsotg_core_connect(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + } mutex_unlock(&hsotg->init_mutex); return ret; -- cgit v0.10.2 From 7b0f000b2fdc18662e9070765a0f63c93ea0ef31 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 21 Nov 2014 14:51:43 +0100 Subject: usb: gadget: function: delete an unnecessary check before rndis_add_hdr() The rndis_add_hdr() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index f13fc6a..829edf8 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -375,8 +375,7 @@ static struct sk_buff *rndis_add_header(struct gether *port, struct sk_buff *skb2; skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); - if (skb2) - rndis_add_hdr(skb2); + rndis_add_hdr(skb2); dev_kfree_skb(skb); return skb2; -- cgit v0.10.2 From 61211b1bda0321803fdedc61158c55eab2685ad6 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 19 Nov 2014 17:28:19 +0200 Subject: phy: twl4030: use the new lookup method Creates the lookup separately. Hard coding the consumer as it can't be anything else except musb. Signed-off-by: Heikki Krogerus Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 7b04bef..c45a3aa 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -644,7 +644,6 @@ static int twl4030_usb_probe(struct platform_device *pdev) struct usb_otg *otg; struct device_node *np = pdev->dev.of_node; struct phy_provider *phy_provider; - struct phy_init_data *init_data = NULL; twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL); if (!twl) @@ -655,7 +654,6 @@ static int twl4030_usb_probe(struct platform_device *pdev) (enum twl4030_usb_mode *)&twl->usb_mode); else if (pdata) { twl->usb_mode = pdata->usb_mode; - init_data = pdata->init_data; } else { dev_err(&pdev->dev, "twl4030 initialized without pdata\n"); return -EINVAL; @@ -680,7 +678,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) otg->set_host = twl4030_set_host; otg->set_peripheral = twl4030_set_peripheral; - phy = devm_phy_create(twl->dev, NULL, &ops, init_data); + phy = devm_phy_create(twl->dev, NULL, &ops, NULL); if (IS_ERR(phy)) { dev_dbg(&pdev->dev, "Failed to create PHY\n"); return PTR_ERR(phy); @@ -733,6 +731,11 @@ static int twl4030_usb_probe(struct platform_device *pdev) return status; } + if (pdata) + err = phy_create_lookup(phy, "usb", "musb-hdrc.0"); + if (err) + return err; + pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(twl->dev); -- cgit v0.10.2 From dbc98635e0d42f0e62ea92813df1e0e4c90f8375 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 19 Nov 2014 17:28:21 +0200 Subject: phy: remove the old lookup method The users of the old method are now converted to the new one. Signed-off-by: Heikki Krogerus [ kishon@ti.com : made phy-berlin-usb.c and phy-miphy28lp.c to use the updated devm_phy_create API.] Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c index c1e0ca3..ef2dc1a 100644 --- a/drivers/phy/phy-bcm-kona-usb2.c +++ b/drivers/phy/phy-bcm-kona-usb2.c @@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); - gphy = devm_phy_create(dev, NULL, &ops, NULL); + gphy = devm_phy_create(dev, NULL, &ops); if (IS_ERR(gphy)) return PTR_ERR(gphy); diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index 873e7a8..3e599dc 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -249,7 +249,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) if (!phy_desc) return -ENOMEM; - phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops, NULL); + phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create PHY %d\n", phy_id); return PTR_ERR(phy); diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index f9f1306..c8a8d53 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -192,8 +192,7 @@ static int phy_berlin_usb_probe(struct platform_device *pdev) priv->pll_divider = *((u32 *)match->data); - priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops, - NULL); + priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops); if (IS_ERR(priv->phy)) { dev_err(&pdev->dev, "failed to create PHY\n"); return PTR_ERR(priv->phy); diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index bc83077..a12d353 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -55,36 +55,6 @@ static int devm_phy_match(struct device *dev, void *res, void *match_data) return res == match_data; } -static struct phy *phy_lookup(struct device *device, const char *port) -{ - unsigned int count; - struct phy *phy; - struct device *dev; - struct phy_consumer *consumers; - struct class_dev_iter iter; - - class_dev_iter_init(&iter, phy_class, NULL, NULL); - while ((dev = class_dev_iter_next(&iter))) { - phy = to_phy(dev); - - if (!phy->init_data) - continue; - count = phy->init_data->num_consumers; - consumers = phy->init_data->consumers; - while (count--) { - if (!strcmp(consumers->dev_name, dev_name(device)) && - !strcmp(consumers->port, port)) { - class_dev_iter_exit(&iter); - return phy; - } - consumers++; - } - } - - class_dev_iter_exit(&iter); - return ERR_PTR(-ENODEV); -} - /** * phy_create_lookup() - allocate and register PHY/device association * @phy: the phy of the association @@ -148,7 +118,6 @@ static struct phy *phy_find(struct device *dev, const char *con_id) { const char *dev_id = dev_name(dev); struct phy_lookup *p, *pl = NULL; - struct phy *phy; mutex_lock(&phy_provider_mutex); list_for_each_entry(p, &phys, node) @@ -158,12 +127,7 @@ static struct phy *phy_find(struct device *dev, const char *con_id) } mutex_unlock(&phy_provider_mutex); - phy = pl ? pl->phy : ERR_PTR(-ENODEV); - - /* fall-back to the old lookup method for now */ - if (IS_ERR(phy)) - phy = phy_lookup(dev, con_id); - return phy; + return pl ? pl->phy : ERR_PTR(-ENODEV); } static struct phy_provider *of_phy_provider_lookup(struct device_node *node) @@ -662,13 +626,11 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get); * @dev: device that is creating the new phy * @node: device node of the phy * @ops: function pointers for performing phy operations - * @init_data: contains the list of PHY consumers or NULL * * Called to create a phy using phy framework. */ struct phy *phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data) + const struct phy_ops *ops) { int ret; int id; @@ -706,7 +668,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node, phy->dev.of_node = node ?: dev->of_node; phy->id = id; phy->ops = ops; - phy->init_data = init_data; ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id); if (ret) @@ -741,7 +702,6 @@ EXPORT_SYMBOL_GPL(phy_create); * @dev: device that is creating the new phy * @node: device node of the phy * @ops: function pointers for performing phy operations - * @init_data: contains the list of PHY consumers or NULL * * Creates a new PHY device adding it to the PHY class. * While at that, it also associates the device with the phy using devres. @@ -749,8 +709,7 @@ EXPORT_SYMBOL_GPL(phy_create); * then, devres data is freed. */ struct phy *devm_phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data) + const struct phy_ops *ops) { struct phy **ptr, *phy; @@ -758,7 +717,7 @@ struct phy *devm_phy_create(struct device *dev, struct device_node *node, if (!ptr) return ERR_PTR(-ENOMEM); - phy = phy_create(dev, node, ops, init_data); + phy = phy_create(dev, node, ops); if (!IS_ERR(phy)) { *ptr = phy; devres_add(dev, ptr); diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 84f49e5..f86cbe6 100644 --- a/drivers/phy/phy-exynos-dp-video.c +++ b/drivers/phy/phy-exynos-dp-video.c @@ -112,7 +112,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev) match = of_match_node(exynos_dp_video_phy_of_match, dev->of_node); state->drvdata = match->data; - phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops, NULL); + phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create Display Port PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 6a9bef13..943e0f8 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -137,7 +137,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { struct phy *phy = devm_phy_create(dev, NULL, - &exynos_mipi_video_phy_ops, NULL); + &exynos_mipi_video_phy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create PHY %d\n", i); return PTR_ERR(phy); diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index f756aca..b3ca3bc 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -637,8 +637,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { struct phy *phy = devm_phy_create(dev, NULL, - &exynos5_usbdrd_phy_ops, - NULL); + &exynos5_usbdrd_phy_ops); if (IS_ERR(phy)) { dev_err(dev, "Failed to create usbdrd_phy phy\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c index 54cf4ae..bc858cc 100644 --- a/drivers/phy/phy-exynos5250-sata.c +++ b/drivers/phy/phy-exynos5250-sata.c @@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev) return ret; } - sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops, NULL); + sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops); if (IS_ERR(sata_phy->phy)) { clk_disable_unprepare(sata_phy->phyclk); dev_err(dev, "failed to create PHY\n"); diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c index d5d9780..a80ff9d 100644 --- a/drivers/phy/phy-hix5hd2-sata.c +++ b/drivers/phy/phy-hix5hd2-sata.c @@ -156,7 +156,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev) if (IS_ERR(priv->peri_ctrl)) priv->peri_ctrl = NULL; - phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops, NULL); + phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 87dcc9a..e34da13 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1231,7 +1231,7 @@ static int miphy28lp_probe(struct platform_device *pdev) miphy_dev->phys[port] = miphy_phy; - phy = devm_phy_create(&pdev->dev, child, &miphy28lp_ops, NULL); + phy = devm_phy_create(&pdev->dev, child, &miphy28lp_ops); if (IS_ERR(phy)) { dev_err(&pdev->dev, "failed to create PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 801afaf..239930e 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -593,7 +593,7 @@ static int miphy365x_probe(struct platform_device *pdev) miphy_dev->phys[port] = miphy_phy; - phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops, NULL); + phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops); if (IS_ERR(phy)) { dev_err(&pdev->dev, "failed to create PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c index d395558..03b94f9 100644 --- a/drivers/phy/phy-mvebu-sata.c +++ b/drivers/phy/phy-mvebu-sata.c @@ -101,7 +101,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev) if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); - phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops, NULL); + phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops); if (IS_ERR(phy)) return PTR_ERR(phy); diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index f091576..5dab3ec 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -260,7 +260,7 @@ static int omap_usb2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); pm_runtime_enable(phy->dev); - generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); + generic_phy = devm_phy_create(phy->dev, NULL, &ops); if (IS_ERR(generic_phy)) { pm_runtime_disable(phy->dev); return PTR_ERR(generic_phy); diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c index 7b3ddfb..4b243f7 100644 --- a/drivers/phy/phy-qcom-apq8064-sata.c +++ b/drivers/phy/phy-qcom-apq8064-sata.c @@ -228,8 +228,7 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev) if (IS_ERR(phy->mmio)) return PTR_ERR(phy->mmio); - generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops, - NULL); + generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops); if (IS_ERR(generic_phy)) { dev_err(dev, "%s: failed to create phy\n", __func__); return PTR_ERR(generic_phy); diff --git a/drivers/phy/phy-qcom-ipq806x-sata.c b/drivers/phy/phy-qcom-ipq806x-sata.c index 759b0bf..6f2fe26 100644 --- a/drivers/phy/phy-qcom-ipq806x-sata.c +++ b/drivers/phy/phy-qcom-ipq806x-sata.c @@ -150,8 +150,7 @@ static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev) if (IS_ERR(phy->mmio)) return PTR_ERR(phy->mmio); - generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops, - NULL); + generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops); if (IS_ERR(generic_phy)) { dev_err(dev, "%s: failed to create phy\n", __func__); return PTR_ERR(generic_phy); diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c index 2793af1..778276a 100644 --- a/drivers/phy/phy-rcar-gen2.c +++ b/drivers/phy/phy-rcar-gen2.c @@ -304,7 +304,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev) phy->select_value = select_value[channel_num][n]; phy->phy = devm_phy_create(dev, NULL, - &rcar_gen2_phy_ops, NULL); + &rcar_gen2_phy_ops); if (IS_ERR(phy->phy)) { dev_err(dev, "Failed to create PHY\n"); return PTR_ERR(phy->phy); diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c index 908949d..4a12f66 100644 --- a/drivers/phy/phy-samsung-usb2.c +++ b/drivers/phy/phy-samsung-usb2.c @@ -202,8 +202,7 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev) struct samsung_usb2_phy_instance *p = &drv->instances[i]; dev_dbg(dev, "Creating phy \"%s\"\n", label); - p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops, - NULL); + p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops); if (IS_ERR(p->phy)) { dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n", label); diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c index 5f4c586..9f47fae 100644 --- a/drivers/phy/phy-spear1310-miphy.c +++ b/drivers/phy/phy-spear1310-miphy.c @@ -227,7 +227,7 @@ static int spear1310_miphy_probe(struct platform_device *pdev) return -EINVAL; } - priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL); + priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops); if (IS_ERR(priv->phy)) { dev_err(dev, "failed to create SATA PCIe PHY\n"); return PTR_ERR(priv->phy); diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c index 1ecd094..e42bc20 100644 --- a/drivers/phy/phy-spear1340-miphy.c +++ b/drivers/phy/phy-spear1340-miphy.c @@ -259,7 +259,7 @@ static int spear1340_miphy_probe(struct platform_device *pdev) return PTR_ERR(priv->misc); } - priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL); + priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops); if (IS_ERR(priv->phy)) { dev_err(dev, "failed to create SATA PCIe PHY\n"); return PTR_ERR(priv->phy); diff --git a/drivers/phy/phy-stih407-usb.c b/drivers/phy/phy-stih407-usb.c index 42428d4..74f0fab 100644 --- a/drivers/phy/phy-stih407-usb.c +++ b/drivers/phy/phy-stih407-usb.c @@ -137,7 +137,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev) } phy_dev->param = res->start; - phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data, NULL); + phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data); if (IS_ERR(phy)) { dev_err(dev, "failed to create Display Port PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-stih41x-usb.c b/drivers/phy/phy-stih41x-usb.c index 9f16cb8..4ab581e 100644 --- a/drivers/phy/phy-stih41x-usb.c +++ b/drivers/phy/phy-stih41x-usb.c @@ -148,7 +148,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(phy_dev->clk); } - phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops, NULL); + phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create phy\n"); diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 6bd2b0c..fb02a67 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -298,7 +298,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(phy->pmu); } - phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops, NULL); + phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops); if (IS_ERR(phy->phy)) { dev_err(dev, "failed to create PHY %d\n", i); return PTR_ERR(phy->phy); diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index ab1e22d..c297b7a 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -399,7 +399,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); pm_runtime_enable(phy->dev); - generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); + generic_phy = devm_phy_create(phy->dev, NULL, &ops); if (IS_ERR(generic_phy)) return PTR_ERR(generic_phy); diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index c45a3aa..d19e4a0 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -678,7 +678,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) otg->set_host = twl4030_set_host; otg->set_peripheral = twl4030_set_peripheral; - phy = devm_phy_create(twl->dev, NULL, &ops, NULL); + phy = devm_phy_create(twl->dev, NULL, &ops); if (IS_ERR(phy)) { dev_dbg(&pdev->dev, "Failed to create PHY\n"); return PTR_ERR(phy); diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index f8a51b1..29214a3 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev) ctx->dev = &pdev->dev; platform_set_drvdata(pdev, ctx); - ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops, NULL); + ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops); if (IS_ERR(ctx->phy)) { dev_dbg(&pdev->dev, "Failed to create PHY\n"); rc = PTR_ERR(ctx->phy); diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c index 1631ec9..a84299b 100644 --- a/drivers/pinctrl/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/pinctrl-tegra-xusb.c @@ -910,7 +910,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) goto reset; } - phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops, NULL); + phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops); if (IS_ERR(phy)) { err = PTR_ERR(phy); goto unregister; @@ -919,7 +919,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy; phy_set_drvdata(phy, padctl); - phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops, NULL); + phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops); if (IS_ERR(phy)) { err = PTR_ERR(phy); goto unregister; diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 849284e..a0197fa 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -61,7 +61,6 @@ struct phy { struct device dev; int id; const struct phy_ops *ops; - struct phy_init_data *init_data; struct mutex mutex; int init_count; int power_count; @@ -84,32 +83,6 @@ struct phy_provider { struct of_phandle_args *args); }; -/** - * struct phy_consumer - represents the phy consumer - * @dev_name: the device name of the controller that will use this PHY device - * @port: name given to the consumer port - */ -struct phy_consumer { - const char *dev_name; - const char *port; -}; - -/** - * struct phy_init_data - contains the list of PHY consumers - * @num_consumers: number of consumers for this PHY device - * @consumers: list of PHY consumers - */ -struct phy_init_data { - unsigned int num_consumers; - struct phy_consumer *consumers; -}; - -#define PHY_CONSUMER(_dev_name, _port) \ -{ \ - .dev_name = _dev_name, \ - .port = _port, \ -} - struct phy_lookup { struct list_head node; const char *dev_id; @@ -166,10 +139,9 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id); struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args *args); struct phy *phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data); + const struct phy_ops *ops); struct phy *devm_phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, struct phy_init_data *init_data); + const struct phy_ops *ops); void phy_destroy(struct phy *phy); void devm_phy_destroy(struct device *dev, struct phy *phy); struct phy_provider *__of_phy_provider_register(struct device *dev, @@ -310,16 +282,14 @@ static inline struct phy *of_phy_simple_xlate(struct device *dev, static inline struct phy *phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data) + const struct phy_ops *ops) { return ERR_PTR(-ENOSYS); } static inline struct phy *devm_phy_create(struct device *dev, struct device_node *node, - const struct phy_ops *ops, - struct phy_init_data *init_data) + const struct phy_ops *ops) { return ERR_PTR(-ENOSYS); } -- cgit v0.10.2 From 08f871a3aca252b15107fc37dedcdacbac80fdb5 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 19 Nov 2014 17:28:23 +0200 Subject: usb: dwc3: host: convey the PHYs to xhci On some platforms a PHY may need to be handled also in the host controller driver. Exynos5420 SoC requires some "PHY tuning" based on the USB speed. This patch delivers dwc3's PHYs to the xhci platform device when it's created. Signed-off-by: Heikki Krogerus Tested-by: Vivek Gautam Acked-by: Felipe Balbi Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index dcb8ca0..12bfd3c 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -29,8 +29,7 @@ int dwc3_host_init(struct dwc3 *dwc) xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); if (!xhci) { dev_err(dwc->dev, "couldn't allocate xHCI device\n"); - ret = -ENOMEM; - goto err0; + return -ENOMEM; } dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); @@ -60,22 +59,33 @@ int dwc3_host_init(struct dwc3 *dwc) goto err1; } + phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy", + dev_name(&xhci->dev)); + phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy", + dev_name(&xhci->dev)); + ret = platform_device_add(xhci); if (ret) { dev_err(dwc->dev, "failed to register xHCI device\n"); - goto err1; + goto err2; } return 0; - +err2: + phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy", + dev_name(&xhci->dev)); + phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy", + dev_name(&xhci->dev)); err1: platform_device_put(xhci); - -err0: return ret; } void dwc3_host_exit(struct dwc3 *dwc) { + phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy", + dev_name(&dwc->xhci->dev)); + phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy", + dev_name(&dwc->xhci->dev)); platform_device_unregister(dwc->xhci); } -- cgit v0.10.2 From 9bde18c1b5d2c9a1b90fc0f3bbe1a314194f6fdf Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:48 +0530 Subject: phy: exynos5-usbdrd: Add pipe-clk, utmi-clk and itp-clk support Exynos7 SoC has now separate gate control for 125MHz pipe3 phy clock, as well as 60MHz utmi phy clock. Additionally, separate gate control is available for the clock used for ITP (Isochronous Transfer Packet) generation. So get the same and control in the phy-exynos5-usbdrd driver. Suggested-by: Anton Tikhomirov Signed-off-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index 15e0f2c..d5bad92 100644 --- a/Documentation/devicetree/bindings/phy/samsung-phy.txt +++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt @@ -128,6 +128,7 @@ Required properties: - compatible : Should be set to one of the following supported values: - "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC, - "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC. + - "samsung,exynos7-usbdrd-phy" - for exynos7 SoC. - reg : Register offset and length of USB DRD PHY register set; - clocks: Clock IDs array as required by the controller - clock-names: names of clocks correseponding to IDs in the clock property; @@ -138,6 +139,11 @@ Required properties: PHY operations, associated by phy name. It is used to determine bit values for clock settings register. For Exynos5420 this is given as 'sclk_usbphy30' in CMU. + - optional clocks: Exynos7 SoC has now following additional + gate clocks available: + - phy_pipe: for PIPE3 phy + - phy_utmi: for UTMI+ phy + - itp: for ITP generation - samsung,pmu-syscon: phandle for PMU system controller interface, used to control pmu registers for power isolation. - #phy-cells : from the generic PHY bindings, must be 1; diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index b3ca3bc..99ba56d 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -141,6 +141,7 @@ struct exynos5_usbdrd_phy_drvdata { const struct exynos5_usbdrd_phy_config *phy_cfg; u32 pmu_offset_usbdrd0_phy; u32 pmu_offset_usbdrd1_phy; + bool has_common_clk_gate; }; /** @@ -148,6 +149,9 @@ struct exynos5_usbdrd_phy_drvdata { * @dev: pointer to device instance of this platform device * @reg_phy: usb phy controller register memory base * @clk: phy clock for register access + * @pipeclk: clock for pipe3 phy + * @utmiclk: clock for utmi+ phy + * @itpclk: clock for ITP generation * @drv_data: pointer to SoC level driver data structure * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY * instances each with its 'phy' and 'phy_cfg'. @@ -155,12 +159,14 @@ struct exynos5_usbdrd_phy_drvdata { * reference clocks' for SS and HS operations * @ref_clk: reference clock to PHY block from which PHY's * operational clocks are derived - * @ref_rate: rate of above reference clock */ struct exynos5_usbdrd_phy { struct device *dev; void __iomem *reg_phy; struct clk *clk; + struct clk *pipeclk; + struct clk *utmiclk; + struct clk *itpclk; const struct exynos5_usbdrd_phy_drvdata *drv_data; struct phy_usb_instance { struct phy *phy; @@ -447,6 +453,11 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); clk_prepare_enable(phy_drd->ref_clk); + if (!phy_drd->drv_data->has_common_clk_gate) { + clk_prepare_enable(phy_drd->pipeclk); + clk_prepare_enable(phy_drd->utmiclk); + clk_prepare_enable(phy_drd->itpclk); + } /* Enable VBUS supply */ if (phy_drd->vbus) { @@ -464,6 +475,11 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) fail_vbus: clk_disable_unprepare(phy_drd->ref_clk); + if (!phy_drd->drv_data->has_common_clk_gate) { + clk_disable_unprepare(phy_drd->itpclk); + clk_disable_unprepare(phy_drd->utmiclk); + clk_disable_unprepare(phy_drd->pipeclk); + } return ret; } @@ -483,6 +499,11 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy) regulator_disable(phy_drd->vbus); clk_disable_unprepare(phy_drd->ref_clk); + if (!phy_drd->drv_data->has_common_clk_gate) { + clk_disable_unprepare(phy_drd->itpclk); + clk_disable_unprepare(phy_drd->pipeclk); + clk_disable_unprepare(phy_drd->utmiclk); + } return 0; } @@ -506,6 +527,57 @@ static struct phy_ops exynos5_usbdrd_phy_ops = { .owner = THIS_MODULE, }; +static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd) +{ + unsigned long ref_rate; + int ret; + + phy_drd->clk = devm_clk_get(phy_drd->dev, "phy"); + if (IS_ERR(phy_drd->clk)) { + dev_err(phy_drd->dev, "Failed to get phy clock\n"); + return PTR_ERR(phy_drd->clk); + } + + phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref"); + if (IS_ERR(phy_drd->ref_clk)) { + dev_err(phy_drd->dev, "Failed to get phy reference clock\n"); + return PTR_ERR(phy_drd->ref_clk); + } + ref_rate = clk_get_rate(phy_drd->ref_clk); + + ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); + if (ret) { + dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", + ref_rate); + return ret; + } + + if (!phy_drd->drv_data->has_common_clk_gate) { + phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe"); + if (IS_ERR(phy_drd->pipeclk)) { + dev_info(phy_drd->dev, + "PIPE3 phy operational clock not specified\n"); + phy_drd->pipeclk = NULL; + } + + phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi"); + if (IS_ERR(phy_drd->utmiclk)) { + dev_info(phy_drd->dev, + "UTMI phy operational clock not specified\n"); + phy_drd->utmiclk = NULL; + } + + phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp"); + if (IS_ERR(phy_drd->itpclk)) { + dev_info(phy_drd->dev, + "ITP clock from main OSC not specified\n"); + phy_drd->itpclk = NULL; + } + } + + return 0; +} + static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { { .id = EXYNOS5_DRDPHY_UTMI, @@ -525,11 +597,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, + .has_common_clk_gate = true, }; static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .has_common_clk_gate = true, +}; + +static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = { + .phy_cfg = phy_cfg_exynos5, + .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .has_common_clk_gate = false, }; static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { @@ -539,6 +619,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { }, { .compatible = "samsung,exynos5420-usbdrd-phy", .data = &exynos5420_usbdrd_phy + }, { + .compatible = "samsung,exynos7-usbdrd-phy", + .data = &exynos7_usbdrd_phy }, { }, }; @@ -555,7 +638,6 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) const struct exynos5_usbdrd_phy_drvdata *drv_data; struct regmap *reg_pmu; u32 pmu_offset; - unsigned long ref_rate; int i, ret; int channel; @@ -576,23 +658,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) drv_data = match->data; phy_drd->drv_data = drv_data; - phy_drd->clk = devm_clk_get(dev, "phy"); - if (IS_ERR(phy_drd->clk)) { - dev_err(dev, "Failed to get clock of phy controller\n"); - return PTR_ERR(phy_drd->clk); - } - - phy_drd->ref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(phy_drd->ref_clk)) { - dev_err(dev, "Failed to get reference clock of usbdrd phy\n"); - return PTR_ERR(phy_drd->ref_clk); - } - ref_rate = clk_get_rate(phy_drd->ref_clk); - - ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); + ret = exynos5_usbdrd_phy_clk_handle(phy_drd); if (ret) { - dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", - ref_rate); + dev_err(dev, "Failed to initialize clocks\n"); return ret; } -- cgit v0.10.2 From a6867836db35d1e178744166765b57288bf4e8e5 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:49 +0530 Subject: phy: exynos5-usbdrd: Add facility for VBUS-BOOST-5V supply Some Exynos boards have a separate regulator controlling a Boost 5V supply which goes as input for VBUS regulator. So adding a control for the same in driver, to enable vbus supply on the port. Signed-off-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index 99ba56d..0437401 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -159,6 +159,8 @@ struct exynos5_usbdrd_phy_drvdata { * reference clocks' for SS and HS operations * @ref_clk: reference clock to PHY block from which PHY's * operational clocks are derived + * vbus: VBUS regulator for phy + * vbus_boost: Boost regulator for VBUS present on few Exynos boards */ struct exynos5_usbdrd_phy { struct device *dev; @@ -178,6 +180,7 @@ struct exynos5_usbdrd_phy { u32 extrefclk; struct clk *ref_clk; struct regulator *vbus; + struct regulator *vbus_boost; }; static inline @@ -460,11 +463,20 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) } /* Enable VBUS supply */ + if (phy_drd->vbus_boost) { + ret = regulator_enable(phy_drd->vbus_boost); + if (ret) { + dev_err(phy_drd->dev, + "Failed to enable VBUS boost supply\n"); + goto fail_vbus; + } + } + if (phy_drd->vbus) { ret = regulator_enable(phy_drd->vbus); if (ret) { dev_err(phy_drd->dev, "Failed to enable VBUS supply\n"); - goto fail_vbus; + goto fail_vbus_boost; } } @@ -473,6 +485,10 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) return 0; +fail_vbus_boost: + if (phy_drd->vbus_boost) + regulator_disable(phy_drd->vbus_boost); + fail_vbus: clk_disable_unprepare(phy_drd->ref_clk); if (!phy_drd->drv_data->has_common_clk_gate) { @@ -497,6 +513,8 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy) /* Disable VBUS supply */ if (phy_drd->vbus) regulator_disable(phy_drd->vbus); + if (phy_drd->vbus_boost) + regulator_disable(phy_drd->vbus_boost); clk_disable_unprepare(phy_drd->ref_clk); if (!phy_drd->drv_data->has_common_clk_gate) { @@ -690,7 +708,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) break; } - /* Get Vbus regulator */ + /* Get Vbus regulators */ phy_drd->vbus = devm_regulator_get(dev, "vbus"); if (IS_ERR(phy_drd->vbus)) { ret = PTR_ERR(phy_drd->vbus); @@ -701,6 +719,16 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) phy_drd->vbus = NULL; } + phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost"); + if (IS_ERR(phy_drd->vbus_boost)) { + ret = PTR_ERR(phy_drd->vbus_boost); + if (ret == -EPROBE_DEFER) + return ret; + + dev_warn(dev, "Failed to get VBUS boost supply regulator\n"); + phy_drd->vbus_boost = NULL; + } + dev_vdbg(dev, "Creating usbdrd_phy phy\n"); for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { -- cgit v0.10.2 From 556186a02c441e8fb03aa4c87d39bdc8ef95820e Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Fri, 21 Nov 2014 19:05:50 +0530 Subject: phy: exynos7-usbdrd: Update dependency for ARCH_EXYNOS This PHY controller is also present on Exynos7 platform in arch-exynos family. So PHY_EXYNOS5_USBDRD should now depend on ARCH_EXYNOS. Signed-off-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 4144d25..96d43d5 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -208,7 +208,7 @@ config PHY_EXYNOS5250_USB2 config PHY_EXYNOS5_USBDRD tristate "Exynos5 SoC series USB DRD PHY driver" - depends on ARCH_EXYNOS5 && OF + depends on ARCH_EXYNOS && OF depends on HAS_IOMEM depends on USB_DWC3_EXYNOS select GENERIC_PHY -- cgit v0.10.2 From ef24d749f2c8713d333b3e3c4b1d84fbc25bc133 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 24 Nov 2014 22:31:23 +0800 Subject: usb: gadget: ss_ep_in_comp_desc can be static drivers/usb/gadget/legacy/printer.c:222:34: sparse: symbol 'ss_ep_in_comp_desc' was not declared. Should it be static? drivers/usb/gadget/legacy/printer.c:234:34: sparse: symbol 'ss_ep_out_comp_desc' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index e0cf1b0..90545980 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -219,7 +219,7 @@ static struct usb_endpoint_descriptor ss_ep_in_desc = { .wMaxPacketSize = cpu_to_le16(1024), }; -struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = { .bLength = sizeof(ss_ep_in_comp_desc), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, }; @@ -231,7 +231,7 @@ static struct usb_endpoint_descriptor ss_ep_out_desc = { .wMaxPacketSize = cpu_to_le16(1024), }; -struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = { .bLength = sizeof(ss_ep_out_comp_desc), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, }; -- cgit v0.10.2 From 6cd6159d4b1695427105d4b8b2e355e1d0509ff4 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 22 Nov 2014 15:56:47 +0100 Subject: usb: dwc3: return error code from the most recent call Copy-paste error from the previous block of error handling code. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e,e1; @@ if (IS_ERR(e)) { ... ( ret = PTR_ERR(e); | * ret = PTR_ERR(e1); ) ... return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index c7602b5..4a1a543 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -243,7 +243,7 @@ static int st_dwc3_probe(struct platform_device *pdev) dwc3_data->rstc_rst = devm_reset_control_get(dev, "softreset"); if (IS_ERR(dwc3_data->rstc_rst)) { dev_err(&pdev->dev, "could not get reset controller\n"); - ret = PTR_ERR(dwc3_data->rstc_pwrdn); + ret = PTR_ERR(dwc3_data->rstc_rst); goto undo_powerdown; } -- cgit v0.10.2 From d908f8478a8d18e66c80a12adb27764920c1f1ca Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 20 Nov 2014 14:54:35 +0100 Subject: cdc-acm: memory leak in error case If probe() fails not only the attributes need to be removed but also the memory freed. Reported-by: Ahmed Tamrawi Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index c74fd3a..6c6a5c4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1473,6 +1473,7 @@ alloc_fail8: &dev_attr_wCountryCodes); device_remove_file(&acm->control->dev, &dev_attr_iCountryCodeRelDate); + kfree(acm->country_codes); } device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); alloc_fail7: -- cgit v0.10.2 From 403dff4e2c94f275e24fd85f40b2732ffec268a1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 7 Nov 2014 08:48:15 -0800 Subject: USB: cdc-acm: check for valid interfaces We need to check that we have both a valid data and control inteface for both types of headers (union and not union.) References: https://bugzilla.kernel.org/show_bug.cgi?id=83551 Reported-by: Simon Schubert <2+kernel@0x2c.org> Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 6c6a5c4..546a17e8 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1195,10 +1195,11 @@ next_desc: } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); - if (!control_interface || !data_interface) { - dev_dbg(&intf->dev, "no interfaces\n"); - return -ENODEV; - } + } + + if (!control_interface || !data_interface) { + dev_dbg(&intf->dev, "no interfaces\n"); + return -ENODEV; } if (data_interface_num != call_interface_num) -- cgit v0.10.2 From 782614b80edf97dad35fa93f9981883c3e117c29 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Thu, 13 Nov 2014 00:49:50 +0100 Subject: usb: ehci-orion: enable big-endian support This commit fixes ehci-orion operation in big-endian mode by enabling byteswap when accessing registers using 'rdl' and 'wrl' macros. Signed-off-by: Grzegorz Jaszczyk Signed-off-by: Marcin Wojtas Reviewed-by: Gregory CLEMENT Tested-by: Thomas Petazzoni Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 36b4657..3c76489 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -25,8 +25,8 @@ #include "ehci.h" -#define rdl(off) __raw_readl(hcd->regs + (off)) -#define wrl(off, val) __raw_writel((val), hcd->regs + (off)) +#define rdl(off) readl_relaxed(hcd->regs + (off)) +#define wrl(off, val) writel_relaxed((val), hcd->regs + (off)) #define USB_CMD 0x140 #define USB_MODE 0x1a8 -- cgit v0.10.2 From eab77694098469d80e1186fdda9f965045730a3e Mon Sep 17 00:00:00 2001 From: Mark Knibbs Date: Fri, 7 Nov 2014 22:02:19 +0000 Subject: storage: Enable multi-target mode as vendor driver does for SCM eUSCSI bridge usb_stor_euscsi_init() enables multi-target mode for SCM eUSB SCSI bridge devices. The control message it sends has wLength = 1 and the byte sent is 0x01. While that works, the SCM Windows driver does it with wLength = 0. We may as well match what the SCM driver does. Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 73f125e..31fa2e9 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -49,10 +49,9 @@ int usb_stor_euscsi_init(struct us_data *us) int result; usb_stor_dbg(us, "Attempting to init eUSCSI bridge...\n"); - us->iobuf[0] = 0x1; result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, - 0x01, 0x0, us->iobuf, 0x1, 5 * HZ); + 0x01, 0x0, NULL, 0x0, 5 * HZ); usb_stor_dbg(us, "-- result is %d\n", result); return 0; -- cgit v0.10.2 From 646a3843177b2ae0cb81813ec0f830fe64e81bf1 Mon Sep 17 00:00:00 2001 From: Mark Knibbs Date: Sat, 8 Nov 2014 21:39:55 +0000 Subject: storage: Fix bus scan and multi-LUN support for SCM eUSCSI devices This patch does two things for SCM eUSCSI USB-SCSI converters: 1. SCM eUSCSI bridge devices are hard-wired to use SCSI ID 7. On connecting the converter, access to that ID is attempted during the bus scan. Asking the converter to issue INQUIRY commands to itself isn't very polite and wastes time. Set this_id to 7 so __scsi_scan_target() skips it in the scan. 2. Enable multi-LUN support. eUSCSI devices don't support Get Max LUN requests, returning an error (-32). [Different targets could have different numbers of LUNs, so it wouldn't make sense to return a particular value in response to Get Max LUN.] usb_stor_scan_dwork() does this: /* For bulk-only devices, determine the max LUN value */ if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) { mutex_lock(&us->dev_mutex); us->max_lun = usb_stor_Bulk_max_lun(us); mutex_unlock(&us->dev_mutex); It avoids calling usb_stor_Bulk_max_lun() if US_FL_SINGLE_LUN, but not for US_FL_SCM_MULT_TARG. Since usb_stor_Bulk_max_lun() returns 0 in the error case, us->max_lun was always set to 0. [If the user doesn't want multi-LUN support (perhaps there are SCSI devices which respond to commands on all LUNs?), the US_FL_SINGLE_LUN quirk can be specified on the kernel command line.] Signed-off-by: Mark Knibbs Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 9d66ce6..d468d02 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -884,7 +884,9 @@ static void usb_stor_scan_dwork(struct work_struct *work) dev_dbg(dev, "starting scan\n"); /* For bulk-only devices, determine the max LUN value */ - if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) { + if (us->protocol == USB_PR_BULK && + !(us->fflags & US_FL_SINGLE_LUN) && + !(us->fflags & US_FL_SCM_MULT_TARG)) { mutex_lock(&us->dev_mutex); us->max_lun = usb_stor_Bulk_max_lun(us); mutex_unlock(&us->dev_mutex); @@ -983,21 +985,31 @@ int usb_stor_probe2(struct us_data *us) usb_stor_dbg(us, "Transport: %s\n", us->transport_name); usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name); + if (us->fflags & US_FL_SCM_MULT_TARG) { + /* + * SCM eUSCSI bridge devices can have different numbers + * of LUNs on different targets; allow all to be probed. + */ + us->max_lun = 7; + /* The eUSCSI itself has ID 7, so avoid scanning that */ + us_to_host(us)->this_id = 7; + /* max_id is 8 initially, so no need to set it here */ + } else { + /* In the normal case there is only a single target */ + us_to_host(us)->max_id = 1; + /* + * Like Windows, we won't store the LUN bits in CDB[1] for + * SCSI-2 devices using the Bulk-Only transport (even though + * this violates the SCSI spec). + */ + if (us->transport == usb_stor_Bulk_transport) + us_to_host(us)->no_scsi2_lun_in_cdb = 1; + } + /* fix for single-lun devices */ if (us->fflags & US_FL_SINGLE_LUN) us->max_lun = 0; - if (!(us->fflags & US_FL_SCM_MULT_TARG)) - us_to_host(us)->max_id = 1; - - /* - * Like Windows, we won't store the LUN bits in CDB[1] for SCSI-2 - * devices using the Bulk-Only transport (even though this violates - * the SCSI spec). - */ - if (us->transport == usb_stor_Bulk_transport) - us_to_host(us)->no_scsi2_lun_in_cdb = 1; - /* Find the endpoints and calculate pipe values */ result = get_pipes(us); if (result) -- cgit v0.10.2 From 0bfed505447dd5a47e6097a32d216d7df7cf70aa Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 20 Nov 2014 18:34:01 +0100 Subject: host: ehci-w90x900: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index 4717bf2..c305732 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -75,8 +75,10 @@ static int usb_w90x900_probe(const struct hc_driver *driver, __raw_writel(val, ehci->regs+PHY1_CTR); irq = platform_get_irq(pdev, 0); - if (irq < 0) + if (irq < 0) { + retval = irq; goto err2; + } retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval != 0) -- cgit v0.10.2 From 03f3df817dd3bf988c6d56e10e99b5b4553f5044 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 21 Nov 2014 16:33:18 +0100 Subject: USB-IP: Deletion of unnecessary checks before the function call "usb_put_dev" The usb_put_dev() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Valentina Manea Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index c02374b..cc1b03e 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -518,8 +518,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, dev_info(dev, "SetAddress Request (%d) to port %d\n", ctrlreq->wValue, vdev->rhport); - if (vdev->udev) - usb_put_dev(vdev->udev); + usb_put_dev(vdev->udev); vdev->udev = usb_get_dev(urb->dev); spin_lock(&vdev->ud.lock); @@ -539,8 +538,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, usbip_dbg_vhci_hc( "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n"); - if (vdev->udev) - usb_put_dev(vdev->udev); + usb_put_dev(vdev->udev); vdev->udev = usb_get_dev(urb->dev); goto out; @@ -831,8 +829,7 @@ static void vhci_device_reset(struct usbip_device *ud) vdev->speed = 0; vdev->devid = 0; - if (vdev->udev) - usb_put_dev(vdev->udev); + usb_put_dev(vdev->udev); vdev->udev = NULL; if (ud->tcp_socket) { -- cgit v0.10.2 From bb2d43e0919ad89077dc756167c2bcc3e4cc97ab Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 21 Nov 2014 15:50:44 +0100 Subject: USB-SIS: Deletion of an unnecessary check before the function call "usb_put_dev" The usb_put_dev() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 633caf6..022dc00 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2472,8 +2472,7 @@ sisusb_delete(struct kref *kref) if (!sisusb) return; - if (sisusb->sisusb_dev) - usb_put_dev(sisusb->sisusb_dev); + usb_put_dev(sisusb->sisusb_dev); sisusb->sisusb_dev = NULL; sisusb_free_buffers(sisusb); -- cgit v0.10.2 From f910b6cba27af4c5e1b0de1225a268448c2e82be Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 21 Nov 2014 15:20:12 +0100 Subject: USB: PCI-quirks: Deletion of unnecessary checks before the function call "pci_dev_put" The pci_dev_put() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 2f3aceb..dd483c1 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -233,10 +233,8 @@ commit: spin_unlock_irqrestore(&amd_lock, flags); - if (info.nb_dev) - pci_dev_put(info.nb_dev); - if (info.smbus_dev) - pci_dev_put(info.smbus_dev); + pci_dev_put(info.nb_dev); + pci_dev_put(info.smbus_dev); } else { /* no race - commit the result */ @@ -447,10 +445,8 @@ void usb_amd_dev_put(void) spin_unlock_irqrestore(&amd_lock, flags); - if (nb) - pci_dev_put(nb); - if (smbus) - pci_dev_put(smbus); + pci_dev_put(nb); + pci_dev_put(smbus); } EXPORT_SYMBOL_GPL(usb_amd_dev_put); -- cgit v0.10.2 From 23fba80a9b1a36654078e29f4df73f07793154fa Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 24 Nov 2014 08:39:10 -0600 Subject: usb: gadget: udc: lpc32xx: remove unnecessary NULL check debugfs_remove() is safe against NULL pointers, so let's remove the unnecessary NULL check before calling it. Acked-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 4be497d..9765296 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -582,8 +582,7 @@ static void create_debug_file(struct lpc32xx_udc *udc) static void remove_debug_file(struct lpc32xx_udc *udc) { - if (udc->pde) - debugfs_remove(udc->pde); + debugfs_remove(udc->pde); } #else -- cgit v0.10.2 From 4db9917b641d18d24932ee2ec95b23a1e26c3f7e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 24 Nov 2014 08:40:01 -0600 Subject: usb: gadget: udc: pxa25x: remove unnecessary NULL check debugfs_remove() is safe against NULL pointers, so let's remove the unnecessary NULL check before calling it. Reviewed-by: Robert Jarzmik Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 8664b99..347a05b 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1134,11 +1134,7 @@ static const struct file_operations debug_fops = { dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \ S_IRUGO, NULL, dev, &debug_fops); \ } while (0) -#define remove_debug_files(dev) \ - do { \ - if (dev->debugfs_udc) \ - debugfs_remove(dev->debugfs_udc); \ - } while (0) +#define remove_debug_files(dev) debugfs_remove(dev->debugfs_udc) #else /* !CONFIG_USB_GADGET_DEBUG_FILES */ -- cgit v0.10.2 From da9f3289c74f93b63c5ca741caa4e2d728ccafba Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 19 Nov 2014 12:37:53 -0200 Subject: usb: dwc2: Fix build warning when CONFIG_PM_SLEEP=n Building with bcm2835_defconfig, which has CONFIG_PM_SLEEP=n causes the following build warning: drivers/usb/dwc2/platform.c:227:12: warning: 'dwc2_suspend' defined but not used [-Wunused-function] drivers/usb/dwc2/platform.c:237:12: warning: 'dwc2_resume' defined but not used [-Wunused-function] Annotate these functions with '__maybe_unused' to prevent the warnings. Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index ec5658a..6a795aa 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -226,7 +226,7 @@ static int dwc2_driver_probe(struct platform_device *dev) return retval; } -static int dwc2_suspend(struct device *dev) +static int __maybe_unused dwc2_suspend(struct device *dev) { struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; @@ -236,7 +236,7 @@ static int dwc2_suspend(struct device *dev) return ret; } -static int dwc2_resume(struct device *dev) +static int __maybe_unused dwc2_resume(struct device *dev) { struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; -- cgit v0.10.2 From f415fbd17f0438913339fd043779f306ee3587b0 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 24 Nov 2014 11:02:11 -0600 Subject: usb: dwc2: remove early return on clock query Since we have assigned clk=NULL, which is a valid clk, we should not be returning when a clock node is not provide. Instead, we should return only when we cannot enable the clock. Signed-off-by: Dinh Nguyen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 05b0522..407f55c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3451,8 +3451,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) hsotg->clk = devm_clk_get(dev, "otg"); if (IS_ERR(hsotg->clk)) { hsotg->clk = NULL; - dev_err(dev, "cannot get otg clock\n"); - return PTR_ERR(hsotg->clk); + dev_dbg(dev, "cannot get otg clock\n"); } hsotg->gadget.max_speed = USB_SPEED_HIGH; @@ -3461,7 +3460,12 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) /* reset the system */ - clk_prepare_enable(hsotg->clk); + ret = clk_prepare_enable(hsotg->clk); + if (ret) { + dev_err(dev, "failed to enable otg clk\n"); + goto err_clk; + } + /* regulators */ -- cgit v0.10.2 From b20f3f9e8e537ee25bfb86940903cba4b5abbde6 Mon Sep 17 00:00:00 2001 From: Kiran Raparthy Date: Mon, 24 Nov 2014 22:54:59 +0530 Subject: usb: phy: Handle per-PHY event for connnect and disconnect events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When usb is connected and enumerated in device mode or when usb is disconnected, call usb_phy_set_event() from phy drivers to handle per-PHY event. [ toddpoynor@google.com : Original patch in Android ] Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org Cc: linux-usb@vger.kernel.org Cc: Android Kernel Team Cc: John Stultz Cc: Sumit Semwal Cc: Arve HjønnevÃ¥g Cc: Benoit Goby Cc: Todd Poynor Signed-off-by: Kiran Raparthy Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 30c96f0..8cd7d19 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -445,6 +445,7 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab, event = UX500_MUSB_NONE; /* Fallback to default B_IDLE as nothing is connected. */ ab->phy.otg->state = OTG_STATE_B_IDLE; + usb_phy_set_event(&ab->phy, USB_EVENT_NONE); break; case USB_LINK_ACA_RID_C_NM_9540: @@ -459,12 +460,14 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab, ab8500_usb_peri_phy_en(ab); atomic_notifier_call_chain(&ab->phy.notifier, UX500_MUSB_PREPARE, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED); } if (ab->mode == USB_IDLE) { ab->mode = USB_PERIPHERAL; ab8500_usb_peri_phy_en(ab); atomic_notifier_call_chain(&ab->phy.notifier, UX500_MUSB_PREPARE, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED); } if (event != UX500_MUSB_RIDC) event = UX500_MUSB_VBUS; @@ -500,6 +503,7 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab, event = UX500_MUSB_CHARGER; atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER); break; case USB_LINK_PHYEN_NO_VBUS_NO_IDGND_9540: @@ -524,6 +528,7 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab, ab->mode = USB_IDLE; ab->phy.otg->default_a = false; ab->vbus_draw = 0; + usb_phy_set_event(&ab->phy, USB_EVENT_NONE); } } break; @@ -583,6 +588,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab, * is connected */ ab->phy.otg->state = OTG_STATE_B_IDLE; + usb_phy_set_event(&ab->phy, USB_EVENT_NONE); break; case USB_LINK_ACA_RID_C_NM_8540: @@ -596,6 +602,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab, ab8500_usb_peri_phy_en(ab); atomic_notifier_call_chain(&ab->phy.notifier, UX500_MUSB_PREPARE, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED); } if (event != UX500_MUSB_RIDC) event = UX500_MUSB_VBUS; @@ -624,6 +631,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab, event = UX500_MUSB_CHARGER; atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER); break; case USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8540: @@ -646,6 +654,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab, ab->mode = USB_IDLE; ab->phy.otg->default_a = false; ab->vbus_draw = 0; + usb_phy_set_event(&ab->phy, USB_EVENT_NONE); } break; @@ -692,6 +701,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab, * is connected */ ab->phy.otg->state = OTG_STATE_B_IDLE; + usb_phy_set_event(&ab->phy, USB_EVENT_NONE); break; case USB_LINK_ACA_RID_C_NM_8505: @@ -705,6 +715,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab, ab8500_usb_peri_phy_en(ab); atomic_notifier_call_chain(&ab->phy.notifier, UX500_MUSB_PREPARE, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED); } if (event != UX500_MUSB_RIDC) event = UX500_MUSB_VBUS; @@ -732,6 +743,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab, event = UX500_MUSB_CHARGER; atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER); break; default: @@ -775,6 +787,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, event = UX500_MUSB_NONE; /* Fallback to default B_IDLE as nothing is connected */ ab->phy.otg->state = OTG_STATE_B_IDLE; + usb_phy_set_event(&ab->phy, USB_EVENT_NONE); break; case USB_LINK_ACA_RID_C_NM_8500: @@ -792,6 +805,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, ab8500_usb_peri_phy_en(ab); atomic_notifier_call_chain(&ab->phy.notifier, UX500_MUSB_PREPARE, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED); } if (event != UX500_MUSB_RIDC) event = UX500_MUSB_VBUS; @@ -818,6 +832,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, event = UX500_MUSB_CHARGER; atomic_notifier_call_chain(&ab->phy.notifier, event, &ab->vbus_draw); + usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER); break; case USB_LINK_RESERVED_8500: diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 9fcf19b..5451172 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -134,6 +134,7 @@ static void gpio_vbus_work(struct work_struct *work) atomic_notifier_call_chain(&gpio_vbus->phy.notifier, status, gpio_vbus->phy.otg->gadget); + usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_ENUMERATED); } else { /* optionally disable D+ pullup */ if (gpio_is_valid(gpio)) @@ -148,6 +149,7 @@ static void gpio_vbus_work(struct work_struct *work) atomic_notifier_call_chain(&gpio_vbus->phy.notifier, status, gpio_vbus->phy.otg->gadget); + usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_NONE); } } diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 81d934f..b234d46 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -441,10 +441,12 @@ run: mv_otg_start_periphrals(mvotg, 0); mv_otg_reset(mvotg); mv_otg_disable(mvotg); + usb_phy_set_event(&mvotg->phy, USB_EVENT_NONE); break; case OTG_STATE_B_PERIPHERAL: mv_otg_enable(mvotg); mv_otg_start_periphrals(mvotg, 1); + usb_phy_set_event(&mvotg->phy, USB_EVENT_ENUMERATED); break; case OTG_STATE_A_IDLE: otg->default_a = 1; diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index 9cabc1a..d391c79 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -87,6 +87,7 @@ static void check_vbus_state(struct tahvo_usb *tu) if (tu->phy.otg->gadget) usb_gadget_vbus_connect(tu->phy.otg->gadget); tu->phy.otg->state = OTG_STATE_B_PERIPHERAL; + usb_phy_set_event(&tu->phy, USB_EVENT_ENUMERATED); break; case OTG_STATE_A_IDLE: /* @@ -105,6 +106,7 @@ static void check_vbus_state(struct tahvo_usb *tu) if (tu->phy.otg->gadget) usb_gadget_vbus_disconnect(tu->phy.otg->gadget); tu->phy.otg->state = OTG_STATE_B_IDLE; + usb_phy_set_event(&tu->phy, USB_EVENT_NONE); break; case OTG_STATE_A_HOST: tu->phy.otg->state = OTG_STATE_A_IDLE; -- cgit v0.10.2 From 5450ac88dcf09b258d0404b45316583806799ef4 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:04:59 -0800 Subject: usb: musb: Add function pointers for IO access functions MUSB currently breaks badly if we try to build in support for multiple platforms. This also happens if done as loadable modules, which is not nice for distros. Let's fix the issue by adding new struct musb_io for the IO access functions that the platform code can populate. Note that we don't want to use the current ops as that's really platform_data and and set as a const. This should allow eventually adding function pointers also for the DMA code to struct musb_io, but that's a whole different set of patches. For now, let's just fix the PIO access. Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 803a997..e5410bc 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -173,8 +173,25 @@ enum musb_g_ep0_state { /******************************** TYPES *************************************/ +struct musb_io; + /** * struct musb_platform_ops - Operations passed to musb_core by HW glue layer + * @quirks: flags for platform specific quirks + * @enable: enable device + * @disable: disable device + * @ep_offset: returns the end point offset + * @ep_select: selects the specified end point + * @fifo_mode: sets the fifo mode + * @fifo_offset: returns the fifo offset + * @readb: read 8 bits + * @writeb: write 8 bits + * @readw: read 16 bits + * @writew: write 16 bits + * @readl: read 32 bits + * @writel: write 32 bits + * @read_fifo: reads the fifo + * @write_fifo: writes to fifo * @init: turns on clocks, sets up platform-specific registers, etc * @exit: undoes @init * @set_mode: forcefully changes operating mode @@ -184,12 +201,34 @@ enum musb_g_ep0_state { * @adjust_channel_params: pre check for standard dma channel_program func */ struct musb_platform_ops { + +#define MUSB_DMA_UX500 BIT(6) +#define MUSB_DMA_CPPI41 BIT(5) +#define MUSB_DMA_CPPI BIT(4) +#define MUSB_DMA_TUSB_OMAP BIT(3) +#define MUSB_DMA_INVENTRA BIT(2) +#define MUSB_IN_TUSB BIT(1) +#define MUSB_INDEXED_EP BIT(0) + u32 quirks; + int (*init)(struct musb *musb); int (*exit)(struct musb *musb); void (*enable)(struct musb *musb); void (*disable)(struct musb *musb); + u32 (*ep_offset)(u8 epnum, u16 offset); + void (*ep_select)(void __iomem *mbase, u8 epnum); + u16 fifo_mode; + u32 (*fifo_offset)(u8 epnum); + u8 (*readb)(const void __iomem *addr, unsigned offset); + void (*writeb)(void __iomem *addr, unsigned offset, u8 data); + u16 (*readw)(const void __iomem *addr, unsigned offset); + void (*writew)(void __iomem *addr, unsigned offset, u16 data); + u32 (*readl)(const void __iomem *addr, unsigned offset); + void (*writel)(void __iomem *addr, unsigned offset, u32 data); + void (*read_fifo)(struct musb_hw_ep *hw_ep, u16 len, u8 *buf); + void (*write_fifo)(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf); int (*set_mode)(struct musb *musb, u8 mode); void (*try_idle)(struct musb *musb, unsigned long timeout); int (*reset)(struct musb *musb); @@ -292,6 +331,7 @@ struct musb { /* device lock */ spinlock_t lock; + struct musb_io io; const struct musb_platform_ops *ops; struct musb_context_registers context; diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index eebeed7..46c01c8 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -37,6 +37,24 @@ #include +/** + * struct musb_io - IO functions for MUSB + * @quirks: platform specific flags + * @ep_offset: platform specific function to get end point offset + * @ep_select: platform specific function to select end point + * @fifo_offset: platform specific function to get fifo offset + * @read_fifo: platform specific function to read fifo + * @write_fifo: platform specific function to write fifo + */ +struct musb_io { + u32 quirks; + u32 (*ep_offset)(u8 epnum, u16 offset); + void (*ep_select)(void __iomem *mbase, u8 epnum); + u32 (*fifo_offset)(u8 epnum); + void (*read_fifo)(struct musb_hw_ep *hw_ep, u16 len, u8 *buf); + void (*write_fifo)(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf); +}; + #ifndef CONFIG_BLACKFIN /* NOTE: these offsets are all in bytes */ -- cgit v0.10.2 From 9d506fc6d2cdafdec5ce605036f5eeec9fd59657 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:05:00 -0800 Subject: usb: musb: Populate new IO functions for tusb6010 Let's populate the new IO functions for tusb6010 but not use them yet. Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 69ca92d6..42e0cf9 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -126,6 +126,41 @@ static void tusb_wbus_quirk(struct musb *musb, int enabled) } } +static u32 tusb_fifo_offset(u8 epnum) +{ + return 0x200 + (epnum * 0x20); +} + +/* + * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. + */ +static u8 tusb_readb(const void __iomem *addr, unsigned offset) +{ + u16 tmp; + u8 val; + + tmp = __raw_readw(addr + (offset & ~1)); + if (offset & 1) + val = (tmp >> 8); + else + val = tmp & 0xff; + + return val; +} + +static void tusb_writeb(void __iomem *addr, unsigned offset, u8 data) +{ + u16 tmp; + + tmp = __raw_readw(addr + (offset & ~1)); + if (offset & 1) + tmp = (data << 8) | (tmp & 0xff); + else + tmp = (tmp & 0xff00) | data; + + __raw_writew(tmp, addr + (offset & ~1)); +} + /* * TUSB 6010 may use a parallel bus that doesn't support byte ops; * so both loading and unloading FIFOs need explicit byte counts. @@ -1135,9 +1170,15 @@ static int tusb_musb_exit(struct musb *musb) } static const struct musb_platform_ops tusb_ops = { + .quirks = MUSB_IN_TUSB, .init = tusb_musb_init, .exit = tusb_musb_exit, + .fifo_offset = tusb_fifo_offset, + .readb = tusb_readb, + .writeb = tusb_writeb, + .read_fifo = musb_read_fifo, + .write_fifo = musb_write_fifo, .enable = tusb_musb_enable, .disable = tusb_musb_disable, -- cgit v0.10.2 From cc92f6818f6e771d02ab5025262760d1a21aae95 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:05:01 -0800 Subject: usb: musb: Populate new IO functions for blackfin Populate new IO functions for blackfin Cc: Bryan Wu Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index f23ce40b..ed1524a 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -33,6 +33,41 @@ struct bfin_glue { }; #define glue_to_musb(g) platform_get_drvdata(g->musb) +static u32 bfin_fifo_offset(u8 epnum) +{ + return USB_OFFSET(USB_EP0_FIFO) + (epnum * 8); +} + +static u8 bfin_readb(const void __iomem *addr, unsigned offset) +{ + return (u8)(bfin_read16(addr + offset)); +} + +static u16 bfin_readw(const void __iomem *addr, unsigned offset) +{ + return bfin_read16(addr + offset); +} + +static u32 bfin_readl(const void __iomem *addr, unsigned offset) +{ + return (u32)(bfin_read16(addr + offset)); +} + +static void bfin_writeb(void __iomem *addr, unsigned offset, u8 data) +{ + bfin_write16(addr + offset, (u16)data); +} + +static void bfin_writew(void __iomem *addr, unsigned offset, u16 data) +{ + bfin_write16(addr + offset, data); +} + +static void binf_writel(void __iomem *addr, unsigned offset, u32 data) +{ + bfin_write16(addr + offset, (u16)data); +} + /* * Load an endpoint's FIFO */ @@ -433,6 +468,14 @@ static const struct musb_platform_ops bfin_ops = { .init = bfin_musb_init, .exit = bfin_musb_exit, + .readb = bfin_readb, + .writeb = bfin_writeb, + .readw = bfin_readw, + .writew = bfin_writew, + .readl = bfin_readl, + .writel = bfin_writel, + .read_fifo = musb_read_fifo, + .write_fifo = musb_write_fifo, .enable = bfin_musb_enable, .disable = bfin_musb_disable, -- cgit v0.10.2 From 1b40fc57a517878cf4c2e16ce29cc9a066dc1064 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:05:02 -0800 Subject: usb: musb: Change to use new IO access Change to use new IO access. This allows us to build in multiple MUSB glue layers. [ balbi@ti.com : switch to EXPORT_SYMBOL_GPL() fix long lines ] Cc: Fabio Baltieri Cc: Lee Jones Cc: Linus Walleij Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index d836a3e..7fc8d47 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -408,7 +408,7 @@ static int am35x_musb_exit(struct musb *musb) } /* AM35x supports only 32bit read operation */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) +static void am35x_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) { void __iomem *fifo = hw_ep->fifo; u32 val; @@ -441,6 +441,7 @@ static const struct musb_platform_ops am35x_ops = { .init = am35x_musb_init, .exit = am35x_musb_exit, + .read_fifo = am35x_read_fifo, .enable = am35x_musb_enable, .disable = am35x_musb_disable, diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index ed1524a..77f9f55 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -71,7 +71,7 @@ static void binf_writel(void __iomem *addr, unsigned offset, u32 data) /* * Load an endpoint's FIFO */ -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) +static void bfin_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) { struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; @@ -135,7 +135,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) /* * Unload an endpoint's FIFO */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) +static void bfin_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) { struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; @@ -474,8 +474,8 @@ static const struct musb_platform_ops bfin_ops = { .writew = bfin_writew, .readl = bfin_readl, .writel = bfin_writel, - .read_fifo = musb_read_fifo, - .write_fifo = musb_write_fifo, + .read_fifo = bfin_read_fifo, + .write_fifo = bfin_write_fifo, .enable = bfin_musb_enable, .disable = bfin_musb_disable, diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 5257928..1c1a9a1 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -224,12 +224,46 @@ static struct usb_phy_io_ops musb_ulpi_access = { /*-------------------------------------------------------------------------*/ -#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN) +static u32 musb_default_fifo_offset(u8 epnum) +{ + return 0x20 + (epnum * 4); +} + +static u8 musb_default_readb(const void __iomem *addr, unsigned offset) +{ + return __raw_readb(addr + offset); +} + +static void musb_default_writeb(void __iomem *addr, unsigned offset, u8 data) +{ + __raw_writeb(data, addr + offset); +} + +static u16 musb_default_readw(const void __iomem *addr, unsigned offset) +{ + return __raw_readw(addr + offset); +} + +static void musb_default_writew(void __iomem *addr, unsigned offset, u16 data) +{ + __raw_writew(data, addr + offset); +} + +static u32 musb_default_readl(const void __iomem *addr, unsigned offset) +{ + return __raw_readl(addr + offset); +} + +static void musb_default_writel(void __iomem *addr, unsigned offset, u32 data) +{ + __raw_writel(data, addr + offset); +} /* * Load an endpoint's FIFO */ -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) +static void musb_default_write_fifo(struct musb_hw_ep *hw_ep, u16 len, + const u8 *src) { struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; @@ -270,11 +304,10 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) } } -#if !defined(CONFIG_USB_MUSB_AM35X) /* * Unload an endpoint's FIFO */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) +static void musb_default_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) { struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; @@ -312,10 +345,40 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) ioread8_rep(fifo, dst, len); } } -#endif -#endif /* normal PIO */ +/* + * Old style IO functions + */ +u8 (*musb_readb)(const void __iomem *addr, unsigned offset); +EXPORT_SYMBOL_GPL(musb_readb); + +void (*musb_writeb)(void __iomem *addr, unsigned offset, u8 data); +EXPORT_SYMBOL_GPL(musb_writeb); +u16 (*musb_readw)(const void __iomem *addr, unsigned offset); +EXPORT_SYMBOL_GPL(musb_readw); + +void (*musb_writew)(void __iomem *addr, unsigned offset, u16 data); +EXPORT_SYMBOL_GPL(musb_writew); + +u32 (*musb_readl)(const void __iomem *addr, unsigned offset); +EXPORT_SYMBOL_GPL(musb_readl); + +void (*musb_writel)(void __iomem *addr, unsigned offset, u32 data); +EXPORT_SYMBOL_GPL(musb_writel); + +/* + * New style IO functions + */ +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) +{ + return hw_ep->musb->io.read_fifo(hw_ep, len, dst); +} + +void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) +{ + return hw_ep->musb->io.write_fifo(hw_ep, len, src); +} /*-------------------------------------------------------------------------*/ @@ -1456,17 +1519,22 @@ static int musb_core_init(u16 musb_type, struct musb *musb) for (i = 0; i < musb->nr_endpoints; i++) { struct musb_hw_ep *hw_ep = musb->endpoints + i; - hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase; + hw_ep->fifo = musb->io.fifo_offset(i) + mbase; #if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE) - hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i); - hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i); - hw_ep->fifo_sync_va = - musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i); - - if (i == 0) - hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF; - else - hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2); + if (musb->io.quirks & MUSB_IN_TUSB) { + hw_ep->fifo_async = musb->async + 0x400 + + musb->io.fifo_offset(i); + hw_ep->fifo_sync = musb->sync + 0x400 + + musb->io.fifo_offset(i); + hw_ep->fifo_sync_va = + musb->sync_va + 0x400 + musb->io.fifo_offset(i); + + if (i == 0) + hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF; + else + hw_ep->conf = mbase + 0x400 + + (((i - 1) & 0xf) << 2); + } #endif hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase; @@ -1903,6 +1971,18 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb->ops = plat->platform_ops; musb->port_mode = plat->mode; + /* + * Initialize the default IO functions. At least omap2430 needs + * these early. We initialize the platform specific IO functions + * later on. + */ + musb_readb = musb_default_readb; + musb_writeb = musb_default_writeb; + musb_readw = musb_default_readw; + musb_writew = musb_default_writew; + musb_readl = musb_default_readl; + musb_writel = musb_default_writel; + /* The musb_platform_init() call: * - adjusts musb->mregs * - sets the musb->isr @@ -1924,6 +2004,37 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) goto fail2; } + if (musb->ops->quirks) + musb->io.quirks = musb->ops->quirks; + + if (musb->ops->fifo_offset) + musb->io.fifo_offset = musb->ops->fifo_offset; + else + musb->io.fifo_offset = musb_default_fifo_offset; + + if (musb->ops->readb) + musb_readb = musb->ops->readb; + if (musb->ops->writeb) + musb_writeb = musb->ops->writeb; + if (musb->ops->readw) + musb_readw = musb->ops->readw; + if (musb->ops->writew) + musb_writew = musb->ops->writew; + if (musb->ops->readl) + musb_readl = musb->ops->readl; + if (musb->ops->writel) + musb_writel = musb->ops->writel; + + if (musb->ops->read_fifo) + musb->io.read_fifo = musb->ops->read_fifo; + else + musb->io.read_fifo = musb_default_read_fifo; + + if (musb->ops->write_fifo) + musb->io.write_fifo = musb->ops->write_fifo; + else + musb->io.write_fifo = musb_default_write_fifo; + if (!musb->xceiv->io_ops) { musb->xceiv->io_dev = musb->controller; musb->xceiv->io_priv = musb->mregs; diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index 46c01c8..14aa217 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -55,86 +55,12 @@ struct musb_io { void (*write_fifo)(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf); }; -#ifndef CONFIG_BLACKFIN - -/* NOTE: these offsets are all in bytes */ - -static inline u16 musb_readw(const void __iomem *addr, unsigned offset) - { return __raw_readw(addr + offset); } - -static inline u32 musb_readl(const void __iomem *addr, unsigned offset) - { return __raw_readl(addr + offset); } - - -static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) - { __raw_writew(data, addr + offset); } - -static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) - { __raw_writel(data, addr + offset); } - - -#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE) - -/* - * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. - */ -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) -{ - u16 tmp; - u8 val; - - tmp = __raw_readw(addr + (offset & ~1)); - if (offset & 1) - val = (tmp >> 8); - else - val = tmp & 0xff; - - return val; -} - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) -{ - u16 tmp; - - tmp = __raw_readw(addr + (offset & ~1)); - if (offset & 1) - tmp = (data << 8) | (tmp & 0xff); - else - tmp = (tmp & 0xff00) | data; - - __raw_writew(tmp, addr + (offset & ~1)); -} - -#else - -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) - { return __raw_readb(addr + offset); } - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) - { __raw_writeb(data, addr + offset); } - -#endif /* CONFIG_USB_MUSB_TUSB6010 */ - -#else - -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) - { return (u8) (bfin_read16(addr + offset)); } - -static inline u16 musb_readw(const void __iomem *addr, unsigned offset) - { return bfin_read16(addr + offset); } - -static inline u32 musb_readl(const void __iomem *addr, unsigned offset) - { return (u32) (bfin_read16(addr + offset)); } - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) - { bfin_write16(addr + offset, (u16) data); } - -static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) - { bfin_write16(addr + offset, data); } - -static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) - { bfin_write16(addr + offset, (u16) data); } - -#endif /* CONFIG_BLACKFIN */ +/* Do not add new entries here, add them the struct musb_io instead */ +extern u8 (*musb_readb)(const void __iomem *addr, unsigned offset); +extern void (*musb_writeb)(void __iomem *addr, unsigned offset, u8 data); +extern u16 (*musb_readw)(const void __iomem *addr, unsigned offset); +extern void (*musb_writew)(void __iomem *addr, unsigned offset, u16 data); +extern u32 (*musb_readl)(const void __iomem *addr, unsigned offset); +extern void (*musb_writel)(void __iomem *addr, unsigned offset, u32 data); #endif diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 37122a4..b2b1f73 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -239,14 +239,6 @@ #define MUSB_INDEX 0x0E /* 8 bit */ #define MUSB_TESTMODE 0x0F /* 8 bit */ -/* Get offset for a given FIFO from musb->mregs */ -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) -#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20)) -#else -#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4)) -#endif - /* * Additional Control Registers */ @@ -480,10 +472,6 @@ static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum) #define MUSB_INDEX USB_OFFSET(USB_INDEX) /* 8 bit */ #define MUSB_TESTMODE USB_OFFSET(USB_TESTMODE)/* 8 bit */ -/* Get offset for a given FIFO from musb->mregs */ -#define MUSB_FIFO_OFFSET(epnum) \ - (USB_OFFSET(USB_EP0_FIFO) + ((epnum) * 8)) - /* * Additional Control Registers */ diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 42e0cf9..16c4475 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -208,7 +208,7 @@ static inline void tusb_fifo_read_unaligned(void __iomem *fifo, } } -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf) +static void tusb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf) { struct musb *musb = hw_ep->musb; void __iomem *ep_conf = hw_ep->conf; @@ -258,7 +258,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf) tusb_fifo_write_unaligned(fifo, buf, len); } -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf) +static void tusb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf) { struct musb *musb = hw_ep->musb; void __iomem *ep_conf = hw_ep->conf; @@ -1177,8 +1177,8 @@ static const struct musb_platform_ops tusb_ops = { .fifo_offset = tusb_fifo_offset, .readb = tusb_readb, .writeb = tusb_writeb, - .read_fifo = musb_read_fifo, - .write_fifo = musb_write_fifo, + .read_fifo = tusb_read_fifo, + .write_fifo = tusb_write_fifo, .enable = tusb_musb_enable, .disable = tusb_musb_disable, diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 734dc84..e93845c 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -91,9 +91,9 @@ static bool ux500_configure_channel(struct dma_channel *channel, struct scatterlist sg; struct dma_slave_config slave_conf; enum dma_slave_buswidth addr_width; - dma_addr_t usb_fifo_addr = (MUSB_FIFO_OFFSET(hw_ep->epnum) + - ux500_channel->controller->phy_base); struct musb *musb = ux500_channel->controller->private_data; + dma_addr_t usb_fifo_addr = (musb->io.fifo_offset(hw_ep->epnum) + + ux500_channel->controller->phy_base); dev_dbg(musb->controller, "packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", -- cgit v0.10.2 From d026e9c76aac3632af174cf02d5c94defa5e6026 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:05:03 -0800 Subject: usb: musb: Change end point selection to use new IO access This allows the endpoints to work when multiple MUSB glue layers are built in. Cc: Fabio Baltieri Cc: Lee Jones Cc: Lars-Peter Clausen Acked-by: Linus Walleij Acked-by: Apelete Seketeli Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 7fc8d47..220fd4d 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -438,6 +438,7 @@ static void am35x_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) } static const struct musb_platform_ops am35x_ops = { + .quirks = MUSB_INDEXED_EP, .init = am35x_musb_init, .exit = am35x_musb_exit, diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 527c7fe..9a61713 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -458,6 +458,7 @@ static int da8xx_musb_exit(struct musb *musb) } static const struct musb_platform_ops da8xx_ops = { + .quirks = MUSB_INDEXED_EP, .init = da8xx_musb_init, .exit = da8xx_musb_exit, diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index d118729..40e9874 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -106,6 +106,7 @@ static int jz4740_musb_exit(struct musb *musb) } static const struct musb_platform_ops jz4740_musb_ops = { + .quirks = MUSB_INDEXED_EP, .init = jz4740_musb_init, .exit = jz4740_musb_exit, }; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 1c1a9a1..1ff944a 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -229,6 +229,27 @@ static u32 musb_default_fifo_offset(u8 epnum) return 0x20 + (epnum * 4); } +/* "flat" mapping: each endpoint has its own i/o address */ +static void musb_flat_ep_select(void __iomem *mbase, u8 epnum) +{ +} + +static u32 musb_flat_ep_offset(u8 epnum, u16 offset) +{ + return 0x100 + (0x10 * epnum) + offset; +} + +/* "indexed" mapping: INDEX register controls register bank select */ +static void musb_indexed_ep_select(void __iomem *mbase, u8 epnum) +{ + musb_writeb(mbase, MUSB_INDEX, epnum); +} + +static u32 musb_indexed_ep_offset(u8 epnum, u16 offset) +{ + return 0x10 + offset; +} + static u8 musb_default_readb(const void __iomem *addr, unsigned offset) { return __raw_readb(addr + offset); @@ -1537,7 +1558,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb) } #endif - hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase; + hw_ep->regs = musb->io.ep_offset(i, 0) + mbase; hw_ep->target_regs = musb_read_target_reg_base(i, mbase); hw_ep->rx_reinit = 1; hw_ep->tx_reinit = 1; @@ -2007,6 +2028,21 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (musb->ops->quirks) musb->io.quirks = musb->ops->quirks; + /* At least tusb6010 has it's own offsets.. */ + if (musb->ops->ep_offset) + musb->io.ep_offset = musb->ops->ep_offset; + if (musb->ops->ep_select) + musb->io.ep_select = musb->ops->ep_select; + + /* ..and some devices use indexed offset or flat offset */ + if (musb->io.quirks & MUSB_INDEXED_EP) { + musb->io.ep_offset = musb_indexed_ep_offset; + musb->io.ep_select = musb_indexed_ep_select; + } else { + musb->io.ep_offset = musb_flat_ep_offset; + musb->io.ep_select = musb_flat_ep_select; + } + if (musb->ops->fifo_offset) musb->io.fifo_offset = musb->ops->fifo_offset; else diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index e5410bc..d9248fd 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -124,41 +124,6 @@ enum musb_g_ep0_state { #define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */ #define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */ - -/*************************** REGISTER ACCESS ********************************/ - -/* Endpoint registers (other than dynfifo setup) can be accessed either - * directly with the "flat" model, or after setting up an index register. - */ - -#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \ - || defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \ - || defined(CONFIG_ARCH_OMAP4) -/* REVISIT indexed access seemed to - * misbehave (on DaVinci) for at least peripheral IN ... - */ -#define MUSB_FLAT_REG -#endif - -/* TUSB mapping: "flat" plus ep0 special cases */ -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) -#define musb_ep_select(_mbase, _epnum) \ - musb_writeb((_mbase), MUSB_INDEX, (_epnum)) -#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET - -/* "flat" mapping: each endpoint has its own i/o address */ -#elif defined(MUSB_FLAT_REG) -#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)), ((void)(_epnum))) -#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET - -/* "indexed" mapping: INDEX register controls register bank select */ -#else -#define musb_ep_select(_mbase, _epnum) \ - musb_writeb((_mbase), MUSB_INDEX, (_epnum)) -#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET -#endif - /****************************** FUNCTIONS ********************************/ #define MUSB_HST_MODE(_musb)\ @@ -515,7 +480,7 @@ static inline int musb_read_fifosize(struct musb *musb, u8 reg = 0; /* read from core using indexed model */ - reg = musb_readb(mbase, MUSB_EP_OFFSET(epnum, MUSB_FIFOSIZE)); + reg = musb_readb(mbase, musb->io.ep_offset(epnum, MUSB_FIFOSIZE)); /* 0's returned when no more endpoints */ if (!reg) return -ENODEV; diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 440333f..53bd0e7 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -633,6 +633,7 @@ static int dsps_musb_reset(struct musb *musb) } static struct musb_platform_ops dsps_ops = { + .quirks = MUSB_INDEXED_EP, .init = dsps_musb_init, .exit = dsps_musb_exit, diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index 14aa217..8a57a6f 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -37,6 +37,8 @@ #include +#define musb_ep_select(_mbase, _epnum) musb->io.ep_select((_mbase), (_epnum)) + /** * struct musb_io - IO functions for MUSB * @quirks: platform specific flags diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index b2b1f73..92b4c3d 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -287,19 +287,8 @@ #define MUSB_FIFOSIZE 0x0F #define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */ -/* Offsets to endpoint registers in indexed model (using INDEX register) */ -#define MUSB_INDEXED_OFFSET(_epnum, _offset) \ - (0x10 + (_offset)) - -/* Offsets to endpoint registers in flat models */ -#define MUSB_FLAT_OFFSET(_epnum, _offset) \ - (0x100 + (0x10*(_epnum)) + (_offset)) - #if defined(CONFIG_USB_MUSB_TUSB6010) || \ defined(CONFIG_USB_MUSB_TUSB6010_MODULE) -/* TUSB6010 EP0 configuration register is special */ -#define MUSB_TUSB_OFFSET(_epnum, _offset) \ - (0x10 + _offset) #include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */ #endif diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index e8e9f9a..ab7ec09 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -195,6 +195,7 @@ static int dma_channel_abort(struct dma_channel *channel) { struct musb_dma_channel *musb_channel = channel->private_data; void __iomem *mbase = musb_channel->controller->base; + struct musb *musb = musb_channel->controller->private_data; u8 bchannel = musb_channel->idx; int offset; @@ -202,7 +203,7 @@ static int dma_channel_abort(struct dma_channel *channel) if (channel->status == MUSB_DMA_STATUS_BUSY) { if (musb_channel->transmit) { - offset = MUSB_EP_OFFSET(musb_channel->epnum, + offset = musb->io.ep_offset(musb_channel->epnum, MUSB_TXCSR); /* @@ -215,7 +216,7 @@ static int dma_channel_abort(struct dma_channel *channel) csr &= ~MUSB_TXCSR_DMAMODE; musb_writew(mbase, offset, csr); } else { - offset = MUSB_EP_OFFSET(musb_channel->epnum, + offset = musb->io.ep_offset(musb_channel->epnum, MUSB_RXCSR); csr = musb_readw(mbase, offset); @@ -326,7 +327,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) (musb_channel->max_packet_sz - 1))) ) { u8 epnum = musb_channel->epnum; - int offset = MUSB_EP_OFFSET(epnum, + int offset = musb->io.ep_offset(epnum, MUSB_TXCSR); u16 txcsr; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 16c4475..3a5ffd5 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -131,6 +131,17 @@ static u32 tusb_fifo_offset(u8 epnum) return 0x200 + (epnum * 0x20); } +static u32 tusb_ep_offset(u8 epnum, u16 offset) +{ + return 0x10 + offset; +} + +/* TUSB mapping: "flat" plus ep0 special cases */ +static void tusb_ep_select(void __iomem *mbase, u8 epnum) +{ + musb_writeb(mbase, MUSB_INDEX, epnum); +} + /* * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. */ @@ -1174,6 +1185,8 @@ static const struct musb_platform_ops tusb_ops = { .init = tusb_musb_init, .exit = tusb_musb_exit, + .ep_offset = tusb_ep_offset, + .ep_select = tusb_ep_select, .fifo_offset = tusb_fifo_offset, .readb = tusb_readb, .writeb = tusb_writeb, diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 1d631d5..06e8b35 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -188,6 +188,7 @@ static int ux500_musb_exit(struct musb *musb) } static const struct musb_platform_ops ux500_ops = { + .quirks = MUSB_INDEXED_EP, .init = ux500_musb_init, .exit = ux500_musb_exit, -- cgit v0.10.2 From 8a77f05aa39be879535f22a9757e703581fa1392 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:05:04 -0800 Subject: usb: musb: Pass fifo_mode in platform data This allows setting the correct fifo_mode when multiple MUSB glue layers are built-in. Cc: Fabio Baltieri Cc: Lee Jones Cc: Linus Walleij Cc: Lars-Peter Clausen Acked-by: Apelete Seketeli Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 77f9f55..a441a2d 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -474,6 +474,7 @@ static const struct musb_platform_ops bfin_ops = { .writew = bfin_writew, .readl = bfin_readl, .writel = bfin_writel, + .fifo_mode = 2, .read_fifo = bfin_read_fifo, .write_fifo = bfin_write_fifo, .enable = bfin_musb_enable, diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 9a61713..9a9c82a 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -462,6 +462,7 @@ static const struct musb_platform_ops da8xx_ops = { .init = da8xx_musb_init, .exit = da8xx_musb_exit, + .fifo_mode = 2, .enable = da8xx_musb_enable, .disable = da8xx_musb_disable, diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index 40e9874..bb7b263 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -107,6 +107,7 @@ static int jz4740_musb_exit(struct musb *musb) static const struct musb_platform_ops jz4740_musb_ops = { .quirks = MUSB_INDEXED_EP, + .fifo_mode = 2, .init = jz4740_musb_init, .exit = jz4740_musb_exit, }; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 1ff944a..1388d99 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1116,21 +1116,7 @@ static void musb_shutdown(struct platform_device *pdev) * We don't currently use dynamic fifo setup capability to do anything * more than selecting one of a bunch of predefined configurations. */ -#if defined(CONFIG_USB_MUSB_TUSB6010) \ - || defined(CONFIG_USB_MUSB_TUSB6010_MODULE) \ - || defined(CONFIG_USB_MUSB_OMAP2PLUS) \ - || defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \ - || defined(CONFIG_USB_MUSB_AM35X) \ - || defined(CONFIG_USB_MUSB_AM35X_MODULE) \ - || defined(CONFIG_USB_MUSB_DSPS) \ - || defined(CONFIG_USB_MUSB_DSPS_MODULE) -static ushort fifo_mode = 4; -#elif defined(CONFIG_USB_MUSB_UX500) \ - || defined(CONFIG_USB_MUSB_UX500_MODULE) -static ushort fifo_mode = 5; -#else -static ushort fifo_mode = 2; -#endif +static ushort fifo_mode; /* "modprobe ... fifo_mode=1" etc */ module_param(fifo_mode, ushort, 0); @@ -2043,6 +2029,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb->io.ep_select = musb_flat_ep_select; } + if (musb->ops->fifo_mode) + fifo_mode = musb->ops->fifo_mode; + else + fifo_mode = 4; + if (musb->ops->fifo_offset) musb->io.fifo_offset = musb->ops->fifo_offset; else diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 06e8b35..abf7272 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -191,6 +191,7 @@ static const struct musb_platform_ops ux500_ops = { .quirks = MUSB_INDEXED_EP, .init = ux500_musb_init, .exit = ux500_musb_exit, + .fifo_mode = 5, .set_vbus = ux500_musb_set_vbus, }; -- cgit v0.10.2 From 82c02f58ba3a1ee0a067c0f90513e826d6152ba6 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:05:05 -0800 Subject: usb: musb: Allow multiple glue layers to be built in There's no reason any longer to keep it as a choice now that the IO access has been fixed. Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 06cc5d6..9d68372 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -58,8 +58,7 @@ config USB_MUSB_DUAL_ROLE endchoice -choice - prompt "Platform Glue Layer" +comment "Platform Glue Layer" config USB_MUSB_DAVINCI tristate "DaVinci" @@ -101,8 +100,6 @@ config USB_MUSB_JZ4740 depends on USB_MUSB_GADGET depends on USB_OTG_BLACKLIST_HUB -endchoice - config USB_MUSB_AM335X_CHILD tristate -- cgit v0.10.2 From ebf3992061db1f7b3aa093f37fb308acc74fbc82 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 24 Nov 2014 11:05:06 -0800 Subject: usb: musb: Use IS_ENABLED for tusb6010 This removes the ifdef clutter a bit and saves few lines. It also makes it easier to detect the remaining places where we have conditional building of code done based on if defined for things like DMA. Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 1388d99..55fe0ff 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1527,7 +1527,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb) struct musb_hw_ep *hw_ep = musb->endpoints + i; hw_ep->fifo = musb->io.fifo_offset(i) + mbase; -#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE) +#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010) if (musb->io.quirks & MUSB_IN_TUSB) { hw_ep->fifo_async = musb->async + 0x400 + musb->io.fifo_offset(i); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index d9248fd..5e65958 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -216,8 +216,7 @@ struct musb_hw_ep { void __iomem *fifo; void __iomem *regs; -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) +#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010) void __iomem *conf; #endif @@ -234,8 +233,7 @@ struct musb_hw_ep { struct dma_channel *tx_channel; struct dma_channel *rx_channel; -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) +#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010) /* TUSB has "asynchronous" and "synchronous" dma modes */ dma_addr_t fifo_async; dma_addr_t fifo_sync; @@ -339,8 +337,7 @@ struct musb { void __iomem *ctrl_base; void __iomem *mregs; -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) +#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010) dma_addr_t async; dma_addr_t sync; void __iomem *sync_va; diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 92b4c3d..11f0be0 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -287,10 +287,7 @@ #define MUSB_FIFOSIZE 0x0F #define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */ -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) #include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */ -#endif #define MUSB_TXCSR_MODE 0x2000 -- cgit v0.10.2 From 2193dda5eec60373c7a061c129c6ab9d658f78e9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 25 Nov 2014 12:28:46 +0100 Subject: USB: host: Remove ehci-octeon and ohci-octeon drivers Remove special-purpose octeon drivers and instead use ehci-platform and ohci-platform as suggested with http://marc.info/?l=linux-mips&m=140139694721623&w=2 [andreas.herrmann: fixed compile error] Cc: David Daney Cc: Alex Smith Signed-off-by: Alan Stern Signed-off-by: Andreas Herrmann Acked-by: Ralf Baechle Tested-by: Aaro Koskinen Signed-off-by: Greg Kroah-Hartman diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 6df0f4d..b67ddf0 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -7,22 +7,27 @@ * Copyright (C) 2008 Wind River Systems */ +#include #include #include #include #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include /* Octeon Random Number Generator. */ static int __init octeon_rng_device_init(void) @@ -68,6 +73,229 @@ device_initcall(octeon_rng_device_init); #ifdef CONFIG_USB +static DEFINE_MUTEX(octeon2_usb_clocks_mutex); + +static int octeon2_usb_clock_start_cnt; + +static void octeon2_usb_clocks_start(void) +{ + u64 div; + union cvmx_uctlx_if_ena if_ena; + union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; + union cvmx_uctlx_uphy_ctl_status uphy_ctl_status; + union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; + int i; + unsigned long io_clk_64_to_ns; + + + mutex_lock(&octeon2_usb_clocks_mutex); + + octeon2_usb_clock_start_cnt++; + if (octeon2_usb_clock_start_cnt != 1) + goto exit; + + io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); + + /* + * Step 1: Wait for voltages stable. That surely happened + * before starting the kernel. + * + * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 + */ + if_ena.u64 = 0; + if_ena.s.en = 1; + cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); + + /* Step 3: Configure the reference clock, PHY, and HCLK */ + clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); + + /* + * If the UCTL looks like it has already been started, skip + * the initialization, otherwise bus errors are obtained. + */ + if (clk_rst_ctl.s.hrst) + goto end_clock; + /* 3a */ + clk_rst_ctl.s.p_por = 1; + clk_rst_ctl.s.hrst = 0; + clk_rst_ctl.s.p_prst = 0; + clk_rst_ctl.s.h_clkdiv_rst = 0; + clk_rst_ctl.s.o_clkdiv_rst = 0; + clk_rst_ctl.s.h_clkdiv_en = 0; + clk_rst_ctl.s.o_clkdiv_en = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3b */ + /* 12MHz crystal. */ + clk_rst_ctl.s.p_refclk_sel = 0; + clk_rst_ctl.s.p_refclk_div = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3c */ + div = octeon_get_io_clock_rate() / 130000000ull; + + switch (div) { + case 0: + div = 1; + break; + case 1: + case 2: + case 3: + case 4: + break; + case 5: + div = 4; + break; + case 6: + case 7: + div = 6; + break; + case 8: + case 9: + case 10: + case 11: + div = 8; + break; + default: + div = 12; + break; + } + clk_rst_ctl.s.h_div = div; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + /* Read it back, */ + clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); + clk_rst_ctl.s.h_clkdiv_en = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + /* 3d */ + clk_rst_ctl.s.h_clkdiv_rst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3e: delay 64 io clocks */ + ndelay(io_clk_64_to_ns); + + /* + * Step 4: Program the power-on reset field in the UCTL + * clock-reset-control register. + */ + clk_rst_ctl.s.p_por = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Step 5: Wait 1 ms for the PHY clock to start. */ + mdelay(1); + + /* + * Step 6: Program the reset input from automatic test + * equipment field in the UPHY CSR + */ + uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0)); + uphy_ctl_status.s.ate_reset = 1; + cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); + + /* Step 7: Wait for at least 10ns. */ + ndelay(10); + + /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */ + uphy_ctl_status.s.ate_reset = 0; + cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); + + /* + * Step 9: Wait for at least 20ns for UPHY to output PHY clock + * signals and OHCI_CLK48 + */ + ndelay(20); + + /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ + /* 10a */ + clk_rst_ctl.s.o_clkdiv_rst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 10b */ + clk_rst_ctl.s.o_clkdiv_en = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 10c */ + ndelay(io_clk_64_to_ns); + + /* + * Step 11: Program the PHY reset field: + * UCTL0_CLK_RST_CTL[P_PRST] = 1 + */ + clk_rst_ctl.s.p_prst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Step 12: Wait 1 uS. */ + udelay(1); + + /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ + clk_rst_ctl.s.hrst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + +end_clock: + /* Now we can set some other registers. */ + + for (i = 0; i <= 1; i++) { + port_ctl_status.u64 = + cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); + /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ + port_ctl_status.s.txvreftune = 15; + port_ctl_status.s.txrisetune = 1; + port_ctl_status.s.txpreemphasistune = 1; + cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), + port_ctl_status.u64); + } + + /* Set uSOF cycle period to 60,000 bits. */ + cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); +exit: + mutex_unlock(&octeon2_usb_clocks_mutex); +} + +static void octeon2_usb_clocks_stop(void) +{ + mutex_lock(&octeon2_usb_clocks_mutex); + octeon2_usb_clock_start_cnt--; + mutex_unlock(&octeon2_usb_clocks_mutex); +} + +static int octeon_ehci_power_on(struct platform_device *pdev) +{ + octeon2_usb_clocks_start(); + return 0; +} + +static void octeon_ehci_power_off(struct platform_device *pdev) +{ + octeon2_usb_clocks_stop(); +} + +static struct usb_ehci_pdata octeon_ehci_pdata = { + /* Octeon EHCI matches CPU endianness. */ +#ifdef __BIG_ENDIAN + .big_endian_mmio = 1, +#endif + .power_on = octeon_ehci_power_on, + .power_off = octeon_ehci_power_off, +}; + +static void __init octeon_ehci_hw_start(void) +{ + union cvmx_uctlx_ehci_ctl ehci_ctl; + + octeon2_usb_clocks_start(); + + ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); + /* Use 64-bit addressing. */ + ehci_ctl.s.ehci_64b_addr_en = 1; + ehci_ctl.s.l2c_addr_msb = 0; + ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ + ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ + cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); + + octeon2_usb_clocks_stop(); +} + +static u64 octeon_ehci_dma_mask = DMA_BIT_MASK(64); + static int __init octeon_ehci_device_init(void) { struct platform_device *pd; @@ -88,7 +316,7 @@ static int __init octeon_ehci_device_init(void) if (octeon_is_simulation() || usb_disabled()) return 0; /* No USB in the simulator. */ - pd = platform_device_alloc("octeon-ehci", 0); + pd = platform_device_alloc("ehci-platform", 0); if (!pd) { ret = -ENOMEM; goto out; @@ -105,6 +333,10 @@ static int __init octeon_ehci_device_init(void) if (ret) goto fail; + pd->dev.dma_mask = &octeon_ehci_dma_mask; + pd->dev.platform_data = &octeon_ehci_pdata; + octeon_ehci_hw_start(); + ret = platform_device_add(pd); if (ret) goto fail; @@ -117,6 +349,41 @@ out: } device_initcall(octeon_ehci_device_init); +static int octeon_ohci_power_on(struct platform_device *pdev) +{ + octeon2_usb_clocks_start(); + return 0; +} + +static void octeon_ohci_power_off(struct platform_device *pdev) +{ + octeon2_usb_clocks_stop(); +} + +static struct usb_ohci_pdata octeon_ohci_pdata = { + /* Octeon OHCI matches CPU endianness. */ +#ifdef __BIG_ENDIAN + .big_endian_mmio = 1, +#endif + .power_on = octeon_ohci_power_on, + .power_off = octeon_ohci_power_off, +}; + +static void __init octeon_ohci_hw_start(void) +{ + union cvmx_uctlx_ohci_ctl ohci_ctl; + + octeon2_usb_clocks_start(); + + ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); + ohci_ctl.s.l2c_addr_msb = 0; + ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ + ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ + cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); + + octeon2_usb_clocks_stop(); +} + static int __init octeon_ohci_device_init(void) { struct platform_device *pd; @@ -137,7 +404,7 @@ static int __init octeon_ohci_device_init(void) if (octeon_is_simulation() || usb_disabled()) return 0; /* No USB in the simulator. */ - pd = platform_device_alloc("octeon-ohci", 0); + pd = platform_device_alloc("ohci-platform", 0); if (!pd) { ret = -ENOMEM; goto out; @@ -154,6 +421,9 @@ static int __init octeon_ohci_device_init(void) if (ret) goto fail; + pd->dev.platform_data = &octeon_ohci_pdata; + octeon_ohci_hw_start(); + ret = platform_device_add(pd); if (ret) goto fail; diff --git a/arch/mips/configs/cavium_octeon_defconfig b/arch/mips/configs/cavium_octeon_defconfig index b2476a1..e57058d 100644 --- a/arch/mips/configs/cavium_octeon_defconfig +++ b/arch/mips/configs/cavium_octeon_defconfig @@ -120,6 +120,9 @@ CONFIG_SPI_OCTEON=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y # CONFIG_USB_SUPPORT is not set +CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y +CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y +CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_STAGING=y diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index a3ca137..fafc628 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -292,11 +292,15 @@ config USB_EHCI_HCD_PLATFORM If unsure, say N. config USB_OCTEON_EHCI - bool "Octeon on-chip EHCI support" + bool "Octeon on-chip EHCI support (DEPRECATED)" depends on CAVIUM_OCTEON_SOC default n select USB_EHCI_BIG_ENDIAN_MMIO + select USB_EHCI_HCD_PLATFORM help + This option is deprecated now and the driver was removed, use + USB_EHCI_HCD_PLATFORM instead. + Enable support for the Octeon II SOC's on-chip EHCI controller. It is needed for high-speed (480Mbit/sec) USB 2.0 device support. All CN6XXX based chips with USB are @@ -575,12 +579,16 @@ config USB_OHCI_HCD_PLATFORM If unsure, say N. config USB_OCTEON_OHCI - bool "Octeon on-chip OHCI support" + bool "Octeon on-chip OHCI support (DEPRECATED)" depends on CAVIUM_OCTEON_SOC default USB_OCTEON_EHCI select USB_OHCI_BIG_ENDIAN_MMIO select USB_OHCI_LITTLE_ENDIAN + select USB_OHCI_HCD_PLATFORM help + This option is deprecated now and the driver was removed, use + USB_OHCI_HCD_PLATFORM instead. + Enable support for the Octeon II SOC's on-chip OHCI controller. It is needed for low-speed USB 1.0 device support. All CN6XXX based chips with USB are supported. @@ -754,12 +762,6 @@ config USB_IMX21_HCD To compile this driver as a module, choose M here: the module will be called "imx21-hcd". - - -config USB_OCTEON2_COMMON - bool - default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI - config USB_HCD_BCMA tristate "BCMA usb host driver" depends on BCMA diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 348c243..d6216a4 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -73,7 +73,6 @@ obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o -obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index df75b8e..38bfeed 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1275,11 +1275,6 @@ MODULE_LICENSE ("GPL"); #define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver #endif -#ifdef CONFIG_USB_OCTEON_EHCI -#include "ehci-octeon.c" -#define PLATFORM_DRIVER ehci_octeon_driver -#endif - #ifdef CONFIG_TILE_USB #include "ehci-tilegx.c" #define PLATFORM_DRIVER ehci_hcd_tilegx_driver diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c deleted file mode 100644 index 2d0c4bc..0000000 --- a/drivers/usb/host/ehci-octeon.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * EHCI HCD glue for Cavium Octeon II SOCs. - * - * Loosely based on ehci-au1xxx.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2010 Cavium Networks - * - */ - -#include - -#include -#include - -#define OCTEON_EHCI_HCD_NAME "octeon-ehci" - -/* Common clock init code. */ -void octeon2_usb_clocks_start(void); -void octeon2_usb_clocks_stop(void); - -static void ehci_octeon_start(void) -{ - union cvmx_uctlx_ehci_ctl ehci_ctl; - - octeon2_usb_clocks_start(); - - ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); - /* Use 64-bit addressing. */ - ehci_ctl.s.ehci_64b_addr_en = 1; - ehci_ctl.s.l2c_addr_msb = 0; - ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ - ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ - cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); -} - -static void ehci_octeon_stop(void) -{ - octeon2_usb_clocks_stop(); -} - -static const struct hc_driver ehci_octeon_hc_driver = { - .description = hcd_name, - .product_desc = "Octeon EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, - - /* - * basic lifecycle operations - */ - .reset = ehci_setup, - .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, - - /* - * 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, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64); - -static int ehci_octeon_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res_mem; - int irq; - int ret; - - if (usb_disabled()) - return -ENODEV; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "No irq assigned\n"); - return -ENODEV; - } - - /* - * We can DMA from anywhere. But the descriptors must be in - * the lower 4GB. - */ - pdev->dev.dma_mask = &ehci_octeon_dma_mask; - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon"); - if (!hcd) - return -ENOMEM; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, res_mem); - if (IS_ERR(hcd->regs)) { - ret = PTR_ERR(hcd->regs); - goto err1; - } - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - - ehci_octeon_start(); - - ehci = hcd_to_ehci(hcd); - - /* Octeon EHCI matches CPU endianness. */ -#ifdef __BIG_ENDIAN - ehci->big_endian_mmio = 1; -#endif - - ehci->caps = hcd->regs; - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); - goto err2; - } - device_wakeup_enable(hcd->self.controller); - - platform_set_drvdata(pdev, hcd); - - return 0; -err2: - ehci_octeon_stop(); - -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_octeon_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - - ehci_octeon_stop(); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ehci_octeon_driver = { - .probe = ehci_octeon_drv_probe, - .remove = ehci_octeon_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = OCTEON_EHCI_HCD_NAME, - .owner = THIS_MODULE, - } -}; - -MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME); diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c deleted file mode 100644 index d9df423..0000000 --- a/drivers/usb/host/octeon2-common.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2010, 2011 Cavium Networks - */ - -#include -#include -#include - -#include -#include - -static DEFINE_MUTEX(octeon2_usb_clocks_mutex); - -static int octeon2_usb_clock_start_cnt; - -void octeon2_usb_clocks_start(void) -{ - u64 div; - union cvmx_uctlx_if_ena if_ena; - union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; - union cvmx_uctlx_uphy_ctl_status uphy_ctl_status; - union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; - int i; - unsigned long io_clk_64_to_ns; - - - mutex_lock(&octeon2_usb_clocks_mutex); - - octeon2_usb_clock_start_cnt++; - if (octeon2_usb_clock_start_cnt != 1) - goto exit; - - io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); - - /* - * Step 1: Wait for voltages stable. That surely happened - * before starting the kernel. - * - * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 - */ - if_ena.u64 = 0; - if_ena.s.en = 1; - cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); - - /* Step 3: Configure the reference clock, PHY, and HCLK */ - clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); - - /* - * If the UCTL looks like it has already been started, skip - * the initialization, otherwise bus errors are obtained. - */ - if (clk_rst_ctl.s.hrst) - goto end_clock; - /* 3a */ - clk_rst_ctl.s.p_por = 1; - clk_rst_ctl.s.hrst = 0; - clk_rst_ctl.s.p_prst = 0; - clk_rst_ctl.s.h_clkdiv_rst = 0; - clk_rst_ctl.s.o_clkdiv_rst = 0; - clk_rst_ctl.s.h_clkdiv_en = 0; - clk_rst_ctl.s.o_clkdiv_en = 0; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 3b */ - /* 12MHz crystal. */ - clk_rst_ctl.s.p_refclk_sel = 0; - clk_rst_ctl.s.p_refclk_div = 0; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 3c */ - div = octeon_get_io_clock_rate() / 130000000ull; - - switch (div) { - case 0: - div = 1; - break; - case 1: - case 2: - case 3: - case 4: - break; - case 5: - div = 4; - break; - case 6: - case 7: - div = 6; - break; - case 8: - case 9: - case 10: - case 11: - div = 8; - break; - default: - div = 12; - break; - } - clk_rst_ctl.s.h_div = div; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - /* Read it back, */ - clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); - clk_rst_ctl.s.h_clkdiv_en = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - /* 3d */ - clk_rst_ctl.s.h_clkdiv_rst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 3e: delay 64 io clocks */ - ndelay(io_clk_64_to_ns); - - /* - * Step 4: Program the power-on reset field in the UCTL - * clock-reset-control register. - */ - clk_rst_ctl.s.p_por = 0; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* Step 5: Wait 1 ms for the PHY clock to start. */ - mdelay(1); - - /* - * Step 6: Program the reset input from automatic test - * equipment field in the UPHY CSR - */ - uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0)); - uphy_ctl_status.s.ate_reset = 1; - cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); - - /* Step 7: Wait for at least 10ns. */ - ndelay(10); - - /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */ - uphy_ctl_status.s.ate_reset = 0; - cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); - - /* - * Step 9: Wait for at least 20ns for UPHY to output PHY clock - * signals and OHCI_CLK48 - */ - ndelay(20); - - /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ - /* 10a */ - clk_rst_ctl.s.o_clkdiv_rst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 10b */ - clk_rst_ctl.s.o_clkdiv_en = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 10c */ - ndelay(io_clk_64_to_ns); - - /* - * Step 11: Program the PHY reset field: - * UCTL0_CLK_RST_CTL[P_PRST] = 1 - */ - clk_rst_ctl.s.p_prst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* Step 12: Wait 1 uS. */ - udelay(1); - - /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ - clk_rst_ctl.s.hrst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - -end_clock: - /* Now we can set some other registers. */ - - for (i = 0; i <= 1; i++) { - port_ctl_status.u64 = - cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); - /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ - port_ctl_status.s.txvreftune = 15; - port_ctl_status.s.txrisetune = 1; - port_ctl_status.s.txpreemphasistune = 1; - cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), - port_ctl_status.u64); - } - - /* Set uSOF cycle period to 60,000 bits. */ - cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); -exit: - mutex_unlock(&octeon2_usb_clocks_mutex); -} -EXPORT_SYMBOL(octeon2_usb_clocks_start); - -void octeon2_usb_clocks_stop(void) -{ - mutex_lock(&octeon2_usb_clocks_mutex); - octeon2_usb_clock_start_cnt--; - mutex_unlock(&octeon2_usb_clocks_mutex); -} -EXPORT_SYMBOL(octeon2_usb_clocks_stop); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d664eda..1dab9df 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1249,11 +1249,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_jz4740_driver #endif -#ifdef CONFIG_USB_OCTEON_OHCI -#include "ohci-octeon.c" -#define PLATFORM_DRIVER ohci_octeon_driver -#endif - #ifdef CONFIG_TILE_USB #include "ohci-tilegx.c" #define PLATFORM_DRIVER ohci_hcd_tilegx_driver diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c deleted file mode 100644 index 20d861b..0000000 --- a/drivers/usb/host/ohci-octeon.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * EHCI HCD glue for Cavium Octeon II SOCs. - * - * Loosely based on ehci-au1xxx.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2010 Cavium Networks - * - */ - -#include - -#include -#include - -#define OCTEON_OHCI_HCD_NAME "octeon-ohci" - -/* Common clock init code. */ -void octeon2_usb_clocks_start(void); -void octeon2_usb_clocks_stop(void); - -static void ohci_octeon_hw_start(void) -{ - union cvmx_uctlx_ohci_ctl ohci_ctl; - - octeon2_usb_clocks_start(); - - ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); - ohci_ctl.s.l2c_addr_msb = 0; - ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ - ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ - cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); - -} - -static void ohci_octeon_hw_stop(void) -{ - /* Undo ohci_octeon_start() */ - octeon2_usb_clocks_stop(); -} - -static int ohci_octeon_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - - if (ret < 0) - return ret; - - ret = ohci_run(ohci); - - if (ret < 0) { - ohci_err(ohci, "can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_octeon_hc_driver = { - .description = hcd_name, - .product_desc = "Octeon OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_octeon_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, - - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_octeon_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - void *reg_base; - struct resource *res_mem; - int irq; - int ret; - - if (usb_disabled()) - return -ENODEV; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "No irq assigned\n"); - return -ENODEV; - } - - /* Ohci is a 32-bit device. */ - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); - if (!hcd) - return -ENOMEM; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg_base = devm_ioremap_resource(&pdev->dev, res_mem); - if (IS_ERR(reg_base)) { - ret = PTR_ERR(reg_base); - goto err1; - } - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - - ohci_octeon_hw_start(); - - hcd->regs = reg_base; - - ohci = hcd_to_ohci(hcd); - - /* Octeon OHCI matches CPU endianness. */ -#ifdef __BIG_ENDIAN - ohci->flags |= OHCI_QUIRK_BE_MMIO; -#endif - - ohci_hcd_init(ohci); - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); - goto err2; - } - - device_wakeup_enable(hcd->self.controller); - - platform_set_drvdata(pdev, hcd); - - return 0; - -err2: - ohci_octeon_hw_stop(); - -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ohci_octeon_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - - ohci_octeon_hw_stop(); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ohci_octeon_driver = { - .probe = ohci_octeon_drv_probe, - .remove = ohci_octeon_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = OCTEON_OHCI_HCD_NAME, - .owner = THIS_MODULE, - } -}; - -MODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME); -- cgit v0.10.2 From c1fc0050102150481ad4ba7e6449b3aa6e88d6e5 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 13 Nov 2014 12:47:43 +0100 Subject: phy: Use PTR_ERR_OR_ZERO to fix warning raised by coccinelle Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Generated by: coccinelle/api/ptr_ret.cocci Signed-off-by: Gregory CLEMENT Acked-by: Jason Cooper Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index 3e599dc..099eee8 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -268,10 +268,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) phy_provider = devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id phy_berlin_sata_of_match[] = { diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c index a80ff9d..34915b4 100644 --- a/drivers/phy/phy-hix5hd2-sata.c +++ b/drivers/phy/phy-hix5hd2-sata.c @@ -164,10 +164,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy, priv); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id hix5hd2_sata_phy_of_match[] = { diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 239930e..6ab43a8 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -610,10 +610,7 @@ static int miphy365x_probe(struct platform_device *pdev) } provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate); - if (IS_ERR(provider)) - return PTR_ERR(provider); - - return 0; + return PTR_ERR_OR_ZERO(provider); } static const struct of_device_id miphy365x_of_match[] = { diff --git a/drivers/phy/phy-stih41x-usb.c b/drivers/phy/phy-stih41x-usb.c index 4ab581e..a603801 100644 --- a/drivers/phy/phy-stih41x-usb.c +++ b/drivers/phy/phy-stih41x-usb.c @@ -160,10 +160,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy, phy_dev); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id stih41x_usb_phy_of_match[] = { -- cgit v0.10.2 From aa1facbd2847263cf168ec7d66e6c8951c413905 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 13 Nov 2014 12:47:44 +0100 Subject: Phy: DT binding documentation for Marvell MVEBU SATA phy. Describe the binding for the Marvell MVEBU SATA phy. This driver can be used at least with Kirkwood, Dove and maybe others. Additionally, update the SATA binding with the properties to link to the phy nodes. Signed-off-by: Andrew Lunn Acked-by: Jason Cooper Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/ata/marvell.txt b/Documentation/devicetree/bindings/ata/marvell.txt index 1c83516..b460edd 100644 --- a/Documentation/devicetree/bindings/ata/marvell.txt +++ b/Documentation/devicetree/bindings/ata/marvell.txt @@ -6,11 +6,17 @@ Required Properties: - interrupts : Interrupt controller is using - nr-ports : Number of SATA ports in use. +Optional Properties: +- phys : List of phandles to sata phys +- phy-names : Should be "0", "1", etc, one number per phandle + Example: sata@80000 { compatible = "marvell,orion-sata"; reg = <0x80000 0x5000>; interrupts = <21>; + phys = <&sata_phy0>, <&sata_phy1>; + phy-names = "0", "1"; nr-ports = <2>; } diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu.txt b/Documentation/devicetree/bindings/phy/phy-mvebu.txt new file mode 100644 index 0000000..6cb3364 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-mvebu.txt @@ -0,0 +1,22 @@ +* Marvell MVEBU SATA PHY + +Power control for the SATA phy found on Marvell MVEBU SoCs. + +This document extends the binding described in phy-bindings.txt + +Required properties : + + - reg : Offset and length of the register set for the SATA device + - compatible : Should be "marvell,mvebu-sata-phy" + - clocks : phandle of clock and specifier that supplies the device + - clock-names : Should be "sata" + +Example: + sata-phy@84000 { + compatible = "marvell,mvebu-sata-phy"; + reg = <0x84000 0x0334>; + clocks = <&gate_clk 15>; + clock-names = "sata"; + #phy-cells = <0>; + status = "ok"; + }; -- cgit v0.10.2 From 1a6ab1c0e844041524f8edd1acf0de94df991aaa Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 13 Nov 2014 12:47:45 +0100 Subject: Phy: DT binding documentation for the Armada 375 USB cluster binding Armada 375 comes with an USB2 host and device controller and an USB3 controller. The USB cluster control register allows to manage common features of both USB controllers. This commit adds the Device Tree binding documentation for this piece of hardware. Signed-off-by: Gregory CLEMENT Acked-by: Jason Cooper Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu.txt b/Documentation/devicetree/bindings/phy/phy-mvebu.txt index 6cb3364..f95b626 100644 --- a/Documentation/devicetree/bindings/phy/phy-mvebu.txt +++ b/Documentation/devicetree/bindings/phy/phy-mvebu.txt @@ -20,3 +20,24 @@ Example: #phy-cells = <0>; status = "ok"; }; + +Armada 375 USB cluster +---------------------- + +Armada 375 comes with an USB2 host and device controller and an USB3 +controller. The USB cluster control register allows to manage common +features of both USB controllers. + +Required properties: + +- compatible: "marvell,armada-375-usb-cluster" +- reg: Should contain usb cluster register location and length. +- #phy-cells : from the generic phy bindings, must be 1. Possible +values are 1 (USB2), 2 (USB3). + +Example: + usbcluster: usb-cluster@18400 { + compatible = "marvell,armada-375-usb-cluster"; + reg = <0x18400 0x4>; + #phy-cells = <1> + }; -- cgit v0.10.2 From eee47538ec1f26198cf5da675975b61d7f16135b Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 13 Nov 2014 12:47:46 +0100 Subject: phy: add support for USB cluster on the Armada 375 SoC The Armada 375 SoC comes with an USB2 host and device controller and an USB3 controller. The USB cluster control register allows to manage common features of both USB controllers. This commit adds a driver integrated in the generic PHY framework to control this USB cluster feature. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni [ kishon@ti.com : Made it to use the updated devm_phy_create API and soem cosmentic changes in Kconfig file.] Signed-off-by: Kishon Vijay Abraham I Acked-by: Jason Cooper diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 96d43d5..ccad880 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -29,6 +29,12 @@ config PHY_BERLIN_SATA help Enable this to support the SATA PHY on Marvell Berlin SoCs. +config ARMADA375_USBCLUSTER_PHY + def_bool y + depends on MACH_ARMADA_375 || COMPILE_TEST + depends on OF + select GENERIC_PHY + config PHY_EXYNOS_MIPI_VIDEO tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" depends on HAS_IOMEM diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 68022f6..aa74f96 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o +obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c new file mode 100644 index 0000000..ac7d99d --- /dev/null +++ b/drivers/phy/phy-armada375-usb2.c @@ -0,0 +1,158 @@ +/* + * USB cluster support for Armada 375 platform. + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT + * + * This file is licensed under the terms of the GNU General Public + * License version 2 or later. This program is licensed "as is" + * without any warranty of any kind, whether express or implied. + * + * Armada 375 comes with an USB2 host and device controller and an + * USB3 controller. The USB cluster control register allows to manage + * common features of both USB controllers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB2_PHY_CONFIG_DISABLE BIT(0) + +struct armada375_cluster_phy { + struct phy *phy; + void __iomem *reg; + bool use_usb3; + int phy_provided; +}; + +static int armada375_usb_phy_init(struct phy *phy) +{ + struct armada375_cluster_phy *cluster_phy; + u32 reg; + + cluster_phy = dev_get_drvdata(phy->dev.parent); + if (!cluster_phy) + return -ENODEV; + + reg = readl(cluster_phy->reg); + if (cluster_phy->use_usb3) + reg |= USB2_PHY_CONFIG_DISABLE; + else + reg &= ~USB2_PHY_CONFIG_DISABLE; + writel(reg, cluster_phy->reg); + + return 0; +} + +static struct phy_ops armada375_usb_phy_ops = { + .init = armada375_usb_phy_init, + .owner = THIS_MODULE, +}; + +/* + * Only one controller can use this PHY. We shouldn't have the case + * when two controllers want to use this PHY. But if this case occurs + * then we provide a phy to the first one and return an error for the + * next one. This error has also to be an error returned by + * devm_phy_optional_get() so different from ENODEV for USB2. In the + * USB3 case it still optional and we use ENODEV. + */ +static struct phy *armada375_usb_phy_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev); + + if (!cluster_phy) + return ERR_PTR(-ENODEV); + + /* + * Either the phy had never been requested and then the first + * usb claiming it can get it, or it had already been + * requested in this case, we only allow to use it with the + * same configuration. + */ + if (WARN_ON((cluster_phy->phy_provided != PHY_NONE) && + (cluster_phy->phy_provided != args->args[0]))) { + dev_err(dev, "This PHY has already been provided!\n"); + dev_err(dev, "Check your device tree, only one controller can use it\n."); + if (args->args[0] == PHY_TYPE_USB2) + return ERR_PTR(-EBUSY); + else + return ERR_PTR(-ENODEV); + } + + if (args->args[0] == PHY_TYPE_USB2) + cluster_phy->use_usb3 = false; + else if (args->args[0] == PHY_TYPE_USB3) + cluster_phy->use_usb3 = true; + else { + dev_err(dev, "Invalid PHY mode\n"); + return ERR_PTR(-ENODEV); + } + + /* Store which phy mode is used for next test */ + cluster_phy->phy_provided = args->args[0]; + + return cluster_phy->phy; +} + +static int armada375_usb_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *phy; + struct phy_provider *phy_provider; + void __iomem *usb_cluster_base; + struct resource *res; + struct armada375_cluster_phy *cluster_phy; + + cluster_phy = devm_kzalloc(dev, sizeof(*cluster_phy), GFP_KERNEL); + if (!cluster_phy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + usb_cluster_base = devm_ioremap_resource(&pdev->dev, res); + if (!usb_cluster_base) + return -ENOMEM; + + phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(phy); + } + + cluster_phy->phy = phy; + cluster_phy->reg = usb_cluster_base; + + dev_set_drvdata(dev, cluster_phy); + + phy_provider = devm_of_phy_provider_register(&pdev->dev, + armada375_usb_phy_xlate); + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id of_usb_cluster_table[] = { + { .compatible = "marvell,armada-375-usb-cluster", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, of_usb_cluster_table); + +static struct platform_driver armada375_usb_phy_driver = { + .probe = armada375_usb_phy_probe, + .driver = { + .of_match_table = of_usb_cluster_table, + .name = "armada-375-usb-cluster", + .owner = THIS_MODULE, + } +}; +module_platform_driver(armada375_usb_phy_driver); + +MODULE_DESCRIPTION("Armada 375 USB cluster driver"); +MODULE_AUTHOR("Gregory CLEMENT "); +MODULE_LICENSE("GPL"); diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h index e8c6a3f..6c90193 100644 --- a/include/dt-bindings/phy/phy.h +++ b/include/dt-bindings/phy/phy.h @@ -10,6 +10,7 @@ #ifndef _DT_BINDINGS_PHY #define _DT_BINDINGS_PHY +#define PHY_NONE 0 #define PHY_TYPE_SATA 1 #define PHY_TYPE_PCIE 2 #define PHY_TYPE_USB2 3 -- cgit v0.10.2 From 4c503dd5fbdc33118d27f60e5c364d364980d4fd Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:22 +0800 Subject: usb: chipidea: using devm_request_irq to instead of request_irq Using devm_request_irq to instead of request_irq. Suggested-by: Arnd Bergmann Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 60578d9..5de1507 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -759,8 +759,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, ci); - ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name, - ci); + ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, + ci->platdata->name, ci); if (ret) goto stop; @@ -771,7 +771,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ret) return 0; - free_irq(ci->irq, ci); stop: ci_role_destroy(ci); deinit_phy: @@ -785,7 +784,6 @@ static int ci_hdrc_remove(struct platform_device *pdev) struct ci_hdrc *ci = platform_get_drvdata(pdev); dbg_remove_files(ci); - free_irq(ci->irq, ci); ci_role_destroy(ci); ci_hdrc_enter_lpm(ci, true); ci_usb_phy_exit(ci); -- cgit v0.10.2 From d0f992498e82e656646ad833e3f32ad69cd093e7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Nov 2014 13:44:23 +0800 Subject: usb: chipidea: core: Remove unneeded OOM message MM core code already complains when devm_kzalloc() fails, so no need to print the error locally. Signed-off-by: Fabio Estevam Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 5de1507..cde3d24 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -633,10 +633,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) return PTR_ERR(base); ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); - if (!ci) { - dev_err(dev, "can't allocate device\n"); + if (!ci) return -ENOMEM; - } ci->dev = dev; ci->platdata = dev_get_platdata(dev); -- cgit v0.10.2 From 73529828cf896df5017255136b4dc2386dff0850 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Nov 2014 13:44:24 +0800 Subject: usb: chipidea: ci_hdrc_imx.c: Remove unneeded OOM message MM core code already complains when devm_kzalloc() fails, so no need to print the error locally. Signed-off-by: Fabio Estevam Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 6f8b1b1..8b1482a 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -115,10 +115,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n"); + if (!data) return -ENOMEM; - } data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); if (IS_ERR(data->usbmisc_data)) -- cgit v0.10.2 From 8d1dc4d055faafafca3edd8499aeeef3f77803e4 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Nov 2014 13:44:25 +0800 Subject: usb: chipidea: usbmisc_imx: Move the reading of USB_PHY_CTRL If 'evdo' property is not defined, then reading the MX25_USB_PHY_CTRL_OFFSET register is an unneeded operation. Move the reading of MX25_USB_PHY_CTRL_OFFSET inside the 'evdo' if block code, where it is actually used. Signed-off-by: Fabio Estevam Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 926c997..29200eb 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -117,10 +117,9 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data) if (data->index > 2) return -EINVAL; - reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; - if (data->evdo) { spin_lock_irqsave(&usbmisc->lock, flags); + reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; val = readl(reg); writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); spin_unlock_irqrestore(&usbmisc->lock, flags); -- cgit v0.10.2 From 4a1d6cf156dcf436e5037375007116197f03bfb1 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Nov 2014 13:44:26 +0800 Subject: usb: chipidea: usbmisc_imx: Read MX53_USB_OTG_PHY_CTRL_1_OFFSET directly There is no need to do an intermediate step for reading the MX53_USB_OTG_PHY_CTRL_1_OFFSET register. Read it directly instead. Signed-off-by: Fabio Estevam Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 29200eb..58591e9 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -171,8 +171,7 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data) return -EINVAL; /* Select a 24 MHz reference clock for the PHY */ - reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET; - val = readl(reg); + val = readl(usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK; val |= MX53_USB_PLL_DIV_24_MHZ; writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); -- cgit v0.10.2 From 6d037db6409c33738c7153e87ae1cf682ca2851b Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:27 +0800 Subject: usb: chipidea: remove the unnecessary delay after clear portsc.phcd The individual PHY driver should take this responsibility if it needs to delay between clear portsc.phcd and let the phy leave low power mode. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index cde3d24..d87caea 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -196,18 +196,12 @@ static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC; bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); - if (enable && !lpm) { + if (enable && !lpm) hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), PORTSC_PHCD(ci->hw_bank.lpm)); - } else if (!enable && lpm) { + else if (!enable && lpm) hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 0); - /* - * the PHY needs some time (less - * than 1ms) to leave low power mode. - */ - usleep_range(1000, 1100); - } } static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) -- cgit v0.10.2 From b82613cf09455d9a50fbb144ef07b68225f2b452 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:28 +0800 Subject: usb: chipidea: add hw_wait_phy_stable for getting stable status The phy needs some delay to output the stable status from low power mode. And for OTGSC, the status inputs are debounced using a 1 ms time constant, so, delay 2ms for controller to get the stable status(like vbus and id) when the phy leaves low power. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index d87caea..fe38805 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -190,6 +190,17 @@ u8 hw_port_test_get(struct ci_hdrc *ci) return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); } +static void hw_wait_phy_stable(void) +{ + /* + * The phy needs some delay to output the stable status from low + * power mode. And for OTGSC, the status inputs are debounced + * using a 1 ms time constant, so, delay 2ms for controller to get + * the stable status, like vbus and id when the phy leaves low power. + */ + usleep_range(2000, 2500); +} + /* The PHY enters/leaves low power mode */ static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) { @@ -351,7 +362,9 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) case USBPHY_INTERFACE_MODE_UTMIW: case USBPHY_INTERFACE_MODE_HSIC: ret = _ci_usb_phy_init(ci); - if (ret) + if (!ret) + hw_wait_phy_stable(); + else return ret; hw_phymode_configure(ci); break; @@ -364,6 +377,8 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) break; default: ret = _ci_usb_phy_init(ci); + if (!ret) + hw_wait_phy_stable(); } return ret; @@ -667,13 +682,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "unable to init phy: %d\n", ret); return ret; - } else { - /* - * The delay to sync PHY's status, the maximum delay is - * 2ms since the otgsc uses 1ms timer to debounce the - * PHY's input - */ - usleep_range(2000, 2500); } ci->hw_bank.phys = res->start; -- cgit v0.10.2 From 8076932ff2fc0f6db0172420e6b148a8b2e8c805 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:29 +0800 Subject: usb: chipidea: add system power management support Add system power management support Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index fe38805..bd74f27 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -791,11 +791,59 @@ static int ci_hdrc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static void ci_controller_suspend(struct ci_hdrc *ci) +{ + ci_hdrc_enter_lpm(ci, true); + + if (ci->usb_phy) + usb_phy_set_suspend(ci->usb_phy, 1); +} + +static int ci_controller_resume(struct device *dev) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + dev_dbg(dev, "at %s\n", __func__); + + ci_hdrc_enter_lpm(ci, false); + + if (ci->usb_phy) { + usb_phy_set_suspend(ci->usb_phy, 0); + usb_phy_set_wakeup(ci->usb_phy, false); + hw_wait_phy_stable(); + } + + return 0; +} + +static int ci_suspend(struct device *dev) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + + if (ci->wq) + flush_workqueue(ci->wq); + + ci_controller_suspend(ci); + + return 0; +} + +static int ci_resume(struct device *dev) +{ + return ci_controller_resume(dev); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops ci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ci_suspend, ci_resume) +}; static struct platform_driver ci_hdrc_driver = { .probe = ci_hdrc_probe, .remove = ci_hdrc_remove, .driver = { .name = "ci_hdrc", + .pm = &ci_pm_ops, .owner = THIS_MODULE, }, }; -- cgit v0.10.2 From 2558c1f53bbbb5848fd5910918b97b03249d3885 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:30 +0800 Subject: usb: chipidea: imx: add system power management support Add basic system power management support Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 8b1482a..75421c2 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -208,6 +208,41 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int imx_controller_suspend(struct device *dev) +{ + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + + dev_dbg(dev, "at %s\n", __func__); + + clk_disable_unprepare(data->clk); + + return 0; +} + +static int imx_controller_resume(struct device *dev) +{ + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + + dev_dbg(dev, "at %s\n", __func__); + + return clk_prepare_enable(data->clk); +} + +static int ci_hdrc_imx_suspend(struct device *dev) +{ + return imx_controller_suspend(dev); +} + +static int ci_hdrc_imx_resume(struct device *dev) +{ + return imx_controller_resume(dev); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) +}; static struct platform_driver ci_hdrc_imx_driver = { .probe = ci_hdrc_imx_probe, .remove = ci_hdrc_imx_remove, @@ -215,6 +250,7 @@ static struct platform_driver ci_hdrc_imx_driver = { .name = "imx_usb", .owner = THIS_MODULE, .of_match_table = ci_hdrc_imx_dt_ids, + .pm = &ci_hdrc_imx_pm_ops, }, }; -- cgit v0.10.2 From 947c88592f17bd299ff677049c3cda36cc6f93dd Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:31 +0800 Subject: usb: chipidea: remove flag CI_HDRC_REQUIRE_TRANSCEIVER Now, USB PHY is mandatory for chipidea core, the flag CI_HDRC_REQUIRE_TRANSCEIVER is useless. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 75421c2..450a168 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -106,8 +106,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) struct ci_hdrc_platform_data pdata = { .name = dev_name(&pdev->dev), .capoffset = DEF_CAPOFFSET, - .flags = CI_HDRC_REQUIRE_TRANSCEIVER | - CI_HDRC_DISABLE_STREAMING, + .flags = CI_HDRC_DISABLE_STREAMING, }; int ret; const struct of_device_id *of_id = diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 3edf969..d79ecc0 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -46,7 +46,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { .name = "ci_hdrc_msm", .capoffset = DEF_CAPOFFSET, .flags = CI_HDRC_REGS_SHARED | - CI_HDRC_REQUIRE_TRANSCEIVER | CI_HDRC_DISABLE_STREAMING, .notify_event = ci_hdrc_msm_notify_event, diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index c01bf4e..535997a 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -19,7 +19,6 @@ struct ci_hdrc_platform_data { enum usb_phy_interface phy_mode; unsigned long flags; #define CI_HDRC_REGS_SHARED BIT(0) -#define CI_HDRC_REQUIRE_TRANSCEIVER BIT(1) #define CI_HDRC_DISABLE_STREAMING BIT(3) /* * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, -- cgit v0.10.2 From cdd278f21eea55412dd0c5bc468bbdfb0639879b Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:32 +0800 Subject: usb: chipidea: add controller reset API Add controller reset API, currently it is used for device mode only. It may be used for host/otg driver in future. Ususally, we need this API for dual-role switch and back from hibernation suspend to let the controller at default state. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index bd74f27..48b25d9 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -385,20 +385,44 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) } /** - * hw_device_reset: resets chip (execute without interruption) + * hw_controller_reset: do controller reset * @ci: the controller * * This function returns an error code */ +static int hw_controller_reset(struct ci_hdrc *ci) +{ + int count = 0; + + hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); + while (hw_read(ci, OP_USBCMD, USBCMD_RST)) { + udelay(10); + if (count++ > 1000) + return -ETIMEDOUT; + } + + return 0; +} + +/** + * hw_device_reset: resets chip (execute without interruption) + * @ci: the controller + * + * This function returns an error code + */ int hw_device_reset(struct ci_hdrc *ci, u32 mode) { + int ret; + /* should flush & stop before reset */ hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); hw_write(ci, OP_USBCMD, USBCMD_RS, 0); - hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); - while (hw_read(ci, OP_USBCMD, USBCMD_RST)) - udelay(10); /* not RTOS friendly */ + ret = hw_controller_reset(ci); + if (ret) { + dev_err(ci->dev, "error resetting controller, ret=%d\n", ret); + return ret; + } if (ci->platdata->notify_event) ci->platdata->notify_event(ci, -- cgit v0.10.2 From 5b1573005a91dc448e6919d6bec076bedc7e1919 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:33 +0800 Subject: usb: chipidea: parameter 'mode' isn't needed for hw_device_reset The hw_device_reset is dedicated to be used at device mode initializaiton, so delete the parameter 'mode'. For host driver, the ehci driver will handle all things. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 5bbfcc7..65913d4 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -352,7 +352,7 @@ u32 hw_read_intr_enable(struct ci_hdrc *ci); u32 hw_read_intr_status(struct ci_hdrc *ci); -int hw_device_reset(struct ci_hdrc *ci, u32 mode); +int hw_device_reset(struct ci_hdrc *ci); int hw_port_test_set(struct ci_hdrc *ci, u8 mode); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 48b25d9..e43be34 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -410,7 +410,7 @@ static int hw_controller_reset(struct ci_hdrc *ci) * * This function returns an error code */ -int hw_device_reset(struct ci_hdrc *ci, u32 mode) +int hw_device_reset(struct ci_hdrc *ci) { int ret; @@ -440,12 +440,12 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) /* USBMODE should be configured step by step */ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); - hw_write(ci, OP_USBMODE, USBMODE_CM, mode); + hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC); /* HW >= 2.3 */ hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); - if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) { - pr_err("cannot enter in %s mode", ci_role(ci)->name); + if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) { + pr_err("cannot enter in %s device mode", ci_role(ci)->name); pr_err("lpm = %i", ci->hw_bank.lpm); return -ENODEV; } diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 368cc8e..7ef124d 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -543,7 +543,7 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on) ci_role_start(ci, CI_ROLE_HOST); } else { ci_role_stop(ci); - hw_device_reset(ci, USBMODE_CM_DC); + hw_device_reset(ci); ci_role_start(ci, CI_ROLE_GADGET); } mutex_lock(&fsm->lock); diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index bdaa7ba..4fe18ce 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1471,7 +1471,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) if (gadget_ready) { if (is_active) { pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(ci, USBMODE_CM_DC); + hw_device_reset(ci); hw_device_state(ci, ci->ep0out->qh.dma); usb_gadget_set_state(_gadget, USB_STATE_POWERED); } else { @@ -1660,7 +1660,7 @@ static int ci_udc_start(struct usb_gadget *gadget, pm_runtime_get_sync(&ci->gadget.dev); if (ci->vbus_active) { spin_lock_irqsave(&ci->lock, flags); - hw_device_reset(ci, USBMODE_CM_DC); + hw_device_reset(ci); } else { pm_runtime_put_sync(&ci->gadget.dev); return retval; -- cgit v0.10.2 From 14b4099c074f2ddf4d84b22d370170e61b527529 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 26 Nov 2014 13:44:34 +0800 Subject: usb: chipidea: remove duplicate dev_set_drvdata for host_start The core driver has already done it, besides, move set driver data operation just after ci has allocated successfully in case some code (like ci_role_start) want to access this driver data. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index e43be34..de1e4a8 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -669,6 +669,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ci) return -ENOMEM; + platform_set_drvdata(pdev, ci); ci->dev = dev; ci->platdata = dev_get_platdata(dev); ci->imx28_write_fix = !!(ci->platdata->flags & @@ -782,7 +783,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) } } - platform_set_drvdata(pdev, ci); ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name, ci); if (ret) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 48731d0..c1694cf 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -91,7 +91,6 @@ static int host_start(struct ci_hdrc *ci) if (!hcd) return -ENOMEM; - dev_set_drvdata(ci->dev, ci); hcd->rsrc_start = ci->hw_bank.phys; hcd->rsrc_len = ci->hw_bank.size; hcd->regs = ci->hw_bank.abs; -- cgit v0.10.2 From 21a5b579cb63364b90e545e7e0a4bccb027711e8 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 26 Nov 2014 13:44:35 +0800 Subject: usb: chipidea: fix phy handling The generic plaftorm device for ChipIdea drivers is probed by calling ci_hdrc_probe. The device structure used is not the one of the specific ChipIdea driver but the one of the generic ChipIdea platform device. This results in not being able to probe the PHYs as we're not using the right device structure. Since all ChipIdea drivers are retrieving their PHYs in their specific driver code, this didn't impact any of them yet. Fixes it using the right device structure (dev->parent). Signed-off-by: Antoine Tenart Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index de1e4a8..068e0c6 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -686,8 +686,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) } else if (ci->platdata->usb_phy) { ci->usb_phy = ci->platdata->usb_phy; } else { - ci->phy = devm_phy_get(dev, "usb-phy"); - ci->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + ci->phy = devm_phy_get(dev->parent, "usb-phy"); + ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2); /* if both generic PHY and USB PHY layers aren't enabled */ if (PTR_ERR(ci->phy) == -ENOSYS && -- cgit v0.10.2 From 10a062cefcfb1f6154a66f9872efc11543eeb3f8 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 26 Nov 2014 13:44:36 +0800 Subject: usb: chipidea: add a usb2 driver for ci13xxx Add a USB2 ChipIdea driver for ci13xxx, with optional PHY, clock and DMA mask, to support USB2 ChipIdea controllers that don't need specific functions. Tested on the Marvell Berlin SoCs USB controllers. Signed-off-by: Antoine Tenart Tested-by: Soren Brinkmann Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 2f099c7..1fc86a2 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -10,6 +10,7 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o # Glue/Bridge layers go here +obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_usb2.o obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_zevio.o diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c new file mode 100644 index 0000000..61d8e55 --- /dev/null +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2014 Marvell Technology Group Ltd. + * + * Antoine Tenart + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ci.h" + +struct ci_hdrc_usb2_priv { + struct platform_device *ci_pdev; + struct clk *clk; +}; + +static struct ci_hdrc_platform_data ci_default_pdata = { + .capoffset = DEF_CAPOFFSET, + .flags = CI_HDRC_DISABLE_STREAMING, +}; + +static int ci_hdrc_usb2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ci_hdrc_usb2_priv *priv; + struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev); + int ret; + + if (!ci_pdata) + ci_pdata = &ci_default_pdata; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->clk = devm_clk_get(dev, NULL); + if (!IS_ERR(priv->clk)) { + ret = clk_prepare_enable(priv->clk); + if (ret) { + dev_err(dev, "failed to enable the clock: %d\n", ret); + return ret; + } + } + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + goto clk_err; + + ci_pdata->name = dev_name(dev); + + priv->ci_pdev = ci_hdrc_add_device(dev, pdev->resource, + pdev->num_resources, ci_pdata); + if (IS_ERR(priv->ci_pdev)) { + ret = PTR_ERR(priv->ci_pdev); + if (ret != -EPROBE_DEFER) + dev_err(dev, + "failed to register ci_hdrc platform device: %d\n", + ret); + goto clk_err; + } + + platform_set_drvdata(pdev, priv); + + pm_runtime_no_callbacks(dev); + pm_runtime_enable(dev); + + return 0; + +clk_err: + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + return ret; +} + +static int ci_hdrc_usb2_remove(struct platform_device *pdev) +{ + struct ci_hdrc_usb2_priv *priv = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + ci_hdrc_remove_device(priv->ci_pdev); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static const struct of_device_id ci_hdrc_usb2_of_match[] = { + { .compatible = "chipidea,usb2" }, + { } +}; +MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match); + +static struct platform_driver ci_hdrc_usb2_driver = { + .probe = ci_hdrc_usb2_probe, + .remove = ci_hdrc_usb2_remove, + .driver = { + .name = "chipidea-usb2", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ci_hdrc_usb2_of_match), + }, +}; +module_platform_driver(ci_hdrc_usb2_driver); + +MODULE_DESCRIPTION("ChipIdea HDRC USB2 binding for ci13xxx"); +MODULE_AUTHOR("Antoine Tenart "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From d7d30c911dd957e274c3da6910d4286862ab1d78 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 26 Nov 2014 13:44:37 +0800 Subject: Documentation: bindings: add doc for the USB2 ChipIdea USB driver Document the USB2 ChipIdea driver (ci13xxx) bindings. Signed-off-by: Antoine Tenart Acked-by: Peter Chen Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt new file mode 100644 index 0000000..27f8b1e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -0,0 +1,24 @@ +* USB2 ChipIdea USB controller for ci13xxx + +Required properties: +- compatible: should be "chipidea,usb2" +- reg: base address and length of the registers +- interrupts: interrupt for the USB controller + +Optional properties: +- clocks: reference to the USB clock +- phys: reference to the USB PHY +- phy-names: should be "usb-phy" +- vbus-supply: reference to the VBUS regulator + +Example: + + usb@f7ed0000 { + compatible = "chipidea,usb2"; + reg = <0xf7ed0000 0x10000>; + interrupts = ; + clocks = <&chip CLKID_USB0>; + phys = <&usb_phy0>; + phy-names = "usb-phy"; + vbus-supply = <®_usb0_vbus>; + }; -- cgit v0.10.2 From 6629467ba5502cac22d31950e207a0334f2a0de5 Mon Sep 17 00:00:00 2001 From: Mickael Maison Date: Wed, 26 Nov 2014 13:44:38 +0800 Subject: usb: chipidea: Fixed a few typos in comments Fixed typos in comments of 2 drivers/usb/chipidea files Signed-off-by: Mickael Maison Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 068e0c6..e14eafb 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -549,7 +549,7 @@ static int ci_get_platdata(struct device *dev, if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { return -EPROBE_DEFER; } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { - /* no vbus regualator is needed */ + /* no vbus regulator is needed */ platdata->reg_vbus = NULL; } else if (IS_ERR(platdata->reg_vbus)) { dev_err(dev, "Getting regulator error: %ld\n", diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 7ef124d..562e581 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -303,7 +303,7 @@ static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator) set_tmout(ci, indicator); /* Disable port power */ hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 0); - /* Clear exsiting DP irq */ + /* Clear existing DP irq */ hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); /* Enable data pulse irq */ hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE); @@ -663,7 +663,7 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci) fsm->b_bus_suspend = 1; /* * Init a timer to know how long this suspend - * will contine, if time out, indicates B no longer + * will continue, if time out, indicates B no longer * wants to be host role */ ci_otg_add_timer(ci, A_BIDL_ADIS); -- cgit v0.10.2 From 67c3c5e28e9bc1dd244829ba7eac8a446da96ff3 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 27 Nov 2014 03:16:33 +0800 Subject: usb: chipidea: fix platform_no_drv_owner.cocci warnings drivers/usb/chipidea/ci_hdrc_usb2.c:108:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Cc: Antoine Tenart Cc: Peter Chen Signed-off-by: Fengguang Wu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index 61d8e55..45844c9 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -105,7 +105,6 @@ static struct platform_driver ci_hdrc_usb2_driver = { .remove = ci_hdrc_usb2_remove, .driver = { .name = "chipidea-usb2", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(ci_hdrc_usb2_of_match), }, }; -- cgit v0.10.2 From fc625960edecfb57e62c2975d1f155155e28e6ba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 26 Nov 2014 17:06:49 +0300 Subject: USB: adutux: NULL dereferences on disconnect Both "dev->udev" and "interface->dev" are NULL. These printks are not very interesting so I just deleted them. Fixes: 03270634e242 ('USB: Add ADU support for Ontrak ADU devices') Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 493c7f2..3071c0e 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -814,15 +814,10 @@ static void adu_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); /* if the device is not opened, then we clean up right now */ - dev_dbg(&dev->udev->dev, "%s : open count %d\n", - __func__, dev->open_count); if (!dev->open_count) adu_delete(dev); mutex_unlock(&adutux_mutex); - - dev_info(&interface->dev, "ADU device adutux%d now disconnected\n", - (minor - ADU_MINOR_BASE)); } /* usb specific object needed to register this driver with the usb subsystem */ -- cgit v0.10.2 From 69defe04ec825e42e0d719cca5a23f48b624bee9 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 27 Nov 2014 18:19:14 +0200 Subject: xhci: cleanup finish_td function Remove unnecessary else after return, dropping extra indentation depth. No functional changes. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 06433ae..5f60932 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1813,72 +1813,65 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, if (skip) goto td_cleanup; - if (trb_comp_code == COMP_STOP_INVAL || - trb_comp_code == COMP_STOP) { + if (trb_comp_code == COMP_STOP_INVAL || trb_comp_code == COMP_STOP) { /* The Endpoint Stop Command completion will take care of any * stopped TDs. A stopped TD may be restarted, so don't update * the ring dequeue pointer or take this TD off any lists yet. */ ep->stopped_td = td; return 0; + } + if (trb_comp_code == COMP_STALL || + xhci_requires_manual_halt_cleanup(xhci, ep_ctx, + trb_comp_code)) { + /* Issue a reset endpoint command to clear the host side + * halt, followed by a set dequeue command to move the + * dequeue pointer past the TD. + * The class driver clears the device side halt later. + */ + xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, + ep_ring->stream_id, td, event_trb); } else { - if (trb_comp_code == COMP_STALL || - xhci_requires_manual_halt_cleanup(xhci, ep_ctx, - trb_comp_code)) { - /* Issue a reset endpoint command to clear the host side - * halt, followed by a set dequeue command to move the - * dequeue pointer past the TD. - * The class driver clears the device side halt later. - */ - xhci_cleanup_halted_endpoint(xhci, - slot_id, ep_index, ep_ring->stream_id, - td, event_trb); - } else { - /* Update ring dequeue pointer */ - while (ep_ring->dequeue != td->last_trb) - inc_deq(xhci, ep_ring); + /* Update ring dequeue pointer */ + while (ep_ring->dequeue != td->last_trb) inc_deq(xhci, ep_ring); - } + inc_deq(xhci, ep_ring); + } td_cleanup: - /* Clean up the endpoint's TD list */ - urb = td->urb; - urb_priv = urb->hcpriv; - - /* Do one last check of the actual transfer length. - * If the host controller said we transferred more data than - * the buffer length, urb->actual_length will be a very big - * number (since it's unsigned). Play it safe and say we didn't - * transfer anything. - */ - if (urb->actual_length > urb->transfer_buffer_length) { - xhci_warn(xhci, "URB transfer length is wrong, " - "xHC issue? req. len = %u, " - "act. len = %u\n", - urb->transfer_buffer_length, - urb->actual_length); - urb->actual_length = 0; - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - *status = -EREMOTEIO; - else - *status = 0; - } - list_del_init(&td->td_list); - /* Was this TD slated to be cancelled but completed anyway? */ - if (!list_empty(&td->cancelled_td_list)) - list_del_init(&td->cancelled_td_list); - - urb_priv->td_cnt++; - /* Giveback the urb when all the tds are completed */ - if (urb_priv->td_cnt == urb_priv->length) { - ret = 1; - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--; - if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs - == 0) { - if (xhci->quirks & XHCI_AMD_PLL_FIX) - usb_amd_quirk_pll_enable(); - } + /* Clean up the endpoint's TD list */ + urb = td->urb; + urb_priv = urb->hcpriv; + + /* Do one last check of the actual transfer length. + * If the host controller said we transferred more data than the buffer + * length, urb->actual_length will be a very big number (since it's + * unsigned). Play it safe and say we didn't transfer anything. + */ + if (urb->actual_length > urb->transfer_buffer_length) { + xhci_warn(xhci, "URB transfer length is wrong, xHC issue? req. len = %u, act. len = %u\n", + urb->transfer_buffer_length, + urb->actual_length); + urb->actual_length = 0; + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) + *status = -EREMOTEIO; + else + *status = 0; + } + list_del_init(&td->td_list); + /* Was this TD slated to be cancelled but completed anyway? */ + if (!list_empty(&td->cancelled_td_list)) + list_del_init(&td->cancelled_td_list); + + urb_priv->td_cnt++; + /* Giveback the urb when all the tds are completed */ + if (urb_priv->td_cnt == urb_priv->length) { + ret = 1; + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--; + if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { + if (xhci->quirks & XHCI_AMD_PLL_FIX) + usb_amd_quirk_pll_enable(); } } } -- cgit v0.10.2 From 4801d4ea559440b7d63babdac1b1b43a13ac7562 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 27 Nov 2014 18:19:15 +0200 Subject: xhci: clear extra bits from slot context when setting max exit latency If we need to change the max exit latency with a Evaluate Context command, we copy the old output slot context and use it as input context for the command. This also copies the dev_state bits which are supposed to be zero in the input slot context. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 033b46c..0ea7e12 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4009,6 +4009,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx); slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT)); slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency); + slot_ctx->dev_state = 0; xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, "Set up evaluate context for LPM MEL change."); -- cgit v0.10.2 From d97b4f8d690b9fc0e7dd4f4ff5aaea838254e350 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 27 Nov 2014 18:19:16 +0200 Subject: xhci: don't use the same variable for stopped and halted rings current TD Endpoints halted on errors, and endpoints stopped manually both used the same ep->stopped_td to store the halted or stopped td. this causes confusion and possible races. There is no longer a need to use the ep->stopped_td variable to store the halted TD. A halted endpoint is handled immediately and we can pass it to the handling function directly. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5f60932..e692e76 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -716,9 +716,7 @@ remove_finished_td: ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } - /* Clear stopped_td if endpoint is not halted */ - if (!(ep->ep_state & EP_HALTED)) - ep->stopped_td = NULL; + ep->stopped_td = NULL; /* * Drop the lock and complete the URBs in the cancelled TD list. @@ -1732,13 +1730,11 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, return; ep->ep_state |= EP_HALTED; - ep->stopped_td = td; ep->stopped_stream = stream_id; xhci_queue_reset_ep(xhci, command, slot_id, ep_index); - xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); + xhci_cleanup_stalled_ring(xhci, ep_index, td); - ep->stopped_td = NULL; ep->stopped_stream = 0; xhci_ring_cmd_db(xhci); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 0ea7e12..5be1bff 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2912,10 +2912,11 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, } void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, - struct usb_device *udev, unsigned int ep_index) + unsigned int ep_index, struct xhci_td *td) { struct xhci_dequeue_state deq_state; struct xhci_virt_ep *ep; + struct usb_device *udev = td->urb->dev; xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, "Cleaning up stalled endpoint ring"); @@ -2924,8 +2925,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, * or it will attempt to resend it on the next doorbell ring. */ xhci_find_new_dequeue_state(xhci, udev->slot_id, - ep_index, ep->stopped_stream, ep->stopped_td, - &deq_state); + ep_index, ep->stopped_stream, td, &deq_state); if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg) return; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d745715..053c9ea 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1825,7 +1825,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, unsigned int stream_id, struct xhci_dequeue_state *deq_state); void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, - struct usb_device *udev, unsigned int ep_index); + unsigned int ep_index, struct xhci_td *td); void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); -- cgit v0.10.2 From e1fd1dc831fa0e1a4c090d0fc018ccce77569236 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Thu, 27 Nov 2014 18:19:17 +0200 Subject: usb: xhci: fix comment for PORT_DEV_REMOVE According to xHCI specification, PORT_DEV_REMOVE(bit 30) in PORTSC true means "Device is non-removable". Reported-by: Juro Bystricky Signed-off-by: Lu Baolu Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 053c9ea..cc7c5bb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -358,7 +358,7 @@ struct xhci_op_regs { /* wake on over-current (enable) */ #define PORT_WKOC_E (1 << 27) /* bits 28:29 reserved */ -/* true: device is removable - for USB 3.0 roothub emulation */ +/* true: device is non-removable - for USB 3.0 roothub emulation */ #define PORT_DEV_REMOVE (1 << 30) /* Initiate a warm port reset - complete when PORT_WRC is '1' */ #define PORT_WR (1 << 31) -- cgit v0.10.2 From b19e5f04cd628c012c26a025cf93da5233df134d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 Nov 2014 19:14:15 +0100 Subject: usbip: remove unneeded structure Delete a local structure that is only used to be initialized by memset. A semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x,i; @@ { ... when any -struct i x; <+... when != x - memset(&x,...); ...+> } // Signed-off-by: Julia Lawall Acked-by: Valentina Manea Signed-off-by: Greg Kroah-Hartman diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index 2f87f2d..2a7cd2b 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c @@ -91,7 +91,6 @@ static void usbipd_help(void) static int recv_request_import(int sockfd) { struct op_import_request req; - struct op_common reply; struct usbip_exported_device *edev; struct usbip_usb_device pdu_udev; struct list_head *i; @@ -100,7 +99,6 @@ static int recv_request_import(int sockfd) int rc; memset(&req, 0, sizeof(req)); - memset(&reply, 0, sizeof(reply)); rc = usbip_net_recv(sockfd, &req, sizeof(req)); if (rc < 0) { -- cgit v0.10.2 From eb94ec7a6516cd1dc52c0f63d7c3a274e6337416 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 Nov 2014 18:03:49 +0100 Subject: wusb: replace memset by memzero_explicit Memset on a local variable may be removed when it is called just before the variable goes out of scope. Using memzero_explicit defeats this optimization. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ identifier x; type T; @@ { ... when any T x[...]; ... when any when exists - memset + memzero_explicit (x, -0, ...) ... when != x when strict } // This change was suggested by Daniel Borkmann Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c index 1018345..415b140 100644 --- a/drivers/usb/wusbcore/dev-sysfs.c +++ b/drivers/usb/wusbcore/dev-sysfs.c @@ -101,7 +101,7 @@ static ssize_t wusb_ck_store(struct device *dev, if (wusbhc == NULL) return -ENODEV; result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck); - memset(&ck, 0, sizeof(ck)); + memzero_explicit(&ck, sizeof(ck)); wusbhc_put(wusbhc); return result < 0 ? result : size; } diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index cc74d66..b66faaf 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -522,10 +522,10 @@ error_hs3: error_hs2: error_hs1: memset(hs, 0, 3*sizeof(hs[0])); - memset(&keydvt_out, 0, sizeof(keydvt_out)); - memset(&keydvt_in, 0, sizeof(keydvt_in)); - memset(&ccm_n, 0, sizeof(ccm_n)); - memset(mic, 0, sizeof(mic)); + memzero_explicit(&keydvt_out, sizeof(keydvt_out)); + memzero_explicit(&keydvt_in, sizeof(keydvt_in)); + memzero_explicit(&ccm_n, sizeof(ccm_n)); + memzero_explicit(mic, sizeof(mic)); if (result < 0) wusb_dev_set_encryption(usb_dev, 0); error_dev_set_encryption: -- cgit v0.10.2 From 6aeab4775262a606b56fef5272ec045ff647602e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 29 Nov 2014 15:49:54 +0300 Subject: USB: mos7720: delete some unneeded code The "status" is uninitialized so this creates a static checker warning. But it's harmless, we can just delete it. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 312b0fe..4f70df3 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1299,8 +1299,6 @@ static void mos7720_throttle(struct tty_struct *tty) mos7720_port->shadowMCR &= ~UART_MCR_RTS; write_mos_reg(port->serial, port->port_number, MCR, mos7720_port->shadowMCR); - if (status != 0) - return; } } @@ -1331,8 +1329,6 @@ static void mos7720_unthrottle(struct tty_struct *tty) mos7720_port->shadowMCR |= UART_MCR_RTS; write_mos_reg(port->serial, port->port_number, MCR, mos7720_port->shadowMCR); - if (status != 0) - return; } } -- cgit v0.10.2 From 016040268ccafaa7ad74ef88708d54fedeb87072 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 29 Nov 2014 15:49:17 +0300 Subject: usb: gadget: udc: missing curly braces There were curly braces intended here. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index 15da5b1..ff67cea 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -457,10 +457,11 @@ static int setup_bd_list_xfr(struct bdc *bdc, struct bdc_req *req, int num_bds) dword3 |= BD_SOT|BD_SBF|(tfs<ep_num == 1) + if (ep->ep_num == 1) { ret = setup_first_bd_ep0(bdc, req, &dword3); if (ret) return ret; + } } if (!req->ep->dir) dword3 |= BD_ISP; -- cgit v0.10.2 From 3ff67445750a84de67faaf52c6e1895cb09f2c56 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 29 Nov 2014 01:29:10 +0300 Subject: usbip: fix error handling in stub_probe() If usb_hub_claim_port() fails, no resources are deallocated and if stub_add_files() fails, port is not released. The patch fixes these issues and rearranges error handling code. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Valentina Manea Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index fac20e0..a3ec49b 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -311,7 +311,6 @@ static int stub_probe(struct usb_device *udev) { struct stub_device *sdev = NULL; const char *udev_busid = dev_name(&udev->dev); - int err = 0; struct bus_id_priv *busid_priv; int rc; @@ -372,23 +371,28 @@ static int stub_probe(struct usb_device *udev) (struct usb_dev_state *) udev); if (rc) { dev_dbg(&udev->dev, "unable to claim port\n"); - return rc; + goto err_port; } - err = stub_add_files(&udev->dev); - if (err) { + rc = stub_add_files(&udev->dev); + if (rc) { dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid); - dev_set_drvdata(&udev->dev, NULL); - usb_put_dev(udev); - kthread_stop_put(sdev->ud.eh); - - busid_priv->sdev = NULL; - stub_device_free(sdev); - return err; + goto err_files; } busid_priv->status = STUB_BUSID_ALLOC; return 0; +err_files: + usb_hub_release_port(udev->parent, udev->portnum, + (struct usb_dev_state *) udev); +err_port: + dev_set_drvdata(&udev->dev, NULL); + usb_put_dev(udev); + kthread_stop_put(sdev->ud.eh); + + busid_priv->sdev = NULL; + stub_device_free(sdev); + return rc; } static void shutdown_busid(struct bus_id_priv *busid_priv) -- cgit v0.10.2 From 81e1dadfb5b2d47aa513ad60b1c9cf0ea17b6514 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 4 Dec 2014 11:54:43 +0530 Subject: arm: omap3: twl: remove usb phy init data commit dbc98635e0d4 ("phy: remove the old lookup method") removes struct phy_consumer but twl-common.c still uses the "phy_consumer" structure resulting in the following compilation warning. arch/arm/mach-omap2/twl-common.c:94:21: error: array type has incomplete element type struct phy_consumer consumers[] = { Removed using phy_consumer since twl4030 uses the new lookup method. Signed-off-by: Heikki Krogerus Signed-off-by: Kishon Vijay Abraham I Reported-by: Stephen Rothwell Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index b0d54da..4457e73 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -91,18 +91,8 @@ void __init omap_pmic_late_init(void) } #if defined(CONFIG_ARCH_OMAP3) -struct phy_consumer consumers[] = { - PHY_CONSUMER("musb-hdrc.0", "usb"), -}; - -struct phy_init_data init_data = { - .consumers = consumers, - .num_consumers = ARRAY_SIZE(consumers), -}; - static struct twl4030_usb_data omap3_usb_pdata = { - .usb_mode = T2_USB_MODE_ULPI, - .init_data = &init_data, + .usb_mode = T2_USB_MODE_ULPI, }; static int omap3_batt_table[] = { diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 8cfb50f..0bc03f1 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -26,7 +26,6 @@ #define __TWL_H_ #include -#include #include /* @@ -634,7 +633,6 @@ enum twl4030_usb_mode { struct twl4030_usb_data { enum twl4030_usb_mode usb_mode; unsigned long features; - struct phy_init_data *init_data; int (*phy_init)(struct device *dev); int (*phy_exit)(struct device *dev); -- cgit v0.10.2