2006-12-04 08:31:14 -03:00
/*
2007-04-14 16:23:49 -03:00
* usbvision_i2c . c
2006-12-04 08:30:53 -03:00
* i2c algorithm for USB - I2C Bridges
*
2007-04-14 16:23:49 -03:00
* Copyright ( c ) 1999 - 2007 Joerg Heckenbach < joerg @ heckenbach - aw . de >
2006-12-04 08:30:53 -03:00
* Dwaine Garden < dwainegarden @ rogers . com >
*
* This module is part of usbvision driver project .
* Updates to driver completed by Dwaine P . Garden
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/version.h>
2006-12-09 11:41:59 -03:00
# include <linux/utsname.h>
2006-12-04 08:30:53 -03:00
# include <linux/init.h>
# include <asm/uaccess.h>
# include <linux/ioport.h>
# include <linux/errno.h>
# include <linux/usb.h>
# include <linux/i2c.h>
2006-12-04 08:31:45 -03:00
# include "usbvision.h"
2006-12-04 08:30:53 -03:00
2006-12-04 08:31:45 -03:00
# define DBG_I2C 1<<0
2006-12-04 08:30:53 -03:00
2008-04-22 14:41:48 -03:00
static int i2c_debug ;
2006-12-04 08:31:45 -03:00
module_param ( i2c_debug , int , 0644 ) ; // debug_i2c_usb mode of the device driver
MODULE_PARM_DESC ( i2c_debug , " enable debug messages [i2c] " ) ;
2006-12-04 08:30:53 -03:00
2008-04-04 21:00:57 -03:00
# define PDEBUG(level, fmt, args...) { \
if ( i2c_debug & ( level ) ) \
info ( " [%s:%d] " fmt , __func__ , __LINE__ , # # args ) ; \
}
2006-12-04 08:30:53 -03:00
2007-04-14 16:23:49 -03:00
static int usbvision_i2c_write ( struct usb_usbvision * usbvision , unsigned char addr , char * buf ,
2006-12-11 05:37:14 -03:00
short len ) ;
2007-04-14 16:23:49 -03:00
static int usbvision_i2c_read ( struct usb_usbvision * usbvision , unsigned char addr , char * buf ,
2006-12-11 05:37:14 -03:00
short len ) ;
2006-12-04 08:30:53 -03:00
static inline int try_write_address ( struct i2c_adapter * i2c_adap ,
unsigned char addr , int retries )
{
2007-04-14 16:23:49 -03:00
struct usb_usbvision * usbvision ;
2006-12-04 08:30:53 -03:00
int i , ret = - 1 ;
char buf [ 4 ] ;
2007-04-16 18:00:49 -03:00
usbvision = ( struct usb_usbvision * ) i2c_get_adapdata ( i2c_adap ) ;
2006-12-04 08:30:53 -03:00
buf [ 0 ] = 0x00 ;
for ( i = 0 ; i < = retries ; i + + ) {
2007-04-14 16:23:49 -03:00
ret = ( usbvision_i2c_write ( usbvision , addr , buf , 1 ) ) ;
2006-12-04 08:30:53 -03:00
if ( ret = = 1 )
break ; /* success! */
2006-12-11 17:18:15 -03:00
udelay ( 5 ) ;
2006-12-04 08:30:53 -03:00
if ( i = = retries ) /* no success */
break ;
2006-12-11 17:18:15 -03:00
udelay ( 10 ) ;
2006-12-04 08:30:53 -03:00
}
2006-12-04 08:31:45 -03:00
if ( i ) {
2007-04-14 16:23:49 -03:00
PDEBUG ( DBG_I2C , " Needed %d retries for address %#2x " , i , addr ) ;
PDEBUG ( DBG_I2C , " Maybe there's no device at this address " ) ;
2006-12-04 08:30:53 -03:00
}
return ret ;
}
static inline int try_read_address ( struct i2c_adapter * i2c_adap ,
unsigned char addr , int retries )
{
2007-04-14 16:23:49 -03:00
struct usb_usbvision * usbvision ;
2006-12-04 08:30:53 -03:00
int i , ret = - 1 ;
char buf [ 4 ] ;
2007-04-16 18:00:49 -03:00
usbvision = ( struct usb_usbvision * ) i2c_get_adapdata ( i2c_adap ) ;
2006-12-04 08:30:53 -03:00
for ( i = 0 ; i < = retries ; i + + ) {
2007-04-14 16:23:49 -03:00
ret = ( usbvision_i2c_read ( usbvision , addr , buf , 1 ) ) ;
2006-12-04 08:30:53 -03:00
if ( ret = = 1 )
break ; /* success! */
2006-12-11 17:18:15 -03:00
udelay ( 5 ) ;
2006-12-04 08:30:53 -03:00
if ( i = = retries ) /* no success */
break ;
2006-12-11 17:18:15 -03:00
udelay ( 10 ) ;
2006-12-04 08:30:53 -03:00
}
2006-12-04 08:31:45 -03:00
if ( i ) {
2007-04-14 16:23:49 -03:00
PDEBUG ( DBG_I2C , " Needed %d retries for address %#2x " , i , addr ) ;
PDEBUG ( DBG_I2C , " Maybe there's no device at this address " ) ;
2006-12-04 08:30:53 -03:00
}
return ret ;
}
static inline int usb_find_address ( struct i2c_adapter * i2c_adap ,
struct i2c_msg * msg , int retries ,
unsigned char * add )
{
unsigned short flags = msg - > flags ;
2006-12-04 08:31:14 -03:00
2006-12-04 08:30:53 -03:00
unsigned char addr ;
int ret ;
if ( ( flags & I2C_M_TEN ) ) {
/* a ten bit address */
addr = 0xf0 | ( ( msg - > addr > > 7 ) & 0x03 ) ;
/* try extended address code... */
ret = try_write_address ( i2c_adap , addr , retries ) ;
if ( ret ! = 1 ) {
err ( " died at extended address code, while writing " ) ;
return - EREMOTEIO ;
}
add [ 0 ] = addr ;
if ( flags & I2C_M_RD ) {
/* okay, now switch into reading mode */
addr | = 0x01 ;
ret = try_read_address ( i2c_adap , addr , retries ) ;
if ( ret ! = 1 ) {
err ( " died at extended address code, while reading " ) ;
return - EREMOTEIO ;
}
}
} else { /* normal 7bit address */
addr = ( msg - > addr < < 1 ) ;
if ( flags & I2C_M_RD )
addr | = 1 ;
add [ 0 ] = addr ;
if ( flags & I2C_M_RD )
ret = try_read_address ( i2c_adap , addr , retries ) ;
else
ret = try_write_address ( i2c_adap , addr , retries ) ;
if ( ret ! = 1 ) {
return - EREMOTEIO ;
}
}
return 0 ;
}
static int
2007-04-14 16:23:49 -03:00
usbvision_i2c_xfer ( struct i2c_adapter * i2c_adap , struct i2c_msg msgs [ ] , int num )
2006-12-04 08:30:53 -03:00
{
struct i2c_msg * pmsg ;
2007-04-14 16:23:49 -03:00
struct usb_usbvision * usbvision ;
2006-12-04 08:30:53 -03:00
int i , ret ;
unsigned char addr ;
2007-04-16 18:00:49 -03:00
usbvision = ( struct usb_usbvision * ) i2c_get_adapdata ( i2c_adap ) ;
2006-12-04 08:30:53 -03:00
for ( i = 0 ; i < num ; i + + ) {
pmsg = & msgs [ i ] ;
ret = usb_find_address ( i2c_adap , pmsg , i2c_adap - > retries , & addr ) ;
if ( ret ! = 0 ) {
2007-04-14 16:23:49 -03:00
PDEBUG ( DBG_I2C , " got NAK from device, message #%d " , i ) ;
2006-12-04 08:30:53 -03:00
return ( ret < 0 ) ? ret : - EREMOTEIO ;
}
if ( pmsg - > flags & I2C_M_RD ) {
/* read bytes into buffer */
2007-04-14 16:23:49 -03:00
ret = ( usbvision_i2c_read ( usbvision , addr , pmsg - > buf , pmsg - > len ) ) ;
2006-12-04 08:30:53 -03:00
if ( ret < pmsg - > len ) {
return ( ret < 0 ) ? ret : - EREMOTEIO ;
}
} else {
/* write bytes from buffer */
2007-04-14 16:23:49 -03:00
ret = ( usbvision_i2c_write ( usbvision , addr , pmsg - > buf , pmsg - > len ) ) ;
2006-12-04 08:30:53 -03:00
if ( ret < pmsg - > len ) {
return ( ret < 0 ) ? ret : - EREMOTEIO ;
}
}
}
return num ;
}
2007-04-14 16:23:49 -03:00
static u32 functionality ( struct i2c_adapter * adap )
2006-12-04 08:30:53 -03:00
{
2007-09-09 06:17:44 -03:00
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR ;
2006-12-04 08:30:53 -03:00
}
/* -----exported algorithm data: ------------------------------------- */
2007-04-14 16:23:49 -03:00
static struct i2c_algorithm usbvision_algo = {
. master_xfer = usbvision_i2c_xfer ,
2006-12-04 08:30:53 -03:00
. smbus_xfer = NULL ,
2007-04-14 16:23:49 -03:00
. functionality = functionality ,
2006-12-04 08:30:53 -03:00
} ;
2007-04-16 18:00:49 -03:00
/*
* registering functions to load algorithms at runtime
*/
static int usbvision_i2c_usb_add_bus ( struct i2c_adapter * adap )
{
PDEBUG ( DBG_I2C , " I2C debugging is enabled [i2c] " ) ;
PDEBUG ( DBG_I2C , " ALGO debugging is enabled [i2c] " ) ;
/* register new adapter to i2c module... */
adap - > algo = & usbvision_algo ;
adap - > timeout = 100 ; /* default values, should */
adap - > retries = 3 ; /* be replaced by defines */
i2c_add_adapter ( adap ) ;
PDEBUG ( DBG_I2C , " i2c bus for %s registered " , adap - > name ) ;
return 0 ;
}
2006-12-04 08:31:45 -03:00
/* ----------------------------------------------------------------------- */
/* usbvision specific I2C functions */
/* ----------------------------------------------------------------------- */
static struct i2c_adapter i2c_adap_template ;
static struct i2c_client i2c_client_template ;
2007-04-14 16:23:49 -03:00
int usbvision_i2c_register ( struct usb_usbvision * usbvision )
2006-12-04 08:31:45 -03:00
{
2007-04-16 18:00:49 -03:00
memcpy ( & usbvision - > i2c_adap , & i2c_adap_template ,
sizeof ( struct i2c_adapter ) ) ;
memcpy ( & usbvision - > i2c_client , & i2c_client_template ,
sizeof ( struct i2c_client ) ) ;
2006-12-04 08:31:45 -03:00
2007-04-14 16:23:49 -03:00
sprintf ( usbvision - > i2c_adap . name + strlen ( usbvision - > i2c_adap . name ) ,
" #%d " , usbvision - > vdev - > minor & 0x1f ) ;
2007-04-16 18:00:49 -03:00
PDEBUG ( DBG_I2C , " Adaptername: %s " , usbvision - > i2c_adap . name ) ;
usbvision - > i2c_adap . dev . parent = & usbvision - > dev - > dev ;
i2c_set_adapdata ( & usbvision - > i2c_adap , usbvision ) ;
i2c_set_clientdata ( & usbvision - > i2c_client , usbvision ) ;
2007-04-14 16:23:49 -03:00
2006-12-04 08:31:45 -03:00
usbvision - > i2c_client . adapter = & usbvision - > i2c_adap ;
if ( usbvision_write_reg ( usbvision , USBVISION_SER_MODE , USBVISION_IIC_LRNACK ) < 0 ) {
2007-04-16 18:00:49 -03:00
printk ( KERN_ERR " usbvision_register: can't write reg \n " ) ;
2006-12-04 08:31:45 -03:00
return - EBUSY ;
}
# ifdef CONFIG_MODULES
/* Request the load of the i2c modules we need */
switch ( usbvision_device_data [ usbvision - > DevModel ] . Codec ) {
case CODEC_SAA7113 :
request_module ( " saa7115 " ) ;
break ;
case CODEC_SAA7111 :
request_module ( " saa7115 " ) ;
break ;
}
if ( usbvision_device_data [ usbvision - > DevModel ] . Tuner = = 1 ) {
request_module ( " tuner " ) ;
2006-12-04 08:30:53 -03:00
}
# endif
2007-04-16 18:00:49 -03:00
return usbvision_i2c_usb_add_bus ( & usbvision - > i2c_adap ) ;
2007-04-14 16:23:49 -03:00
}
int usbvision_i2c_unregister ( struct usb_usbvision * usbvision )
{
i2c_del_adapter ( & ( usbvision - > i2c_adap ) ) ;
PDEBUG ( DBG_I2C , " i2c bus for %s unregistered " , usbvision - > i2c_adap . name ) ;
return 0 ;
2006-12-04 08:31:45 -03:00
}
void call_i2c_clients ( struct usb_usbvision * usbvision , unsigned int cmd ,
void * arg )
{
i2c_clients_command ( & usbvision - > i2c_adap , cmd , arg ) ;
}
static int attach_inform ( struct i2c_client * client )
{
struct usb_usbvision * usbvision ;
2007-04-16 18:00:49 -03:00
usbvision = ( struct usb_usbvision * ) i2c_get_adapdata ( client - > adapter ) ;
2006-12-04 08:31:45 -03:00
switch ( client - > addr < < 1 ) {
2007-04-15 10:09:56 -03:00
case 0x42 < < 1 :
case 0x43 < < 1 :
case 0x4a < < 1 :
case 0x4b < < 1 :
2007-04-16 17:47:08 -03:00
PDEBUG ( DBG_I2C , " attach_inform: tda9887 detected. " ) ;
2006-12-04 08:31:45 -03:00
break ;
case 0x42 :
PDEBUG ( DBG_I2C , " attach_inform: saa7114 detected. " ) ;
break ;
case 0x4a :
PDEBUG ( DBG_I2C , " attach_inform: saa7113 detected. " ) ;
break ;
2006-12-15 16:46:53 -03:00
case 0x48 :
PDEBUG ( DBG_I2C , " attach_inform: saa7111 detected. " ) ;
break ;
2006-12-04 08:31:45 -03:00
case 0xa0 :
PDEBUG ( DBG_I2C , " attach_inform: eeprom detected. " ) ;
break ;
default :
{
struct tuner_setup tun_setup ;
PDEBUG ( DBG_I2C , " attach inform: detected I2C address %x " , client - > addr < < 1 ) ;
usbvision - > tuner_addr = client - > addr ;
if ( ( usbvision - > have_tuner ) & & ( usbvision - > tuner_type ! = - 1 ) ) {
tun_setup . mode_mask = T_ANALOG_TV | T_RADIO ;
tun_setup . type = usbvision - > tuner_type ;
tun_setup . addr = usbvision - > tuner_addr ;
call_i2c_clients ( usbvision , TUNER_SET_TYPE_ADDR , & tun_setup ) ;
}
}
break ;
}
2006-12-04 08:30:53 -03:00
return 0 ;
}
2006-12-04 08:31:45 -03:00
static int detach_inform ( struct i2c_client * client )
{
struct usb_usbvision * usbvision ;
2007-04-16 18:00:49 -03:00
usbvision = ( struct usb_usbvision * ) i2c_get_adapdata ( client - > adapter ) ;
2006-12-04 08:31:45 -03:00
2006-12-09 11:41:59 -03:00
PDEBUG ( DBG_I2C , " usbvision[%d] detaches %s " , usbvision - > nr , client - > name ) ;
2006-12-04 08:31:45 -03:00
return 0 ;
}
static int
usbvision_i2c_read_max4 ( struct usb_usbvision * usbvision , unsigned char addr ,
char * buf , short len )
{
int rc , retries ;
for ( retries = 5 ; ; ) {
rc = usbvision_write_reg ( usbvision , USBVISION_SER_ADRS , addr ) ;
if ( rc < 0 )
return rc ;
/* Initiate byte read cycle */
/* USBVISION_SER_CONT <- d0-d2 n. of bytes to r/w */
/* d3 0=Wr 1=Rd */
rc = usbvision_write_reg ( usbvision , USBVISION_SER_CONT ,
( len & 0x07 ) | 0x18 ) ;
if ( rc < 0 )
return rc ;
/* Test for Busy and ACK */
do {
/* USBVISION_SER_CONT -> d4 == 0 busy */
rc = usbvision_read_reg ( usbvision , USBVISION_SER_CONT ) ;
} while ( rc > 0 & & ( ( rc & 0x10 ) ! = 0 ) ) ; /* Retry while busy */
if ( rc < 0 )
return rc ;
/* USBVISION_SER_CONT -> d5 == 1 Not ack */
if ( ( rc & 0x20 ) = = 0 ) /* Ack? */
break ;
/* I2C abort */
rc = usbvision_write_reg ( usbvision , USBVISION_SER_CONT , 0x00 ) ;
if ( rc < 0 )
return rc ;
if ( - - retries < 0 )
return - 1 ;
}
switch ( len ) {
case 4 :
buf [ 3 ] = usbvision_read_reg ( usbvision , USBVISION_SER_DAT4 ) ;
case 3 :
buf [ 2 ] = usbvision_read_reg ( usbvision , USBVISION_SER_DAT3 ) ;
case 2 :
buf [ 1 ] = usbvision_read_reg ( usbvision , USBVISION_SER_DAT2 ) ;
case 1 :
buf [ 0 ] = usbvision_read_reg ( usbvision , USBVISION_SER_DAT1 ) ;
break ;
default :
printk ( KERN_ERR
" usbvision_i2c_read_max4: buffer length > 4 \n " ) ;
}
if ( i2c_debug & DBG_I2C ) {
int idx ;
for ( idx = 0 ; idx < len ; idx + + ) {
PDEBUG ( DBG_I2C , " read %x from address %x " , ( unsigned char ) buf [ idx ] , addr ) ;
}
}
return len ;
}
static int usbvision_i2c_write_max4 ( struct usb_usbvision * usbvision ,
unsigned char addr , const char * buf ,
short len )
{
int rc , retries ;
int i ;
unsigned char value [ 6 ] ;
unsigned char ser_cont ;
ser_cont = ( len & 0x07 ) | 0x10 ;
value [ 0 ] = addr ;
value [ 1 ] = ser_cont ;
for ( i = 0 ; i < len ; i + + )
value [ i + 2 ] = buf [ i ] ;
for ( retries = 5 ; ; ) {
rc = usb_control_msg ( usbvision - > dev ,
usb_sndctrlpipe ( usbvision - > dev , 1 ) ,
USBVISION_OP_CODE ,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_ENDPOINT , 0 ,
( __u16 ) USBVISION_SER_ADRS , value ,
len + 2 , HZ ) ;
if ( rc < 0 )
return rc ;
rc = usbvision_write_reg ( usbvision , USBVISION_SER_CONT ,
( len & 0x07 ) | 0x10 ) ;
if ( rc < 0 )
return rc ;
/* Test for Busy and ACK */
do {
rc = usbvision_read_reg ( usbvision , USBVISION_SER_CONT ) ;
} while ( rc > 0 & & ( ( rc & 0x10 ) ! = 0 ) ) ; /* Retry while busy */
if ( rc < 0 )
return rc ;
if ( ( rc & 0x20 ) = = 0 ) /* Ack? */
break ;
/* I2C abort */
usbvision_write_reg ( usbvision , USBVISION_SER_CONT , 0x00 ) ;
if ( - - retries < 0 )
return - 1 ;
}
if ( i2c_debug & DBG_I2C ) {
int idx ;
for ( idx = 0 ; idx < len ; idx + + ) {
PDEBUG ( DBG_I2C , " wrote %x at address %x " , ( unsigned char ) buf [ idx ] , addr ) ;
}
}
return len ;
}
2007-04-14 16:23:49 -03:00
static int usbvision_i2c_write ( struct usb_usbvision * usbvision , unsigned char addr , char * buf ,
2006-12-04 08:31:45 -03:00
short len )
{
char * bufPtr = buf ;
int retval ;
int wrcount = 0 ;
int count ;
int maxLen = 4 ;
while ( len > 0 ) {
count = ( len > maxLen ) ? maxLen : len ;
retval = usbvision_i2c_write_max4 ( usbvision , addr , bufPtr , count ) ;
if ( retval > 0 ) {
len - = count ;
bufPtr + = count ;
wrcount + = count ;
} else
return ( retval < 0 ) ? retval : - EFAULT ;
}
return wrcount ;
}
2007-04-14 16:23:49 -03:00
static int usbvision_i2c_read ( struct usb_usbvision * usbvision , unsigned char addr , char * buf ,
2006-12-04 08:31:45 -03:00
short len )
{
char temp [ 4 ] ;
int retval , i ;
int rdcount = 0 ;
int count ;
while ( len > 0 ) {
count = ( len > 3 ) ? 4 : len ;
retval = usbvision_i2c_read_max4 ( usbvision , addr , temp , count ) ;
if ( retval > 0 ) {
for ( i = 0 ; i < len ; i + + )
buf [ rdcount + i ] = temp [ i ] ;
len - = count ;
rdcount + = count ;
} else
return ( retval < 0 ) ? retval : - EFAULT ;
}
return rdcount ;
}
static struct i2c_adapter i2c_adap_template = {
. owner = THIS_MODULE ,
. name = " usbvision " ,
. id = I2C_HW_B_BT848 , /* FIXME */
. client_register = attach_inform ,
. client_unregister = detach_inform ,
2006-12-09 11:41:59 -03:00
# ifdef I2C_ADAP_CLASS_TV_ANALOG
2006-12-04 08:31:45 -03:00
. class = I2C_ADAP_CLASS_TV_ANALOG ,
2006-12-09 11:41:59 -03:00
# else
2006-12-04 08:31:45 -03:00
. class = I2C_CLASS_TV_ANALOG ,
# endif
} ;
static struct i2c_client i2c_client_template = {
. name = " usbvision internal " ,
} ;
/*
* Overrides for Emacs so that we follow Linus ' s tabbing style .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Local variables :
* c - basic - offset : 8
* End :
*/