aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/renesas_usbhs
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig2
-rw-r--r--drivers/usb/renesas_usbhs/common.c54
-rw-r--r--drivers/usb/renesas_usbhs/common.h6
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c106
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h5
-rw-r--r--drivers/usb/renesas_usbhs/mod.c40
-rw-r--r--drivers/usb/renesas_usbhs/mod.h2
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c159
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c68
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c105
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h11
11 files changed, 332 insertions, 226 deletions
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
index 6f4afa43638..1c4195abc10 100644
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ b/drivers/usb/renesas_usbhs/Kconfig
@@ -4,7 +4,7 @@
config USB_RENESAS_USBHS
tristate 'Renesas USBHS controller'
- depends on USB && USB_GADGET
+ depends on USB_GADGET
default n
help
Renesas USBHS is a discrete USB host and peripheral controller chip
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index e9a5b1d2615..17267b0a2e9 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -14,12 +14,13 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include "./common.h"
+#include "common.h"
/*
* image of renesas_usbhs
@@ -132,6 +133,11 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
}
+void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable)
+{
+ usbhs_bset(priv, SYSCFG, DPRPU, enable ? DPRPU : 0);
+}
+
void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode)
{
usbhs_write(priv, TESTMODE, mode);
@@ -410,11 +416,10 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
*/
static int usbhs_probe(struct platform_device *pdev)
{
- struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+ struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
struct renesas_usbhs_driver_callback *dfunc;
struct usbhs_priv *priv;
- struct resource *res;
- unsigned int irq;
+ struct resource *res, *irq_res;
int ret;
/* check platform information */
@@ -426,25 +431,22 @@ static int usbhs_probe(struct platform_device *pdev)
/* platform data */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0) {
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res || !irq_res) {
dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
return -ENODEV;
}
/* usb private data */
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "Could not allocate priv\n");
return -ENOMEM;
}
- priv->base = ioremap_nocache(res->start, resource_size(res));
- if (!priv->base) {
- dev_err(&pdev->dev, "ioremap error.\n");
- ret = -ENOMEM;
- goto probe_end_kfree;
- }
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
/*
* care platform info
@@ -476,7 +478,9 @@ static int usbhs_probe(struct platform_device *pdev)
/*
* priv settings
*/
- priv->irq = irq;
+ priv->irq = irq_res->start;
+ if (irq_res->flags & IORESOURCE_IRQ_SHAREABLE)
+ priv->irqflags = IRQF_SHARED;
priv->pdev = pdev;
INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug);
spin_lock_init(usbhs_priv_to_lock(priv));
@@ -484,7 +488,7 @@ static int usbhs_probe(struct platform_device *pdev)
/* call pipe and module init */
ret = usbhs_pipe_probe(priv);
if (ret < 0)
- goto probe_end_iounmap;
+ return ret;
ret = usbhs_fifo_probe(priv);
if (ret < 0)
@@ -495,7 +499,7 @@ static int usbhs_probe(struct platform_device *pdev)
goto probe_end_fifo_exit;
/* dev_set_drvdata should be called after usbhs_mod_init */
- dev_set_drvdata(&pdev->dev, priv);
+ platform_set_drvdata(pdev, priv);
/*
* deviece reset here because
@@ -545,20 +549,16 @@ probe_end_fifo_exit:
usbhs_fifo_remove(priv);
probe_end_pipe_exit:
usbhs_pipe_remove(priv);
-probe_end_iounmap:
- iounmap(priv->base);
-probe_end_kfree:
- kfree(priv);
dev_info(&pdev->dev, "probe failed\n");
return ret;
}
-static int __devexit usbhs_remove(struct platform_device *pdev)
+static int usbhs_remove(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+ struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
dev_dbg(&pdev->dev, "usb remove\n");
@@ -575,8 +575,6 @@ static int __devexit usbhs_remove(struct platform_device *pdev)
usbhs_mod_remove(priv);
usbhs_fifo_remove(priv);
usbhs_pipe_remove(priv);
- iounmap(priv->base);
- kfree(priv);
return 0;
}
@@ -602,12 +600,12 @@ static int usbhsc_resume(struct device *dev)
struct usbhs_priv *priv = dev_get_drvdata(dev);
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
- usbhs_platform_call(priv, phy_reset, pdev);
-
if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
usbhsc_power_ctrl(priv, 1);
- usbhsc_hotplug(priv);
+ usbhs_platform_call(priv, phy_reset, pdev);
+
+ usbhsc_drvcllbck_notify_hotplug(pdev);
return 0;
}
@@ -637,7 +635,7 @@ static struct platform_driver renesas_usbhs_driver = {
.pm = &usbhsc_pm_ops,
},
.probe = usbhs_probe,
- .remove = __devexit_p(usbhs_remove),
+ .remove = usbhs_remove,
};
module_platform_driver(renesas_usbhs_driver);
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index d79b3e27db9..c69dd2fba36 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -22,8 +22,8 @@
struct usbhs_priv;
-#include "./mod.h"
-#include "./pipe.h"
+#include "mod.h"
+#include "pipe.h"
/*
*
@@ -242,6 +242,7 @@ struct usbhs_priv {
void __iomem *base;
unsigned int irq;
+ unsigned long irqflags;
struct renesas_usbhs_platform_callback pfunc;
struct renesas_usbhs_driver_param dparam;
@@ -284,6 +285,7 @@ void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data);
*/
void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable);
void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable);
+void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable);
void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode);
/*
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 72339bd6fca..4fd36530bfa 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -17,12 +17,13 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/scatterlist.h>
-#include "./common.h"
-#include "./pipe.h"
+#include "common.h"
+#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_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f)
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
@@ -31,7 +32,6 @@
*/
void usbhs_pkt_init(struct usbhs_pkt *pkt)
{
- pkt->dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&pkt->node);
}
@@ -75,8 +75,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
pipe->handler = &usbhsf_null_handler;
}
- list_del_init(&pkt->node);
- list_add_tail(&pkt->node, &pipe->list);
+ list_move_tail(&pkt->node, &pipe->list);
/*
* each pkt must hold own handler.
@@ -106,7 +105,7 @@ static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
if (list_empty(&pipe->list))
return NULL;
- return list_entry(pipe->list.next, struct usbhs_pkt, node);
+ return list_first_entry(&pipe->list, struct usbhs_pkt, node);
}
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
@@ -163,7 +162,7 @@ static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type)
func = pkt->handler->dma_done;
break;
default:
- dev_err(dev, "unknown pkt hander\n");
+ dev_err(dev, "unknown pkt handler\n");
goto __usbhs_pkt_handler_end;
}
@@ -192,8 +191,8 @@ void usbhs_pkt_start(struct usbhs_pipe *pipe)
/*
* irq enable/disable function
*/
-#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, bempsts, e)
-#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, brdysts, e)
+#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_bempsts, e)
+#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_brdysts, e)
#define usbhsf_irq_callback_ctrl(pipe, status, enable) \
({ \
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \
@@ -202,9 +201,9 @@ void usbhs_pkt_start(struct usbhs_pipe *pipe)
if (!mod) \
return; \
if (enable) \
- mod->irq_##status |= status; \
+ mod->status |= status; \
else \
- mod->irq_##status &= ~status; \
+ mod->status &= ~status; \
usbhs_irq_callback_update(priv, mod); \
})
@@ -305,7 +304,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
}
/* "base" will be used below */
- usbhs_write(priv, fifo->sel, base | MBW_32);
+ if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo))
+ usbhs_write(priv, fifo->sel, base);
+ else
+ usbhs_write(priv, fifo->sel, base | MBW_32);
/* check ISEL and CURPIPE value */
while (timeout--) {
@@ -485,6 +487,8 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
usbhs_pipe_data_sequence(pipe, pkt->sequence);
pkt->sequence = -1; /* -1 sequence will be ignored */
+ usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
+
ret = usbhsf_fifo_select(pipe, fifo, 1);
if (ret < 0)
return 0;
@@ -591,6 +595,7 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
usbhs_pipe_data_sequence(pipe, pkt->sequence);
pkt->sequence = -1; /* -1 sequence will be ignored */
+ usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
usbhs_pipe_enable(pipe);
usbhsf_rx_irq_ctrl(pipe, 1);
@@ -676,6 +681,14 @@ 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);
@@ -762,38 +775,29 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
}
static void usbhsf_dma_complete(void *arg);
-static void usbhsf_dma_prepare_tasklet(unsigned long data)
+static void xfer_work(struct work_struct *work)
{
- struct usbhs_pkt *pkt = (struct usbhs_pkt *)data;
+ struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
- struct scatterlist sg;
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
struct device *dev = usbhs_priv_to_dev(priv);
enum dma_transfer_direction dir;
- dma_cookie_t cookie;
dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
- sg_init_table(&sg, 1);
- sg_set_page(&sg, virt_to_page(pkt->dma),
- pkt->length, offset_in_page(pkt->dma));
- sg_dma_address(&sg) = pkt->dma + pkt->actual;
- sg_dma_len(&sg) = pkt->trans;
-
- desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir,
- DMA_PREP_INTERRUPT |
- DMA_CTRL_ACK);
+ desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual,
+ pkt->trans, dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
return;
desc->callback = usbhsf_dma_complete;
desc->callback_param = pipe;
- cookie = desc->tx_submit(desc);
- if (cookie < 0) {
+ if (dmaengine_submit(desc) < 0) {
dev_err(dev, "Failed to submit dma descriptor\n");
return;
}
@@ -801,6 +805,8 @@ static void usbhsf_dma_prepare_tasklet(unsigned long data)
dev_dbg(dev, " %s %d (%d/ %d)\n",
fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
+ usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
+ usbhs_pipe_enable(pipe);
usbhsf_dma_start(pipe, fifo);
dma_async_issue_pending(chan);
}
@@ -824,7 +830,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
usbhs_pipe_is_dcp(pipe))
goto usbhsf_pio_prepare_push;
- if (len % 4) /* 32bit alignment */
+ if (len & 0x7) /* 8byte alignment */
goto usbhsf_pio_prepare_push;
if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
@@ -844,11 +850,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len;
- tasklet_init(&fifo->tasklet,
- usbhsf_dma_prepare_tasklet,
- (unsigned long)pkt);
-
- tasklet_schedule(&fifo->tasklet);
+ INIT_WORK(&pkt->work, xfer_work);
+ schedule_work(&pkt->work);
return 0;
@@ -914,7 +917,7 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
/* use PIO if packet is less than pio_dma_border */
len = usbhsf_fifo_rcv_len(priv, fifo);
len = min(pkt->length - pkt->actual, len);
- if (len % 4) /* 32bit alignment */
+ if (len & 0x7) /* 8byte alignment */
goto usbhsf_pio_prepare_pop_unselect;
if (len < usbhs_get_dparam(priv, pio_dma_border))
@@ -938,11 +941,8 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len;
- tasklet_init(&fifo->tasklet,
- usbhsf_dma_prepare_tasklet,
- (unsigned long)pkt);
-
- tasklet_schedule(&fifo->tasklet);
+ INIT_WORK(&pkt->work, xfer_work);
+ schedule_work(&pkt->work);
return 0;
@@ -998,7 +998,7 @@ static bool usbhsf_dma_filter(struct dma_chan *chan, void *param)
*
* usbhs doesn't recognize id = 0 as valid DMA
*/
- if (0 == slave->slave_id)
+ if (0 == slave->shdma_slave.slave_id)
return false;
chan->private = slave;
@@ -1132,19 +1132,8 @@ void usbhs_fifo_init(struct usbhs_priv *priv)
mod->irq_brdysts = 0;
cfifo->pipe = NULL;
- cfifo->tx_chan = NULL;
- cfifo->rx_chan = NULL;
-
d0fifo->pipe = NULL;
- d0fifo->tx_chan = NULL;
- d0fifo->rx_chan = NULL;
-
d1fifo->pipe = NULL;
- d1fifo->tx_chan = NULL;
- d1fifo->rx_chan = NULL;
-
- usbhsf_dma_init(priv, usbhsf_get_d0fifo(priv));
- usbhsf_dma_init(priv, usbhsf_get_d1fifo(priv));
}
void usbhs_fifo_quit(struct usbhs_priv *priv)
@@ -1155,9 +1144,6 @@ void usbhs_fifo_quit(struct usbhs_priv *priv)
mod->irq_ready = NULL;
mod->irq_bempsts = 0;
mod->irq_brdysts = 0;
-
- usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv));
- usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv));
}
int usbhs_fifo_probe(struct usbhs_priv *priv)
@@ -1177,8 +1163,9 @@ int usbhs_fifo_probe(struct usbhs_priv *priv)
fifo->port = D0FIFO;
fifo->sel = D0FIFOSEL;
fifo->ctr = D0FIFOCTR;
- fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id);
- fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id);
+ 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);
@@ -1186,12 +1173,15 @@ int usbhs_fifo_probe(struct usbhs_priv *priv)
fifo->port = D1FIFO;
fifo->sel = D1FIFOSEL;
fifo->ctr = D1FIFOCTR;
- fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id);
- fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id);
+ 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);
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));
}
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index f68609c0f48..a168a1760fc 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -19,11 +19,10 @@
#include <linux/interrupt.h>
#include <linux/sh_dma.h>
+#include <linux/workqueue.h>
#include <asm/dma.h>
#include "pipe.h"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
struct usbhs_fifo {
char *name;
u32 port; /* xFIFO */
@@ -31,7 +30,6 @@ struct usbhs_fifo {
u32 ctr; /* xFIFOCTR */
struct usbhs_pipe *pipe;
- struct tasklet_struct tasklet;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
@@ -53,6 +51,7 @@ struct usbhs_pkt {
struct usbhs_pkt_handle *handler;
void (*done)(struct usbhs_priv *priv,
struct usbhs_pkt *pkt);
+ struct work_struct work;
dma_addr_t dma;
void *buf;
int length;
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 1b97fb12694..6a030b931a3 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -16,8 +16,8 @@
*/
#include <linux/interrupt.h>
-#include "./common.h"
-#include "./mod.h"
+#include "common.h"
+#include "mod.h"
#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
#define usbhs_mod_info_call(priv, func, param...) \
@@ -151,8 +151,8 @@ int usbhs_mod_probe(struct usbhs_priv *priv)
goto mod_init_host_err;
/* irq settings */
- ret = request_irq(priv->irq, usbhs_interrupt,
- 0, dev_name(dev), priv);
+ ret = devm_request_irq(dev, priv->irq, usbhs_interrupt,
+ priv->irqflags, dev_name(dev), priv);
if (ret) {
dev_err(dev, "irq request err\n");
goto mod_init_gadget_err;
@@ -172,7 +172,6 @@ void usbhs_mod_remove(struct usbhs_priv *priv)
{
usbhs_mod_host_remove(priv);
usbhs_mod_gadget_remove(priv);
- free_irq(priv->irq, priv);
}
/*
@@ -209,14 +208,18 @@ int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state)
return (int)irq_state->intsts0 & CTSQ_MASK;
}
-static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
- struct usbhs_irq_state *state)
+static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
+ struct usbhs_irq_state *state)
{
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
+ u16 intenb0, intenb1;
state->intsts0 = usbhs_read(priv, INTSTS0);
state->intsts1 = usbhs_read(priv, INTSTS1);
+ intenb0 = usbhs_read(priv, INTENB0);
+ intenb1 = usbhs_read(priv, INTENB1);
+
/* mask */
if (mod) {
state->brdysts = usbhs_read(priv, BRDYSTS);
@@ -226,6 +229,20 @@ static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
state->bempsts &= mod->irq_bempsts;
state->brdysts &= mod->irq_brdysts;
}
+
+ /*
+ * Check whether the irq enable registers and the irq status are set
+ * when IRQF_SHARED is set.
+ */
+ if (priv->irqflags & IRQF_SHARED) {
+ if (!(intenb0 & state->intsts0) &&
+ !(intenb1 & state->intsts1) &&
+ !(state->bempsts) &&
+ !(state->brdysts))
+ return -EIO;
+ }
+
+ return 0;
}
/*
@@ -238,7 +255,8 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
struct usbhs_priv *priv = data;
struct usbhs_irq_state irq_state;
- usbhs_status_get_each_irq(priv, &irq_state);
+ if (usbhs_status_get_each_irq(priv, &irq_state) < 0)
+ return IRQ_NONE;
/*
* clear interrupt
@@ -254,9 +272,9 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC);
usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
- usbhs_write(priv, BRDYSTS, 0);
- usbhs_write(priv, NRDYSTS, 0);
- usbhs_write(priv, BEMPSTS, 0);
+ usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
+ usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts);
+ usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);
/*
* call irq callback functions
diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h
index 6c6875533f0..1ef5bf60407 100644
--- a/drivers/usb/renesas_usbhs/mod.h
+++ b/drivers/usb/renesas_usbhs/mod.h
@@ -19,7 +19,7 @@
#include <linux/spinlock.h>
#include <linux/usb/renesas_usbhs.h>
-#include "./common.h"
+#include "common.h"
/*
* struct
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 7542aa94a46..458f3766bef 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -55,6 +55,7 @@ struct usbhsg_gpriv {
#define USBHSG_STATUS_STARTED (1 << 0)
#define USBHSG_STATUS_REGISTERD (1 << 1)
#define USBHSG_STATUS_WEDGE (1 << 2)
+#define USBHSG_STATUS_SELF_POWERED (1 << 3)
};
struct usbhsg_recip_handle {
@@ -76,9 +77,9 @@ struct usbhsg_recip_handle {
struct usbhsg_gpriv, mod)
#define __usbhsg_for_each_uep(start, pos, g, i) \
- for (i = start, pos = (g)->uep + i; \
- i < (g)->uep_size; \
- i++, pos = (g)->uep + i)
+ for ((i) = start; \
+ ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \
+ (i)++)
#define usbhsg_for_each_uep(pos, gpriv, i) \
__usbhsg_for_each_uep(1, pos, gpriv, i)
@@ -165,69 +166,32 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
/*
* dma map/unmap
*/
-static int usbhsg_dma_map(struct device *dev,
- struct usbhs_pkt *pkt,
- enum dma_data_direction dir)
-{
- struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
- struct usb_request *req = &ureq->req;
-
- if (pkt->dma != DMA_ADDR_INVALID) {
- dev_err(dev, "dma is already mapped\n");
- return -EIO;
- }
-
- if (req->dma == DMA_ADDR_INVALID) {
- pkt->dma = dma_map_single(dev, pkt->buf, pkt->length, dir);
- } else {
- dma_sync_single_for_device(dev, req->dma, req->length, dir);
- pkt->dma = req->dma;
- }
-
- if (dma_mapping_error(dev, pkt->dma)) {
- dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma);
- return -EIO;
- }
-
- return 0;
-}
-
-static int usbhsg_dma_unmap(struct device *dev,
- struct usbhs_pkt *pkt,
- enum dma_data_direction dir)
+static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
{
struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
struct usb_request *req = &ureq->req;
-
- if (pkt->dma == DMA_ADDR_INVALID) {
- dev_err(dev, "dma is not mapped\n");
- return -EIO;
- }
-
- if (req->dma == DMA_ADDR_INVALID)
- dma_unmap_single(dev, pkt->dma, pkt->length, dir);
- else
- dma_sync_single_for_cpu(dev, req->dma, req->length, dir);
-
- pkt->dma = DMA_ADDR_INVALID;
-
- return 0;
-}
-
-static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
-{
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
- struct device *dev = usbhsg_gpriv_to_dev(gpriv);
enum dma_data_direction dir;
+ int ret = 0;
- dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ dir = usbhs_pipe_is_dir_host(pipe);
- if (map)
- return usbhsg_dma_map(dev, pkt, dir);
- else
- return usbhsg_dma_unmap(dev, pkt, dir);
+ if (map) {
+ /* it can not use scatter/gather */
+ WARN_ON(req->num_sgs);
+
+ ret = usb_gadget_map_request(&gpriv->gadget, req, dir);
+ if (ret < 0)
+ return ret;
+
+ pkt->dma = req->dma;
+ } else {
+ usb_gadget_unmap_request(&gpriv->gadget, req, dir);
+ }
+
+ return ret;
}
/*
@@ -266,7 +230,7 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_clear_feature = {
+static struct usbhsg_recip_handle req_clear_feature = {
.name = "clear feature",
.device = usbhsg_recip_handler_std_control_done,
.interface = usbhsg_recip_handler_std_control_done,
@@ -307,7 +271,7 @@ static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_set_feature = {
+static struct usbhsg_recip_handle req_set_feature = {
.name = "set feature",
.device = usbhsg_recip_handler_std_set_device,
.interface = usbhsg_recip_handler_std_control_done,
@@ -370,7 +334,10 @@ static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv,
struct usb_ctrlrequest *ctrl)
{
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
- unsigned short status = 1 << USB_DEVICE_SELF_POWERED;
+ unsigned short status = 0;
+
+ if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED))
+ status = 1 << USB_DEVICE_SELF_POWERED;
__usbhsg_recip_send_status(gpriv, status);
@@ -405,7 +372,7 @@ static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_get_status = {
+static struct usbhsg_recip_handle req_get_status = {
.name = "get status",
.device = usbhsg_recip_handler_std_get_device,
.interface = usbhsg_recip_handler_std_get_interface,
@@ -578,15 +545,6 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)
return 0;
}
-static void usbhsg_uep_init(struct usbhsg_gpriv *gpriv)
-{
- int i;
- struct usbhsg_uep *uep;
-
- usbhsg_for_each_uep_with_dcp(uep, gpriv, i)
- uep->pipe = NULL;
-}
-
/*
*
* usb_ep_ops
@@ -643,7 +601,12 @@ static int usbhsg_ep_disable(struct usb_ep *ep)
{
struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
- return usbhsg_pipe_disable(uep);
+ usbhsg_pipe_disable(uep);
+
+ uep->pipe->mod_private = NULL;
+ uep->pipe = NULL;
+
+ return 0;
}
static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep,
@@ -657,8 +620,6 @@ static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep,
usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq));
- ureq->req.dma = DMA_ADDR_INVALID;
-
return &ureq->req;
}
@@ -796,9 +757,8 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
usbhs_pipe_init(priv,
usbhsg_dma_map_ctrl);
usbhs_fifo_init(priv);
- usbhsg_uep_init(gpriv);
- /* dcp init */
+ /* dcp init instead of usbhsg_ep_enable() */
dcp->pipe = usbhs_dcp_malloc(priv);
dcp->pipe->mod_private = dcp;
usbhs_pipe_config_update(dcp->pipe, 0, 0, 64);
@@ -860,7 +820,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
usbhs_sys_set_test_mode(priv, 0);
usbhs_sys_function_ctrl(priv, 0);
- usbhsg_pipe_disable(dcp);
+ usbhsg_ep_disable(&dcp->ep);
dev_dbg(dev, "stop gadget\n");
@@ -885,7 +845,6 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
/* first hook up the driver ... */
gpriv->driver = driver;
- gpriv->gadget.dev.driver = &driver->driver;
return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
}
@@ -896,12 +855,7 @@ 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);
- if (!driver ||
- !driver->unbind)
- return -EINVAL;
-
usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
- gpriv->gadget.dev.driver = NULL;
gpriv->driver = NULL;
return 0;
@@ -918,10 +872,34 @@ static int usbhsg_get_frame(struct usb_gadget *gadget)
return usbhs_frame_get_num(priv);
}
-static struct usb_gadget_ops usbhsg_gadget_ops = {
+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);
+
+ usbhs_sys_function_pullup(priv, is_on);
+
+ return 0;
+}
+
+static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+ struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
+
+ if (is_self)
+ usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED);
+ else
+ usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
+
+ return 0;
+}
+
+static const struct usb_gadget_ops usbhsg_gadget_ops = {
.get_frame = usbhsg_get_frame,
+ .set_selfpowered = usbhsg_set_selfpowered,
.udc_start = usbhsg_gadget_start,
.udc_stop = usbhsg_gadget_stop,
+ .pullup = usbhsg_pullup,
};
static int usbhsg_start(struct usbhs_priv *priv)
@@ -987,14 +965,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
/*
* init gadget
*/
- dev_set_name(&gpriv->gadget.dev, "gadget");
gpriv->gadget.dev.parent = dev;
gpriv->gadget.name = "renesas_usbhs_udc";
gpriv->gadget.ops = &usbhsg_gadget_ops;
gpriv->gadget.max_speed = USB_SPEED_HIGH;
- ret = device_register(&gpriv->gadget.dev);
- if (ret < 0)
- goto err_add_udc;
INIT_LIST_HEAD(&gpriv->gadget.ep_list);
@@ -1003,6 +977,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
*/
usbhsg_for_each_uep_with_dcp(uep, gpriv, i) {
uep->gpriv = gpriv;
+ uep->pipe = NULL;
snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i);
uep->ep.name = uep->ep_name;
@@ -1012,26 +987,24 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
/* init DCP */
if (usbhsg_is_dcp(uep)) {
gpriv->gadget.ep0 = &uep->ep;
- uep->ep.maxpacket = 64;
+ usb_ep_set_maxpacket_limit(&uep->ep, 64);
}
/* init normal pipe */
else {
- uep->ep.maxpacket = 512;
+ usb_ep_set_maxpacket_limit(&uep->ep, 512);
list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list);
}
}
ret = usb_add_gadget_udc(dev, &gpriv->gadget);
if (ret)
- goto err_register;
+ goto err_add_udc;
dev_info(dev, "gadget probed\n");
return 0;
-err_register:
- device_unregister(&gpriv->gadget.dev);
err_add_udc:
kfree(gpriv->uep);
@@ -1047,8 +1020,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv)
usb_del_gadget_udc(&gpriv->gadget);
- device_unregister(&gpriv->gadget.dev);
-
kfree(gpriv->uep);
kfree(gpriv);
}
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 1834cf50888..10e1ded9c9c 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -85,6 +85,7 @@ struct usbhsh_ep {
struct usbhsh_device *udev; /* attached udev */
struct usb_host_endpoint *ep;
struct list_head ep_list; /* list to usbhsh_device */
+ unsigned int counter; /* pipe attach counter */
};
#define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */
@@ -110,9 +111,9 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
#define __usbhsh_for_each_udev(start, pos, h, i) \
- for (i = start, pos = (h)->udev + i; \
- i < USBHSH_DEVICE_MAX; \
- i++, pos = (h)->udev + i)
+ for ((i) = start; \
+ ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i)); \
+ (i)++)
#define usbhsh_for_each_udev(pos, hpriv, i) \
__usbhsh_for_each_udev(1, pos, hpriv, i)
@@ -271,8 +272,12 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
/******************** spin lock ********************/
usbhs_lock(priv, flags);
- if (unlikely(usbhsh_uep_to_pipe(uep))) {
- dev_err(dev, "uep already has pipe\n");
+ /*
+ * if uep has been attached to pipe,
+ * reuse it
+ */
+ if (usbhsh_uep_to_pipe(uep)) {
+ ret = 0;
goto usbhsh_pipe_attach_done;
}
@@ -320,6 +325,9 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
}
usbhsh_pipe_attach_done:
+ if (0 == ret)
+ uep->counter++;
+
usbhs_unlock(priv, flags);
/******************** spin unlock ******************/
@@ -334,6 +342,11 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv,
struct device *dev = usbhs_priv_to_dev(priv);
unsigned long flags;
+ if (unlikely(!uep)) {
+ dev_err(dev, "no uep\n");
+ return;
+ }
+
/******************** spin lock ********************/
usbhs_lock(priv, flags);
@@ -341,7 +354,7 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv,
if (unlikely(!pipe)) {
dev_err(dev, "uep doens't have pipe\n");
- } else {
+ } else if (1 == uep->counter--) { /* last user */
struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep);
struct usbhsh_device *udev = usbhsh_uep_to_udev(uep);
@@ -386,6 +399,7 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv,
/*
* init endpoint
*/
+ uep->counter = 0;
INIT_LIST_HEAD(&uep->ep_list);
list_add_tail(&uep->ep_list, &udev->ep_list_head);
@@ -647,9 +661,10 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
status = -ESHUTDOWN;
urb->actual_length = pkt->actual;
- usbhsh_ureq_free(hpriv, ureq);
usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
+ usbhsh_ureq_free(hpriv, ureq);
+
usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));
usb_hcd_unlink_urb_from_ep(hcd, urb);
@@ -681,9 +696,9 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,
}
if (usb_pipein(urb->pipe))
- pipe->handler = &usbhs_fifo_pio_pop_handler;
+ pipe->handler = &usbhs_fifo_dma_pop_handler;
else
- pipe->handler = &usbhs_fifo_pio_push_handler;
+ pipe->handler = &usbhs_fifo_dma_push_handler;
buf = (void *)(urb->transfer_buffer + urb->actual_length);
len = urb->transfer_buffer_length - urb->actual_length;
@@ -916,6 +931,19 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
*/
static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
{
+ if (map) {
+ struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
+ struct urb *urb = ureq->urb;
+
+ /* it can not use scatter/gather */
+ if (urb->num_sgs)
+ return -EINVAL;
+
+ pkt->dma = urb->transfer_dma;
+ if (!pkt->dma)
+ return -EINVAL;
+ }
+
return 0;
}
@@ -941,7 +969,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *ep = urb->ep;
struct usbhsh_device *new_udev = NULL;
int is_dir_in = usb_pipein(urb->pipe);
- int i;
int ret;
dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out");
@@ -987,13 +1014,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
* attach pipe to endpoint
* see [image of mod_host]
*/
- for (i = 0; i < 1024; i++) {
- ret = usbhsh_pipe_attach(hpriv, urb);
- if (ret < 0)
- msleep(100);
- else
- break;
- }
+ ret = usbhsh_pipe_attach(hpriv, urb);
if (ret < 0) {
dev_err(dev, "pipe attach failed\n");
goto usbhsh_urb_enqueue_error_free_endpoint;
@@ -1067,8 +1088,6 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd,
static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
- struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
- struct device *dev = usbhs_priv_to_dev(priv);
int roothub_id = 1; /* only 1 root hub */
/*
@@ -1080,8 +1099,6 @@ static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf)
else
*buf = 0;
- dev_dbg(dev, "%s (%02x)\n", __func__, *buf);
-
return !!(*buf);
}
@@ -1266,6 +1283,12 @@ static int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return ret;
}
+static int usbhsh_bus_nop(struct usb_hcd *hcd)
+{
+ /* nothing to do */
+ return 0;
+}
+
static struct hc_driver usbhsh_driver = {
.description = usbhsh_hcd_name,
.hcd_priv_size = sizeof(struct usbhsh_hpriv),
@@ -1290,6 +1313,8 @@ static struct hc_driver usbhsh_driver = {
*/
.hub_status_data = usbhsh_hub_status_data,
.hub_control = usbhsh_hub_control,
+ .bus_suspend = usbhsh_bus_nop,
+ .bus_resume = usbhsh_bus_nop,
};
/*
@@ -1444,6 +1469,7 @@ static int usbhsh_start(struct usbhs_priv *priv)
ret = usb_add_hcd(hcd, 0, 0);
if (ret < 0)
return 0;
+ device_wakeup_enable(hcd->self.controller);
/*
* pipe initialize and enable DCP
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index feb06d6d281..7926e1c700f 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -16,8 +16,8 @@
*/
#include <linux/delay.h>
#include <linux/slab.h>
-#include "./common.h"
-#include "./pipe.h"
+#include "common.h"
+#include "pipe.h"
/*
* macros
@@ -93,6 +93,82 @@ static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
}
/*
+ * PIPEnTRN/PIPEnTRE functions
+ */
+static void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
+{
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int num = usbhs_pipe_number(pipe);
+ u16 reg;
+
+ /*
+ * It is impossible to calculate address,
+ * since PIPEnTRN addresses were mapped randomly.
+ */
+#define CASE_PIPExTRN(a) \
+ case 0x ## a: \
+ reg = PIPE ## a ## TRN; \
+ break;
+
+ switch (num) {
+ CASE_PIPExTRN(1);
+ CASE_PIPExTRN(2);
+ CASE_PIPExTRN(3);
+ CASE_PIPExTRN(4);
+ CASE_PIPExTRN(5);
+ CASE_PIPExTRN(B);
+ CASE_PIPExTRN(C);
+ CASE_PIPExTRN(D);
+ CASE_PIPExTRN(E);
+ CASE_PIPExTRN(F);
+ CASE_PIPExTRN(9);
+ CASE_PIPExTRN(A);
+ default:
+ dev_err(dev, "unknown pipe (%d)\n", num);
+ return;
+ }
+ __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val);
+}
+
+static void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
+{
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int num = usbhs_pipe_number(pipe);
+ u16 reg;
+
+ /*
+ * It is impossible to calculate address,
+ * since PIPEnTRE addresses were mapped randomly.
+ */
+#define CASE_PIPExTRE(a) \
+ case 0x ## a: \
+ reg = PIPE ## a ## TRE; \
+ break;
+
+ switch (num) {
+ CASE_PIPExTRE(1);
+ CASE_PIPExTRE(2);
+ CASE_PIPExTRE(3);
+ CASE_PIPExTRE(4);
+ CASE_PIPExTRE(5);
+ CASE_PIPExTRE(B);
+ CASE_PIPExTRE(C);
+ CASE_PIPExTRE(D);
+ CASE_PIPExTRE(E);
+ CASE_PIPExTRE(F);
+ CASE_PIPExTRE(9);
+ CASE_PIPExTRE(A);
+ default:
+ dev_err(dev, "unknown pipe (%d)\n", num);
+ return;
+ }
+
+ __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val);
+}
+
+/*
* PIPEBUF
*/
static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
@@ -264,6 +340,31 @@ int usbhs_pipe_is_stall(struct usbhs_pipe *pipe)
return (int)(pid == PID_STALL10 || pid == PID_STALL11);
}
+void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len)
+{
+ if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
+ return;
+
+ /*
+ * clear and disable transfer counter for IN/OUT pipe
+ */
+ usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR);
+
+ /*
+ * Only IN direction bulk pipe can use transfer count.
+ * Without using this function,
+ * received data will break if it was large data size.
+ * see PIPEnTRN/PIPEnTRE for detail
+ */
+ if (usbhs_pipe_is_dir_in(pipe)) {
+ int maxp = usbhs_pipe_get_maxpacket(pipe);
+
+ usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp));
+ usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */
+ }
+}
+
+
/*
* pipe setup
*/
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index fa18b7dc2b2..3e534987983 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -17,8 +17,8 @@
#ifndef RENESAS_USB_PIPE_H
#define RENESAS_USB_PIPE_H
-#include "./common.h"
-#include "./fifo.h"
+#include "common.h"
+#include "fifo.h"
/*
* struct
@@ -54,9 +54,9 @@ struct usbhs_pipe_info {
* pipe list
*/
#define __usbhs_for_each_pipe(start, pos, info, i) \
- for (i = start, pos = (info)->pipe; \
- i < (info)->size; \
- i++, pos = (info)->pipe + i)
+ for ((i) = start; \
+ ((i) < (info)->size) && ((pos) = (info)->pipe + (i)); \
+ (i)++)
#define usbhs_for_each_pipe(pos, priv, i) \
__usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i)
@@ -88,6 +88,7 @@ void usbhs_pipe_enable(struct usbhs_pipe *pipe);
void usbhs_pipe_disable(struct usbhs_pipe *pipe);
void usbhs_pipe_stall(struct usbhs_pipe *pipe);
int usbhs_pipe_is_stall(struct usbhs_pipe *pipe);
+void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len);
void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
u16 epnum, u16 maxp);