summaryrefslogtreecommitdiff
path: root/drivers/usb/renesas_usbhs/pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/renesas_usbhs/pipe.c')
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 122526cfd32b..7926e1c700f1 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -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
*/