summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc2/gadget.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc2/gadget.c')
-rw-r--r--drivers/usb/dwc2/gadget.c138
1 files changed, 86 insertions, 52 deletions
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index ce6071d65d51..7b5856fadd93 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -182,16 +182,33 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
/* start at the end of the GNPTXFSIZ, rounded up */
addr = 2048 + 1024;
- size = 768;
/*
- * currently we allocate TX FIFOs for all possible endpoints,
- * and assume that they are all the same size.
+ * Because we have not enough memory to have each TX FIFO of size at
+ * least 3072 bytes (the maximum single packet size), we create four
+ * FIFOs of lenght 1024, and four of length 3072 bytes, and assing
+ * them to endpoints dynamically according to maxpacket size value of
+ * given endpoint.
*/
- for (ep = 1; ep <= 15; ep++) {
+ /* 256*4=1024 bytes FIFO length */
+ size = 256;
+ for (ep = 1; ep <= 4; ep++) {
val = addr;
val |= size << FIFOSIZE_DEPTH_SHIFT;
+ WARN_ONCE(addr + size > hsotg->fifo_mem,
+ "insufficient fifo memory");
+ addr += size;
+
+ writel(val, hsotg->regs + DPTXFSIZN(ep));
+ }
+ /* 768*4=3072 bytes FIFO length */
+ size = 768;
+ for (ep = 5; ep <= 8; ep++) {
+ val = addr;
+ val |= size << FIFOSIZE_DEPTH_SHIFT;
+ WARN_ONCE(addr + size > hsotg->fifo_mem,
+ "insufficient fifo memory");
addr += size;
writel(val, hsotg->regs + DPTXFSIZN(ep));
@@ -987,8 +1004,8 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
hs_req = ep->req;
ep->req = NULL;
list_del_init(&hs_req->queue);
- hs_req->req.complete(&ep->ep,
- &hs_req->req);
+ usb_gadget_giveback_request(&ep->ep,
+ &hs_req->req);
}
/* If we have pending request, then start it */
@@ -1245,7 +1262,7 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
if (hs_req->req.complete) {
spin_unlock(&hsotg->lock);
- hs_req->req.complete(&hs_ep->ep, &hs_req->req);
+ usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req);
spin_lock(&hsotg->lock);
}
@@ -1832,7 +1849,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
if (dir_in) {
int epctl = readl(hsotg->regs + epctl_reg);
- s3c_hsotg_txfifo_flush(hsotg, idx);
+ s3c_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
if ((epctl & DXEPCTL_STALL) &&
(epctl & DXEPCTL_EPTYPE_BULK)) {
@@ -1981,6 +1998,7 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
int result, bool force)
{
struct s3c_hsotg_req *req, *treq;
+ unsigned size;
list_for_each_entry_safe(req, treq, &ep->queue, queue) {
/*
@@ -1994,9 +2012,11 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
s3c_hsotg_complete_request(hsotg, ep, req,
result);
}
- if (hsotg->dedicated_fifos)
- if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072)
- s3c_hsotg_txfifo_flush(hsotg, ep->index);
+ if (!hsotg->dedicated_fifos)
+ return;
+ size = (readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4;
+ if (size < ep->fifo_size)
+ s3c_hsotg_txfifo_flush(hsotg, ep->fifo_index);
}
/**
@@ -2437,6 +2457,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
u32 epctrl;
u32 mps;
int dir_in;
+ int i, val, size;
int ret = 0;
dev_dbg(hsotg->dev,
@@ -2509,17 +2530,8 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
break;
case USB_ENDPOINT_XFER_INT:
- if (dir_in) {
- /*
- * Allocate our TxFNum by simply using the index
- * of the endpoint for the moment. We could do
- * something better if the host indicates how
- * many FIFOs we are expecting to use.
- */
-
+ if (dir_in)
hs_ep->periodic = 1;
- epctrl |= DXEPCTL_TXFNUM(index);
- }
epctrl |= DXEPCTL_EPTYPE_INTERRUPT;
break;
@@ -2533,8 +2545,25 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
* if the hardware has dedicated fifos, we must give each IN EP
* a unique tx-fifo even if it is non-periodic.
*/
- if (dir_in && hsotg->dedicated_fifos)
- epctrl |= DXEPCTL_TXFNUM(index);
+ if (dir_in && hsotg->dedicated_fifos) {
+ size = hs_ep->ep.maxpacket*hs_ep->mc;
+ for (i = 1; i <= 8; ++i) {
+ if (hsotg->fifo_map & (1<<i))
+ continue;
+ val = readl(hsotg->regs + DPTXFSIZN(i));
+ val = (val >> FIFOSIZE_DEPTH_SHIFT)*4;
+ if (val < size)
+ continue;
+ hsotg->fifo_map |= 1<<i;
+
+ epctrl |= DXEPCTL_TXFNUM(i);
+ hs_ep->fifo_index = i;
+ hs_ep->fifo_size = val;
+ break;
+ }
+ if (i == 8)
+ return -ENOMEM;
+ }
/* for non control endpoints, set PID to D0 */
if (index)
@@ -2568,7 +2597,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
u32 epctrl_reg;
u32 ctrl;
- dev_info(hsotg->dev, "%s(ep %p)\n", __func__, ep);
+ dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
if (ep == &hsotg->eps[0].ep) {
dev_err(hsotg->dev, "%s: called for ep0\n", __func__);
@@ -2581,6 +2610,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
/* terminate all requests with shutdown */
kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
+ hsotg->fifo_map &= ~(1<<hs_ep->fifo_index);
+ hs_ep->fifo_index = 0;
+ hs_ep->fifo_size = 0;
ctrl = readl(hsotg->regs + epctrl_reg);
ctrl &= ~DXEPCTL_EPENA;
@@ -2626,7 +2658,7 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
struct s3c_hsotg *hs = hs_ep->parent;
unsigned long flags;
- dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
+ dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
spin_lock_irqsave(&hs->lock, flags);
@@ -2861,6 +2893,8 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+ clk_enable(hsotg->clk);
+
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
if (ret) {
@@ -2909,6 +2943,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
+ clk_disable(hsotg->clk);
+
return 0;
}
@@ -2935,13 +2971,15 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
struct s3c_hsotg *hsotg = to_hsotg(gadget);
unsigned long flags = 0;
- dev_dbg(hsotg->dev, "%s: is_in: %d\n", __func__, is_on);
+ dev_dbg(hsotg->dev, "%s: is_on: %d\n", __func__, is_on);
spin_lock_irqsave(&hsotg->lock, flags);
if (is_on) {
s3c_hsotg_phy_enable(hsotg);
+ clk_enable(hsotg->clk);
s3c_hsotg_core_init(hsotg);
} else {
+ clk_disable(hsotg->clk);
s3c_hsotg_phy_disable(hsotg);
}
@@ -2972,7 +3010,6 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
int epnum)
{
- u32 ptxfifo;
char *dir;
if (epnum == 0)
@@ -3001,15 +3038,6 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
hs_ep->ep.ops = &s3c_hsotg_ep_ops;
/*
- * Read the FIFO size for the Periodic TX FIFO, even if we're
- * an OUT endpoint, we may as well do this if in future the
- * code is changed to make each endpoint's direction changeable.
- */
-
- ptxfifo = readl(hsotg->regs + DPTXFSIZN(epnum));
- hs_ep->fifo_size = FIFOSIZE_DEPTH_GET(ptxfifo) * 4;
-
- /*
* if we're using dma, we need to set the next-endpoint pointer
* to be something valid.
*/
@@ -3029,19 +3057,22 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
*/
static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg)
{
- u32 cfg2, cfg4;
+ u32 cfg2, cfg3, cfg4;
/* check hardware configuration */
cfg2 = readl(hsotg->regs + 0x48);
hsotg->num_of_eps = (cfg2 >> 10) & 0xF;
- dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps);
+ cfg3 = readl(hsotg->regs + 0x4C);
+ hsotg->fifo_mem = (cfg3 >> 16);
cfg4 = readl(hsotg->regs + 0x50);
hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
- dev_info(hsotg->dev, "%s fifos\n",
- hsotg->dedicated_fifos ? "dedicated" : "shared");
+ dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n",
+ hsotg->num_of_eps,
+ hsotg->dedicated_fifos ? "dedicated" : "shared",
+ hsotg->fifo_mem);
}
/**
@@ -3392,6 +3423,9 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
if (!hsotg)
return -ENOMEM;
+ /* Set default UTMI width */
+ hsotg->phyif = GUSBCFG_PHYIF16;
+
/*
* Attempt to find a generic PHY, then look for an old style
* USB PHY, finally fall back to pdata
@@ -3410,8 +3444,15 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
hsotg->plat = plat;
} else
hsotg->uphy = uphy;
- } else
+ } else {
hsotg->phy = phy;
+ /*
+ * If using the generic PHY framework, check if the PHY bus
+ * width is 8-bit and set the phyif appropriately.
+ */
+ if (phy_get_bus_width(phy) == 8)
+ hsotg->phyif = GUSBCFG_PHYIF8;
+ }
hsotg->dev = dev;
@@ -3471,22 +3512,12 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
goto err_supplies;
}
- /* Set default UTMI width */
- hsotg->phyif = GUSBCFG_PHYIF16;
-
- /*
- * If using the generic PHY framework, check if the PHY bus
- * width is 8-bit and set the phyif appropriately.
- */
- if (hsotg->phy && (phy_get_bus_width(phy) == 8))
- hsotg->phyif = GUSBCFG_PHYIF8;
-
/* usb phy enable */
s3c_hsotg_phy_enable(hsotg);
s3c_hsotg_corereset(hsotg);
- s3c_hsotg_init(hsotg);
s3c_hsotg_hw_cfg(hsotg);
+ s3c_hsotg_init(hsotg);
ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0,
dev_name(dev), hsotg);
@@ -3611,6 +3642,7 @@ static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state)
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
+ clk_disable(hsotg->clk);
}
return ret;
@@ -3625,6 +3657,8 @@ static int s3c_hsotg_resume(struct platform_device *pdev)
if (hsotg->driver) {
dev_info(hsotg->dev, "resuming usb gadget %s\n",
hsotg->driver->driver.name);
+
+ clk_enable(hsotg->clk);
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
}