summaryrefslogtreecommitdiffstats
path: root/drivers/usb/renesas_usbhs/pipe.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-11-11 17:31:53 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-11-11 17:31:53 -0800
commit7fd94beecaff19b346efbf6b77288ab4b0b42dbd (patch)
tree01c1354e59c8c338fd2fe65772c169022aa0ca81 /drivers/usb/renesas_usbhs/pipe.c
parent0f89fc3fd861b8c50fc8c8db5b9a640959744ac7 (diff)
parentf72e3b78867142a19b77f1de0698ce8b03dc6cbd (diff)
downloadblackbird-op-linux-7fd94beecaff19b346efbf6b77288ab4b0b42dbd.tar.gz
blackbird-op-linux-7fd94beecaff19b346efbf6b77288ab4b0b42dbd.zip
Merge tag 'gadget-for-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
USB gadget patches from Felipe: "usb: gadget: patches for v3.8 renesas_usbhs implements ->pullup() method, switches over to devm_request_irq(), adds support for DMA Engine and got a few miscelaneous cleanups. The NCM gadget got an endianness fix and the Ethernet gadget a frame size fix. We're finally removing the g_file_storage gadget and sticking to g_mass_storage and the new tcm_usb_gadget gadgets since that was a huge duplicaton of effort anyway. While removing g_file_storage, we also had to fix a bunch of defconfigs which were still pointing to the old gadget. There's a big series getting us closer to being able to introduce our configfs interface. The series converts functions into loadable modules which will, eventually, be registered to the configfs interface. Other than that there's the usual typo fixes and miscelaneous cleanups all over the place."
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
*/
OpenPOWER on IntegriCloud