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 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 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 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 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 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 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 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 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