2011-04-04 08:44:59 +04:00
/*
* Renesas USB driver
*
* Copyright ( C ) 2011 Renesas Solutions Corp .
* Kuninori Morimoto < kuninori . morimoto . gx @ renesas . com >
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
*/
# include <linux/delay.h>
# include <linux/slab.h>
2012-06-03 20:39:13 +04:00
# include "common.h"
# include "pipe.h"
2011-04-04 08:44:59 +04:00
/*
* macros
*/
# define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2)
# define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f)
# define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f)
# define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f)
# define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0)
/*
* for debug
*/
static char * usbhsp_pipe_name [ ] = {
[ USB_ENDPOINT_XFER_CONTROL ] = " DCP " ,
[ USB_ENDPOINT_XFER_BULK ] = " BULK " ,
[ USB_ENDPOINT_XFER_INT ] = " INT " ,
[ USB_ENDPOINT_XFER_ISOC ] = " ISO " ,
} ;
2011-10-11 09:04:23 +04:00
char * usbhs_pipe_name ( struct usbhs_pipe * pipe )
{
return usbhsp_pipe_name [ usbhs_pipe_type ( pipe ) ] ;
}
2011-04-04 08:44:59 +04:00
/*
* DCPCTR / PIPEnCTR functions
*/
static void usbhsp_pipectrl_set ( struct usbhs_pipe * pipe , u16 mask , u16 val )
{
2011-06-06 09:18:03 +04:00
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
2011-04-04 08:44:59 +04:00
int offset = usbhsp_addr_offset ( pipe ) ;
2011-06-06 09:18:03 +04:00
if ( usbhs_pipe_is_dcp ( pipe ) )
2011-04-04 08:44:59 +04:00
usbhs_bset ( priv , DCPCTR , mask , val ) ;
else
usbhs_bset ( priv , PIPEnCTR + offset , mask , val ) ;
}
static u16 usbhsp_pipectrl_get ( struct usbhs_pipe * pipe )
{
2011-06-06 09:18:03 +04:00
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
2011-04-04 08:44:59 +04:00
int offset = usbhsp_addr_offset ( pipe ) ;
2011-06-06 09:18:03 +04:00
if ( usbhs_pipe_is_dcp ( pipe ) )
2011-04-04 08:44:59 +04:00
return usbhs_read ( priv , DCPCTR ) ;
else
return usbhs_read ( priv , PIPEnCTR + offset ) ;
}
/*
* DCP / PIPE functions
*/
static void __usbhsp_pipe_xxx_set ( struct usbhs_pipe * pipe ,
u16 dcp_reg , u16 pipe_reg ,
u16 mask , u16 val )
{
2011-06-06 09:18:03 +04:00
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
2011-04-04 08:44:59 +04:00
2011-06-06 09:18:03 +04:00
if ( usbhs_pipe_is_dcp ( pipe ) )
2011-04-04 08:44:59 +04:00
usbhs_bset ( priv , dcp_reg , mask , val ) ;
else
usbhs_bset ( priv , pipe_reg , mask , val ) ;
}
2015-03-12 09:35:20 +03:00
static u16 __usbhsp_pipe_xxx_get ( struct usbhs_pipe * pipe ,
u16 dcp_reg , u16 pipe_reg )
{
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
if ( usbhs_pipe_is_dcp ( pipe ) )
return usbhs_read ( priv , dcp_reg ) ;
else
return usbhs_read ( priv , pipe_reg ) ;
}
2011-04-04 08:44:59 +04:00
/*
* DCPCFG / PIPECFG functions
*/
static void usbhsp_pipe_cfg_set ( struct usbhs_pipe * pipe , u16 mask , u16 val )
{
__usbhsp_pipe_xxx_set ( pipe , DCPCFG , PIPECFG , mask , val ) ;
}
2015-03-12 09:35:20 +03:00
static u16 usbhsp_pipe_cfg_get ( struct usbhs_pipe * pipe )
{
return __usbhsp_pipe_xxx_get ( pipe , DCPCFG , PIPECFG ) ;
}
2012-11-07 04:15:09 +04:00
/*
* 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 0 x # # 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 0 x # # 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 ) ;
}
2011-04-04 08:44:59 +04:00
/*
* PIPEBUF
*/
static void usbhsp_pipe_buf_set ( struct usbhs_pipe * pipe , u16 mask , u16 val )
{
2011-06-06 09:18:03 +04:00
if ( usbhs_pipe_is_dcp ( pipe ) )
2011-04-04 08:44:59 +04:00
return ;
__usbhsp_pipe_xxx_set ( pipe , 0 , PIPEBUF , mask , val ) ;
}
/*
* DCPMAXP / PIPEMAXP
*/
static void usbhsp_pipe_maxp_set ( struct usbhs_pipe * pipe , u16 mask , u16 val )
{
__usbhsp_pipe_xxx_set ( pipe , DCPMAXP , PIPEMAXP , mask , val ) ;
}
/*
* pipe control functions
*/
static void usbhsp_pipe_select ( struct usbhs_pipe * pipe )
{
2011-06-06 09:18:03 +04:00
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
2011-04-04 08:44:59 +04:00
/*
* On pipe , this is necessary before
* accesses to below registers .
*
* PIPESEL : usbhsp_pipe_select
* PIPECFG : usbhsp_pipe_cfg_xxx
* PIPEBUF : usbhsp_pipe_buf_xxx
* PIPEMAXP : usbhsp_pipe_maxp_xxx
* PIPEPERI
*/
/*
* if pipe is dcp , no pipe is selected .
* it is no problem , because dcp have its register
*/
usbhs_write ( priv , PIPESEL , 0xF & usbhs_pipe_number ( pipe ) ) ;
}
static int usbhsp_pipe_barrier ( struct usbhs_pipe * pipe )
{
2011-06-06 09:18:03 +04:00
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
2011-04-04 08:44:59 +04:00
int timeout = 1024 ;
u16 val ;
/*
* make sure . . . .
*
* Modify these bits when CSSTS = 0 , PID = NAK , and no pipe number is
* specified by the CURPIPE bits .
* When changing the setting of this bit after changing
* the PID bits for the selected pipe from BUF to NAK ,
* check that CSSTS = 0 and PBUSY = 0.
*/
/*
* CURPIPE bit = 0
*
* see also
* " Operation "
* - " Pipe Control "
* - " Pipe Control Registers Switching Procedure "
*/
usbhs_write ( priv , CFIFOSEL , 0 ) ;
2011-06-06 09:18:03 +04:00
usbhs_pipe_disable ( pipe ) ;
2011-04-04 08:44:59 +04:00
do {
val = usbhsp_pipectrl_get ( pipe ) ;
val & = CSSTS | PID_MASK ;
if ( ! val )
return 0 ;
udelay ( 10 ) ;
} while ( timeout - - ) ;
return - EBUSY ;
}
2011-06-06 09:18:03 +04:00
int usbhs_pipe_is_accessible ( struct usbhs_pipe * pipe )
2011-04-04 08:44:59 +04:00
{
u16 val ;
val = usbhsp_pipectrl_get ( pipe ) ;
if ( val & BSTS )
return 0 ;
return - EBUSY ;
}
/*
* PID ctrl
*/
static void __usbhsp_pid_try_nak_if_stall ( struct usbhs_pipe * pipe )
{
u16 pid = usbhsp_pipectrl_get ( pipe ) ;
pid & = PID_MASK ;
/*
* see
* " Pipe n Control Register " - " PID "
*/
switch ( pid ) {
case PID_STALL11 :
usbhsp_pipectrl_set ( pipe , PID_MASK , PID_STALL10 ) ;
/* fall-through */
case PID_STALL10 :
usbhsp_pipectrl_set ( pipe , PID_MASK , PID_NAK ) ;
}
}
2011-06-06 09:18:03 +04:00
void usbhs_pipe_disable ( struct usbhs_pipe * pipe )
2011-04-04 08:44:59 +04:00
{
2011-05-11 11:00:09 +04:00
int timeout = 1024 ;
u16 val ;
2011-04-04 08:44:59 +04:00
/* see "Pipe n Control Register" - "PID" */
__usbhsp_pid_try_nak_if_stall ( pipe ) ;
usbhsp_pipectrl_set ( pipe , PID_MASK , PID_NAK ) ;
2011-05-11 11:00:09 +04:00
do {
val = usbhsp_pipectrl_get ( pipe ) ;
val & = PBUSY ;
if ( ! val )
break ;
udelay ( 10 ) ;
} while ( timeout - - ) ;
2011-04-04 08:44:59 +04:00
}
2011-06-06 09:18:03 +04:00
void usbhs_pipe_enable ( struct usbhs_pipe * pipe )
2011-04-04 08:44:59 +04:00
{
/* see "Pipe n Control Register" - "PID" */
__usbhsp_pid_try_nak_if_stall ( pipe ) ;
usbhsp_pipectrl_set ( pipe , PID_MASK , PID_BUF ) ;
}
2011-06-06 09:18:03 +04:00
void usbhs_pipe_stall ( struct usbhs_pipe * pipe )
2011-04-04 08:44:59 +04:00
{
u16 pid = usbhsp_pipectrl_get ( pipe ) ;
pid & = PID_MASK ;
/*
* see
* " Pipe n Control Register " - " PID "
*/
switch ( pid ) {
case PID_NAK :
usbhsp_pipectrl_set ( pipe , PID_MASK , PID_STALL10 ) ;
break ;
case PID_BUF :
usbhsp_pipectrl_set ( pipe , PID_MASK , PID_STALL11 ) ;
break ;
}
}
2011-11-25 05:27:32 +04:00
int usbhs_pipe_is_stall ( struct usbhs_pipe * pipe )
{
u16 pid = usbhsp_pipectrl_get ( pipe ) & PID_MASK ;
return ( int ) ( pid = = PID_STALL10 | | pid = = PID_STALL11 ) ;
}
2012-11-07 04:15:09 +04:00
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 */
}
}
2011-04-04 08:44:59 +04:00
/*
* pipe setup
*/
static int usbhsp_possible_double_buffer ( struct usbhs_pipe * pipe )
{
/*
* only ISO / BULK pipe can use double buffer
*/
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_BULK ) | |
usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_ISOC ) )
2011-04-04 08:44:59 +04:00
return 1 ;
return 0 ;
}
static u16 usbhsp_setup_pipecfg ( struct usbhs_pipe * pipe ,
2011-10-11 08:59:46 +04:00
int is_host ,
int dir_in )
2011-04-04 08:44:59 +04:00
{
u16 type = 0 ;
u16 bfre = 0 ;
u16 dblb = 0 ;
u16 cntmd = 0 ;
u16 dir = 0 ;
u16 epnum = 0 ;
u16 shtnak = 0 ;
u16 type_array [ ] = {
[ USB_ENDPOINT_XFER_BULK ] = TYPE_BULK ,
[ USB_ENDPOINT_XFER_INT ] = TYPE_INT ,
[ USB_ENDPOINT_XFER_ISOC ] = TYPE_ISO ,
} ;
int is_double = usbhsp_possible_double_buffer ( pipe ) ;
2011-06-06 09:18:03 +04:00
if ( usbhs_pipe_is_dcp ( pipe ) )
2011-04-04 08:44:59 +04:00
return - EINVAL ;
/*
* PIPECFG
*
* see
* - " Register Descriptions " - " PIPECFG " register
* - " Features " - " Pipe configuration "
* - " Operation " - " Pipe Control "
*/
/* TYPE */
2011-10-11 09:02:21 +04:00
type = type_array [ usbhs_pipe_type ( pipe ) ] ;
2011-04-04 08:44:59 +04:00
/* BFRE */
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_ISOC ) | |
usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_BULK ) )
2011-04-04 08:44:59 +04:00
bfre = 0 ; /* FIXME */
/* DBLB */
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_ISOC ) | |
usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_BULK ) )
2011-04-04 08:44:59 +04:00
dblb = ( is_double ) ? DBLB : 0 ;
/* CNTMD */
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_BULK ) )
2011-04-04 08:44:59 +04:00
cntmd = 0 ; /* FIXME */
/* DIR */
2011-10-11 08:59:46 +04:00
if ( dir_in )
2011-06-06 09:17:56 +04:00
usbhsp_flags_set ( pipe , IS_DIR_HOST ) ;
2011-04-04 08:44:59 +04:00
2011-12-21 15:13:33 +04:00
if ( ! ! is_host ^ ! ! dir_in )
2011-04-04 08:44:59 +04:00
dir | = DIR_OUT ;
2011-06-06 09:17:56 +04:00
if ( ! dir )
usbhsp_flags_set ( pipe , IS_DIR_IN ) ;
2011-04-04 08:44:59 +04:00
/* SHTNAK */
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_BULK ) & &
2011-04-04 08:44:59 +04:00
! dir )
shtnak = SHTNAK ;
/* EPNUM */
2011-10-11 08:59:46 +04:00
epnum = 0 ; /* see usbhs_pipe_config_update() */
2011-04-04 08:44:59 +04:00
return type |
bfre |
dblb |
cntmd |
dir |
shtnak |
epnum ;
}
2011-10-11 08:59:46 +04:00
static u16 usbhsp_setup_pipebuff ( struct usbhs_pipe * pipe )
2011-04-04 08:44:59 +04:00
{
2011-06-06 09:18:03 +04:00
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
struct usbhs_pipe_info * info = usbhs_priv_to_pipeinfo ( priv ) ;
2011-04-04 08:44:59 +04:00
struct device * dev = usbhs_priv_to_dev ( priv ) ;
int pipe_num = usbhs_pipe_number ( pipe ) ;
int is_double = usbhsp_possible_double_buffer ( pipe ) ;
u16 buff_size ;
u16 bufnmb ;
u16 bufnmb_cnt ;
/*
* PIPEBUF
*
* see
* - " Register Descriptions " - " PIPEBUF " register
* - " Features " - " Pipe configuration "
* - " Operation " - " FIFO Buffer Memory "
* - " Operation " - " Pipe Control "
*
* ex ) if pipe6 - pipe9 are USB_ENDPOINT_XFER_INT ( SH7724 )
*
* BUFNMB : PIPE
* 0 : pipe0 ( DCP 256 byte )
* 1 : -
* 2 : -
* 3 : -
* 4 : pipe6 ( INT 64 byte )
* 5 : pipe7 ( INT 64 byte )
* 6 : pipe8 ( INT 64 byte )
* 7 : pipe9 ( INT 64 byte )
* 8 - xx : free ( for BULK , ISOC )
*/
/*
* FIXME
*
* it doesn ' t have good buffer allocator
*
* DCP : 256 byte
* BULK : 512 byte
* INT : 64 byte
* ISOC : 512 byte
*/
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_CONTROL ) )
2011-04-04 08:44:59 +04:00
buff_size = 256 ;
2011-10-11 09:02:21 +04:00
else if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_INT ) )
2011-04-04 08:44:59 +04:00
buff_size = 64 ;
else
buff_size = 512 ;
/* change buff_size to register value */
bufnmb_cnt = ( buff_size / 64 ) - 1 ;
/* BUFNMB has been reserved for INT pipe
* see above */
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_INT ) ) {
2011-04-04 08:44:59 +04:00
bufnmb = pipe_num - 2 ;
} else {
bufnmb = info - > bufnmb_last ;
info - > bufnmb_last + = bufnmb_cnt + 1 ;
/*
* double buffer
*/
if ( is_double )
info - > bufnmb_last + = bufnmb_cnt + 1 ;
}
dev_dbg ( dev , " pipe : %d : buff_size 0x%x: bufnmb 0x%x \n " ,
pipe_num , buff_size , bufnmb ) ;
return ( 0x1f & bufnmb_cnt ) < < 10 |
( 0xff & bufnmb ) < < 0 ;
}
2011-10-11 09:04:00 +04:00
void usbhs_pipe_config_update ( struct usbhs_pipe * pipe , u16 devsel ,
u16 epnum , u16 maxp )
2011-10-11 08:59:46 +04:00
{
2011-10-11 09:04:00 +04:00
if ( devsel > 0xA ) {
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
struct device * dev = usbhs_priv_to_dev ( priv ) ;
dev_err ( dev , " devsel error %d \n " , devsel ) ;
devsel = 0 ;
}
2011-10-11 08:59:46 +04:00
usbhsp_pipe_barrier ( pipe ) ;
2011-10-11 09:00:42 +04:00
pipe - > maxp = maxp ;
2011-10-11 08:59:46 +04:00
usbhsp_pipe_select ( pipe ) ;
2011-10-11 09:04:00 +04:00
usbhsp_pipe_maxp_set ( pipe , 0xFFFF ,
( devsel < < 12 ) |
maxp ) ;
2011-10-11 08:59:46 +04:00
if ( ! usbhs_pipe_is_dcp ( pipe ) )
usbhsp_pipe_cfg_set ( pipe , 0x000F , epnum ) ;
}
2011-04-04 08:44:59 +04:00
/*
* pipe control
*/
int usbhs_pipe_get_maxpacket ( struct usbhs_pipe * pipe )
{
2011-10-11 09:00:42 +04:00
/*
* see
* usbhs_pipe_config_update ( )
* usbhs_dcp_malloc ( )
*/
return pipe - > maxp ;
2011-04-04 08:44:59 +04:00
}
int usbhs_pipe_is_dir_in ( struct usbhs_pipe * pipe )
{
return usbhsp_flags_has ( pipe , IS_DIR_IN ) ;
}
2011-06-06 09:17:56 +04:00
int usbhs_pipe_is_dir_host ( struct usbhs_pipe * pipe )
{
return usbhsp_flags_has ( pipe , IS_DIR_HOST ) ;
}
2014-08-22 15:13:50 +04:00
int usbhs_pipe_is_running ( struct usbhs_pipe * pipe )
{
return usbhsp_flags_has ( pipe , IS_RUNNING ) ;
}
void usbhs_pipe_running ( struct usbhs_pipe * pipe , int running )
{
if ( running )
usbhsp_flags_set ( pipe , IS_RUNNING ) ;
else
usbhsp_flags_clr ( pipe , IS_RUNNING ) ;
}
2011-12-09 06:28:54 +04:00
void usbhs_pipe_data_sequence ( struct usbhs_pipe * pipe , int sequence )
2011-04-04 08:44:59 +04:00
{
2011-10-11 09:05:30 +04:00
u16 mask = ( SQCLR | SQSET ) ;
2011-12-09 06:28:54 +04:00
u16 val ;
/*
* sequence
* 0 : data0
* 1 : data1
* - 1 : no change
*/
switch ( sequence ) {
case 0 :
val = SQCLR ;
break ;
case 1 :
val = SQSET ;
break ;
default :
return ;
}
2011-10-11 09:05:30 +04:00
usbhsp_pipectrl_set ( pipe , mask , val ) ;
2011-04-04 08:44:59 +04:00
}
2015-03-12 09:35:20 +03:00
static int usbhs_pipe_get_data_sequence ( struct usbhs_pipe * pipe )
{
return ! ! ( usbhsp_pipectrl_get ( pipe ) & SQMON ) ;
}
2011-06-09 11:48:25 +04:00
void usbhs_pipe_clear ( struct usbhs_pipe * pipe )
{
2014-11-04 04:05:45 +03:00
if ( usbhs_pipe_is_dcp ( pipe ) ) {
usbhs_fifo_clear_dcp ( pipe ) ;
} else {
usbhsp_pipectrl_set ( pipe , ACLRM , ACLRM ) ;
usbhsp_pipectrl_set ( pipe , ACLRM , 0 ) ;
}
2011-06-09 11:48:25 +04:00
}
2015-03-12 09:35:20 +03:00
void usbhs_pipe_config_change_bfre ( struct usbhs_pipe * pipe , int enable )
{
int sequence ;
if ( usbhs_pipe_is_dcp ( pipe ) )
return ;
usbhsp_pipe_select ( pipe ) ;
/* check if the driver needs to change the BFRE value */
if ( ! ( enable ^ ! ! ( usbhsp_pipe_cfg_get ( pipe ) & BFRE ) ) )
return ;
sequence = usbhs_pipe_get_data_sequence ( pipe ) ;
usbhsp_pipe_cfg_set ( pipe , BFRE , enable ? BFRE : 0 ) ;
usbhs_pipe_clear ( pipe ) ;
usbhs_pipe_data_sequence ( pipe , sequence ) ;
}
2011-04-04 08:44:59 +04:00
static struct usbhs_pipe * usbhsp_get_pipe ( struct usbhs_priv * priv , u32 type )
{
struct usbhs_pipe * pos , * pipe ;
int i ;
/*
* find target pipe
*/
pipe = NULL ;
usbhs_for_each_pipe_with_dcp ( pos , priv , i ) {
2011-10-11 09:02:21 +04:00
if ( ! usbhs_pipe_type_is ( pos , type ) )
2011-04-04 08:44:59 +04:00
continue ;
if ( usbhsp_flags_has ( pos , IS_USED ) )
continue ;
pipe = pos ;
break ;
}
if ( ! pipe )
return NULL ;
/*
* initialize pipe flags
*/
usbhsp_flags_init ( pipe ) ;
usbhsp_flags_set ( pipe , IS_USED ) ;
return pipe ;
}
2014-07-09 15:30:13 +04:00
static void usbhsp_put_pipe ( struct usbhs_pipe * pipe )
{
usbhsp_flags_init ( pipe ) ;
}
2011-06-06 09:18:07 +04:00
void usbhs_pipe_init ( struct usbhs_priv * priv ,
2011-06-06 09:19:03 +04:00
int ( * dma_map_ctrl ) ( struct usbhs_pkt * pkt , int map ) )
2011-04-04 08:44:59 +04:00
{
2011-06-06 09:18:03 +04:00
struct usbhs_pipe_info * info = usbhs_priv_to_pipeinfo ( priv ) ;
2011-04-04 08:44:59 +04:00
struct usbhs_pipe * pipe ;
int i ;
/*
* FIXME
*
* driver needs good allocator .
*
* find first free buffer area ( BULK , ISOC )
* ( DCP , INT area is fixed )
*
* buffer number 0 - 3 have been reserved for DCP
* see
* usbhsp_to_bufnmb
*/
info - > bufnmb_last = 4 ;
usbhs_for_each_pipe_with_dcp ( pipe , priv , i ) {
2011-10-11 09:02:21 +04:00
if ( usbhs_pipe_type_is ( pipe , USB_ENDPOINT_XFER_INT ) )
2011-04-04 08:44:59 +04:00
info - > bufnmb_last + + ;
usbhsp_flags_init ( pipe ) ;
2011-06-06 09:18:50 +04:00
pipe - > fifo = NULL ;
2011-04-04 08:44:59 +04:00
pipe - > mod_private = NULL ;
2011-06-06 09:18:16 +04:00
INIT_LIST_HEAD ( & pipe - > list ) ;
2011-04-21 09:09:58 +04:00
2011-06-06 09:18:03 +04:00
/* pipe force init */
2011-06-09 11:48:25 +04:00
usbhs_pipe_clear ( pipe ) ;
2011-04-04 08:44:59 +04:00
}
2011-06-06 09:18:07 +04:00
2011-06-06 09:19:03 +04:00
info - > dma_map_ctrl = dma_map_ctrl ;
2011-04-04 08:44:59 +04:00
}
struct usbhs_pipe * usbhs_pipe_malloc ( struct usbhs_priv * priv ,
2011-10-11 08:59:46 +04:00
int endpoint_type ,
int dir_in )
2011-04-04 08:44:59 +04:00
{
struct device * dev = usbhs_priv_to_dev ( priv ) ;
struct usbhs_pipe * pipe ;
2011-10-11 09:02:45 +04:00
int is_host = usbhs_mod_is_host ( priv ) ;
2011-04-04 08:44:59 +04:00
int ret ;
2011-10-11 08:59:46 +04:00
u16 pipecfg , pipebuf ;
2011-04-04 08:44:59 +04:00
2011-10-11 08:59:46 +04:00
pipe = usbhsp_get_pipe ( priv , endpoint_type ) ;
2011-04-21 09:10:24 +04:00
if ( ! pipe ) {
dev_err ( dev , " can't get pipe (%s) \n " ,
2011-10-11 08:59:46 +04:00
usbhsp_pipe_name [ endpoint_type ] ) ;
2011-04-04 08:44:59 +04:00
return NULL ;
2011-04-21 09:10:24 +04:00
}
2011-04-04 08:44:59 +04:00
2011-06-06 09:18:16 +04:00
INIT_LIST_HEAD ( & pipe - > list ) ;
2011-06-06 09:18:03 +04:00
usbhs_pipe_disable ( pipe ) ;
2011-04-04 08:44:59 +04:00
/* make sure pipe is not busy */
ret = usbhsp_pipe_barrier ( pipe ) ;
if ( ret < 0 ) {
dev_err ( dev , " pipe setup failed %d \n " , usbhs_pipe_number ( pipe ) ) ;
return NULL ;
}
2011-10-11 08:59:46 +04:00
pipecfg = usbhsp_setup_pipecfg ( pipe , is_host , dir_in ) ;
pipebuf = usbhsp_setup_pipebuff ( pipe ) ;
2011-04-04 08:44:59 +04:00
usbhsp_pipe_select ( pipe ) ;
usbhsp_pipe_cfg_set ( pipe , 0xFFFF , pipecfg ) ;
usbhsp_pipe_buf_set ( pipe , 0xFFFF , pipebuf ) ;
2014-07-09 15:30:03 +04:00
usbhs_pipe_clear ( pipe ) ;
2011-04-04 08:44:59 +04:00
2011-10-11 09:05:30 +04:00
usbhs_pipe_sequence_data0 ( pipe ) ;
2011-04-04 08:44:59 +04:00
dev_dbg ( dev , " enable pipe %d : %s (%s) \n " ,
usbhs_pipe_number ( pipe ) ,
2011-10-11 09:04:23 +04:00
usbhs_pipe_name ( pipe ) ,
2011-04-04 08:44:59 +04:00
usbhs_pipe_is_dir_in ( pipe ) ? " in " : " out " ) ;
2011-10-11 08:59:46 +04:00
/*
* epnum / maxp are still not set to this pipe .
* call usbhs_pipe_config_update ( ) after this function ! !
*/
2011-04-04 08:44:59 +04:00
return pipe ;
}
2014-07-09 15:30:13 +04:00
void usbhs_pipe_free ( struct usbhs_pipe * pipe )
{
usbhsp_put_pipe ( pipe ) ;
}
2011-06-06 09:18:50 +04:00
void usbhs_pipe_select_fifo ( struct usbhs_pipe * pipe , struct usbhs_fifo * fifo )
{
if ( pipe - > fifo )
pipe - > fifo - > pipe = NULL ;
pipe - > fifo = fifo ;
if ( fifo )
fifo - > pipe = pipe ;
}
2011-04-04 08:44:59 +04:00
/*
* dcp control
*/
struct usbhs_pipe * usbhs_dcp_malloc ( struct usbhs_priv * priv )
{
struct usbhs_pipe * pipe ;
pipe = usbhsp_get_pipe ( priv , USB_ENDPOINT_XFER_CONTROL ) ;
if ( ! pipe )
return NULL ;
2011-10-11 08:59:46 +04:00
INIT_LIST_HEAD ( & pipe - > list ) ;
2011-04-04 08:44:59 +04:00
/*
2011-10-11 08:59:46 +04:00
* call usbhs_pipe_config_update ( ) after this function ! !
2011-04-04 08:44:59 +04:00
*/
return pipe ;
}
void usbhs_dcp_control_transfer_done ( struct usbhs_pipe * pipe )
{
2011-10-11 09:07:20 +04:00
struct usbhs_priv * priv = usbhs_pipe_to_priv ( pipe ) ;
2011-06-06 09:18:03 +04:00
WARN_ON ( ! usbhs_pipe_is_dcp ( pipe ) ) ;
2011-04-04 08:44:59 +04:00
2011-06-06 09:18:03 +04:00
usbhs_pipe_enable ( pipe ) ;
2011-10-11 09:07:20 +04:00
if ( ! usbhs_mod_is_host ( priv ) ) /* funconly */
usbhsp_pipectrl_set ( pipe , CCPL , CCPL ) ;
2011-04-04 08:44:59 +04:00
}
2011-10-11 09:02:57 +04:00
void usbhs_dcp_dir_for_host ( struct usbhs_pipe * pipe , int dir_out )
{
usbhsp_pipe_cfg_set ( pipe , DIR_OUT ,
dir_out ? DIR_OUT : 0 ) ;
}
2011-04-04 08:44:59 +04:00
/*
* pipe module function
*/
int usbhs_pipe_probe ( struct usbhs_priv * priv )
{
2011-06-06 09:18:03 +04:00
struct usbhs_pipe_info * info = usbhs_priv_to_pipeinfo ( priv ) ;
2011-04-04 08:44:59 +04:00
struct usbhs_pipe * pipe ;
struct device * dev = usbhs_priv_to_dev ( priv ) ;
u32 * pipe_type = usbhs_get_dparam ( priv , pipe_type ) ;
int pipe_size = usbhs_get_dparam ( priv , pipe_size ) ;
int i ;
/* This driver expects 1st pipe is DCP */
if ( pipe_type [ 0 ] ! = USB_ENDPOINT_XFER_CONTROL ) {
dev_err ( dev , " 1st PIPE is not DCP \n " ) ;
return - EINVAL ;
}
info - > pipe = kzalloc ( sizeof ( struct usbhs_pipe ) * pipe_size , GFP_KERNEL ) ;
if ( ! info - > pipe ) {
dev_err ( dev , " Could not allocate pipe \n " ) ;
return - ENOMEM ;
}
info - > size = pipe_size ;
/*
* init pipe
*/
usbhs_for_each_pipe_with_dcp ( pipe , priv , i ) {
pipe - > priv = priv ;
2011-10-11 09:02:21 +04:00
usbhs_pipe_type ( pipe ) =
pipe_type [ i ] & USB_ENDPOINT_XFERTYPE_MASK ;
2011-04-04 08:44:59 +04:00
dev_dbg ( dev , " pipe %x \t : %s \n " ,
i , usbhsp_pipe_name [ pipe_type [ i ] ] ) ;
}
return 0 ;
}
void usbhs_pipe_remove ( struct usbhs_priv * priv )
{
2011-06-06 09:18:03 +04:00
struct usbhs_pipe_info * info = usbhs_priv_to_pipeinfo ( priv ) ;
2011-04-04 08:44:59 +04:00
kfree ( info - > pipe ) ;
}