diff options
Diffstat (limited to 'drivers/usb/renesas_usbhs/pipe.c')
| -rw-r--r-- | drivers/usb/renesas_usbhs/pipe.c | 101 | 
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 122526cfd32..7926e1c700f 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   */  | 
