summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc2')
-rw-r--r--drivers/usb/dwc2/core_intr.c7
-rw-r--r--drivers/usb/dwc2/gadget.c46
-rw-r--r--drivers/usb/dwc2/params.c2
-rw-r--r--drivers/usb/dwc2/platform.c18
4 files changed, 55 insertions, 18 deletions
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 6af6add3d4c0..6272b4ae4740 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -421,10 +421,13 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit power_down failed\n");
+ /* Change to L0 state */
+ hsotg->lx_state = DWC2_L0;
call_gadget(hsotg, resume);
+ } else {
+ /* Change to L0 state */
+ hsotg->lx_state = DWC2_L0;
}
- /* Change to L0 state */
- hsotg->lx_state = DWC2_L0;
} else {
if (hsotg->params.power_down)
return;
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 7fd0900a9cb0..70ac47a341ac 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -712,8 +712,11 @@ static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
*/
static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep)
{
+ const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc;
int is_isoc = hs_ep->isochronous;
unsigned int maxsize;
+ u32 mps = hs_ep->ep.maxpacket;
+ int dir_in = hs_ep->dir_in;
if (is_isoc)
maxsize = (hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT :
@@ -722,6 +725,11 @@ static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep)
else
maxsize = DEV_DMA_NBYTES_LIMIT * MAX_DMA_DESC_NUM_GENERIC;
+ /* Interrupt OUT EP with mps not multiple of 4 */
+ if (hs_ep->index)
+ if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4))
+ maxsize = mps * MAX_DMA_DESC_NUM_GENERIC;
+
return maxsize;
}
@@ -737,11 +745,14 @@ static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep)
* Isochronous - descriptor rx/tx bytes bitfield limit,
* Control In/Bulk/Interrupt - multiple of mps. This will allow to not
* have concatenations from various descriptors within one packet.
+ * Interrupt OUT - if mps not multiple of 4 then a single packet corresponds
+ * to a single descriptor.
*
* Selects corresponding mask for RX/TX bytes as well.
*/
static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask)
{
+ const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc;
u32 mps = hs_ep->ep.maxpacket;
int dir_in = hs_ep->dir_in;
u32 desc_size = 0;
@@ -765,6 +776,13 @@ static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask)
desc_size -= desc_size % mps;
}
+ /* Interrupt OUT EP with mps not multiple of 4 */
+ if (hs_ep->index)
+ if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) {
+ desc_size = mps;
+ *mask = DEV_DMA_NBYTES_MASK;
+ }
+
return desc_size;
}
@@ -1123,13 +1141,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
length += (mps - (length % mps));
}
- /*
- * If more data to send, adjust DMA for EP0 out data stage.
- * ureq->dma stays unchanged, hence increment it by already
- * passed passed data count before starting new transaction.
- */
- if (!index && hsotg->ep0_state == DWC2_EP0_DATA_OUT &&
- continuing)
+ if (continuing)
offset = ureq->actual;
/* Fill DDMA chain entries */
@@ -2319,22 +2331,36 @@ static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg,
*/
static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep)
{
+ const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc;
struct dwc2_hsotg *hsotg = hs_ep->parent;
unsigned int bytes_rem = 0;
+ unsigned int bytes_rem_correction = 0;
struct dwc2_dma_desc *desc = hs_ep->desc_list;
int i;
u32 status;
+ u32 mps = hs_ep->ep.maxpacket;
+ int dir_in = hs_ep->dir_in;
if (!desc)
return -EINVAL;
+ /* Interrupt OUT EP with mps not multiple of 4 */
+ if (hs_ep->index)
+ if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4))
+ bytes_rem_correction = 4 - (mps % 4);
+
for (i = 0; i < hs_ep->desc_count; ++i) {
status = desc->status;
bytes_rem += status & DEV_DMA_NBYTES_MASK;
+ bytes_rem -= bytes_rem_correction;
if (status & DEV_DMA_STS_MASK)
dev_err(hsotg->dev, "descriptor %d closed with %x\n",
i, status & DEV_DMA_STS_MASK);
+
+ if (status & DEV_DMA_L)
+ break;
+
desc++;
}
@@ -4886,12 +4912,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
epnum, 0);
}
- ret = usb_add_gadget_udc(dev, &hsotg->gadget);
- if (ret) {
- dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep,
- hsotg->ctrl_req);
- return ret;
- }
dwc2_hsotg_dump(hsotg);
return 0;
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 31e090ac9f1e..6d3812678b8c 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -846,7 +846,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
int dwc2_init_params(struct dwc2_hsotg *hsotg)
{
const struct of_device_id *match;
- void (*set_params)(void *data);
+ void (*set_params)(struct dwc2_hsotg *data);
dwc2_set_default_params(hsotg);
dwc2_get_device_properties(hsotg);
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 3c6ce09a6db5..34bb6124f1e2 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -337,7 +337,8 @@ static void dwc2_driver_shutdown(struct platform_device *dev)
{
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
- disable_irq(hsotg->irq);
+ dwc2_disable_global_interrupts(hsotg);
+ synchronize_irq(hsotg->irq);
}
/**
@@ -507,10 +508,23 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
dwc2_lowlevel_hw_disable(hsotg);
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
+ IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+ /* Postponed adding a new gadget to the udc class driver list */
+ if (hsotg->gadget_enabled) {
+ retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget);
+ if (retval) {
+ hsotg->gadget.udc = NULL;
+ dwc2_hsotg_remove(hsotg);
+ goto error;
+ }
+ }
+#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
return 0;
error:
- dwc2_lowlevel_hw_disable(hsotg);
+ if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL)
+ dwc2_lowlevel_hw_disable(hsotg);
return retval;
}