2006-07-30 00:33:44 +04:00
# include <linux/i2c.h>
# include "dibx000_common.h"
static int debug ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " turn on debugging (default: 0) " ) ;
2009-12-04 19:27:57 +03:00
# define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0)
2006-07-30 00:33:44 +04:00
static int dibx000_write_word ( struct dibx000_i2c_master * mst , u16 reg , u16 val )
{
u8 b [ 4 ] = {
( reg > > 8 ) & 0xff , reg & 0xff ,
( val > > 8 ) & 0xff , val & 0xff ,
} ;
struct i2c_msg msg = {
2009-08-17 14:01:10 +04:00
. addr = mst - > i2c_addr , . flags = 0 , . buf = b , . len = 4
2006-07-30 00:33:44 +04:00
} ;
return i2c_transfer ( mst - > i2c_adap , & msg , 1 ) ! = 1 ? - EREMOTEIO : 0 ;
}
2009-08-17 14:01:10 +04:00
static int dibx000_i2c_select_interface ( struct dibx000_i2c_master * mst ,
enum dibx000_i2c_interface intf )
2006-07-30 00:33:44 +04:00
{
if ( mst - > device_rev > DIB3000MC & & mst - > selected_interface ! = intf ) {
2009-12-04 19:27:57 +03:00
dprintk ( " selecting interface: %d " , intf ) ;
2006-07-30 00:33:44 +04:00
mst - > selected_interface = intf ;
return dibx000_write_word ( mst , mst - > base_reg + 4 , intf ) ;
}
return 0 ;
}
2009-08-17 14:01:10 +04:00
static int dibx000_i2c_gate_ctrl ( struct dibx000_i2c_master * mst , u8 tx [ 4 ] ,
u8 addr , int onoff )
2006-07-30 00:33:44 +04:00
{
u16 val ;
if ( onoff )
2009-08-17 14:01:10 +04:00
val = addr < < 8 ; // bit 7 = use master or not, if 0, the gate is open
2006-07-30 00:33:44 +04:00
else
val = 1 < < 7 ;
if ( mst - > device_rev > DIB7000 )
val < < = 1 ;
tx [ 0 ] = ( ( ( mst - > base_reg + 1 ) > > 8 ) & 0xff ) ;
2009-08-17 14:01:10 +04:00
tx [ 1 ] = ( ( mst - > base_reg + 1 ) & 0xff ) ;
2006-07-30 00:33:44 +04:00
tx [ 2 ] = val > > 8 ;
tx [ 3 ] = val & 0xff ;
return 0 ;
}
static u32 dibx000_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
2009-08-17 14:01:10 +04:00
static int dibx000_i2c_gated_tuner_xfer ( struct i2c_adapter * i2c_adap ,
struct i2c_msg msg [ ] , int num )
2006-07-30 00:33:44 +04:00
{
struct dibx000_i2c_master * mst = i2c_get_adapdata ( i2c_adap ) ;
struct i2c_msg m [ 2 + num ] ;
u8 tx_open [ 4 ] , tx_close [ 4 ] ;
2009-08-17 14:01:10 +04:00
memset ( m , 0 , sizeof ( struct i2c_msg ) * ( 2 + num ) ) ;
2006-07-30 00:33:44 +04:00
dibx000_i2c_select_interface ( mst , DIBX000_I2C_INTERFACE_TUNER ) ;
2009-08-17 14:01:10 +04:00
dibx000_i2c_gate_ctrl ( mst , tx_open , msg [ 0 ] . addr , 1 ) ;
2006-07-30 00:33:44 +04:00
m [ 0 ] . addr = mst - > i2c_addr ;
2009-08-17 14:01:10 +04:00
m [ 0 ] . buf = tx_open ;
m [ 0 ] . len = 4 ;
2006-07-30 00:33:44 +04:00
memcpy ( & m [ 1 ] , msg , sizeof ( struct i2c_msg ) * num ) ;
dibx000_i2c_gate_ctrl ( mst , tx_close , 0 , 0 ) ;
2009-08-17 14:01:10 +04:00
m [ num + 1 ] . addr = mst - > i2c_addr ;
m [ num + 1 ] . buf = tx_close ;
m [ num + 1 ] . len = 4 ;
2006-07-30 00:33:44 +04:00
2009-08-17 14:01:10 +04:00
return i2c_transfer ( mst - > i2c_adap , m , 2 + num ) = = 2 + num ? num : - EIO ;
2006-07-30 00:33:44 +04:00
}
static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
2009-08-17 14:01:10 +04:00
. master_xfer = dibx000_i2c_gated_tuner_xfer ,
2006-07-30 00:33:44 +04:00
. functionality = dibx000_i2c_func ,
} ;
2009-08-17 14:01:10 +04:00
struct i2c_adapter * dibx000_get_i2c_adapter ( struct dibx000_i2c_master * mst ,
enum dibx000_i2c_interface intf ,
int gating )
2006-07-30 00:33:44 +04:00
{
struct i2c_adapter * i2c = NULL ;
switch ( intf ) {
2009-08-17 14:01:10 +04:00
case DIBX000_I2C_INTERFACE_TUNER :
if ( gating )
i2c = & mst - > gated_tuner_i2c_adap ;
break ;
default :
printk ( KERN_ERR " DiBX000: incorrect I2C interface selected \n " ) ;
break ;
2006-07-30 00:33:44 +04:00
}
return i2c ;
}
2009-08-17 14:01:10 +04:00
2006-07-30 00:33:44 +04:00
EXPORT_SYMBOL ( dibx000_get_i2c_adapter ) ;
2009-08-17 14:01:10 +04:00
void dibx000_reset_i2c_master ( struct dibx000_i2c_master * mst )
{
/* initialize the i2c-master by closing the gate */
u8 tx [ 4 ] ;
struct i2c_msg m = { . addr = mst - > i2c_addr , . buf = tx , . len = 4 } ;
dibx000_i2c_gate_ctrl ( mst , tx , 0 , 0 ) ;
i2c_transfer ( mst - > i2c_adap , & m , 1 ) ;
mst - > selected_interface = 0xff ; // the first time force a select of the I2C
dibx000_i2c_select_interface ( mst , DIBX000_I2C_INTERFACE_TUNER ) ;
}
EXPORT_SYMBOL ( dibx000_reset_i2c_master ) ;
static int i2c_adapter_init ( struct i2c_adapter * i2c_adap ,
struct i2c_algorithm * algo , const char * name ,
struct dibx000_i2c_master * mst )
2006-07-30 00:33:44 +04:00
{
2007-05-02 01:26:28 +04:00
strncpy ( i2c_adap - > name , name , sizeof ( i2c_adap - > name ) ) ;
2009-08-17 14:01:10 +04:00
i2c_adap - > class = I2C_CLASS_TV_DIGITAL , i2c_adap - > algo = algo ;
2006-07-30 00:33:44 +04:00
i2c_adap - > algo_data = NULL ;
i2c_set_adapdata ( i2c_adap , mst ) ;
if ( i2c_add_adapter ( i2c_adap ) < 0 )
return - ENODEV ;
return 0 ;
}
2009-08-17 14:01:10 +04:00
int dibx000_init_i2c_master ( struct dibx000_i2c_master * mst , u16 device_rev ,
struct i2c_adapter * i2c_adap , u8 i2c_addr )
2006-07-30 00:33:44 +04:00
{
u8 tx [ 4 ] ;
2009-08-17 14:01:10 +04:00
struct i2c_msg m = { . addr = i2c_addr > > 1 , . buf = tx , . len = 4 } ;
2006-07-30 00:33:44 +04:00
mst - > device_rev = device_rev ;
2009-08-17 14:01:10 +04:00
mst - > i2c_adap = i2c_adap ;
mst - > i2c_addr = i2c_addr > > 1 ;
2006-07-30 00:33:44 +04:00
2009-08-17 14:01:10 +04:00
if ( device_rev = = DIB7000P | | device_rev = = DIB8000 )
2006-07-30 00:33:44 +04:00
mst - > base_reg = 1024 ;
else
mst - > base_reg = 768 ;
2009-08-17 14:01:10 +04:00
if ( i2c_adapter_init
( & mst - > gated_tuner_i2c_adap , & dibx000_i2c_gated_tuner_algo ,
" DiBX000 tuner I2C bus " , mst ) ! = 0 )
printk ( KERN_ERR
" DiBX000: could not initialize the tuner i2c_adapter \n " ) ;
2006-07-30 00:33:44 +04:00
/* initialize the i2c-master by closing the gate */
dibx000_i2c_gate_ctrl ( mst , tx , 0 , 0 ) ;
return i2c_transfer ( i2c_adap , & m , 1 ) = = 1 ;
}
2009-08-17 14:01:10 +04:00
2006-07-30 00:33:44 +04:00
EXPORT_SYMBOL ( dibx000_init_i2c_master ) ;
void dibx000_exit_i2c_master ( struct dibx000_i2c_master * mst )
{
i2c_del_adapter ( & mst - > gated_tuner_i2c_adap ) ;
}
EXPORT_SYMBOL ( dibx000_exit_i2c_master ) ;
2006-08-06 15:49:09 +04:00
2009-12-04 19:27:57 +03:00
u32 systime ( )
{
struct timespec t ;
t = current_kernel_time ( ) ;
return ( t . tv_sec * 10000 ) + ( t . tv_nsec / 100000 ) ;
}
EXPORT_SYMBOL ( systime ) ;
2006-08-06 15:49:09 +04:00
MODULE_AUTHOR ( " Patrick Boettcher <pboettcher@dibcom.fr> " ) ;
MODULE_DESCRIPTION ( " Common function the DiBcom demodulator family " ) ;
MODULE_LICENSE ( " GPL " ) ;