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
} ;
2011-01-03 21:39:35 +03:00
2006-07-30 00:33:44 +04:00
return i2c_transfer ( mst - > i2c_adap , & msg , 1 ) ! = 1 ? - EREMOTEIO : 0 ;
}
2011-01-03 21:39:35 +03:00
static u16 dibx000_read_word ( struct dibx000_i2c_master * mst , u16 reg )
{
u8 wb [ 2 ] = { reg > > 8 , reg & 0xff } ;
u8 rb [ 2 ] ;
struct i2c_msg msg [ 2 ] = {
{ . addr = mst - > i2c_addr , . flags = 0 , . buf = wb , . len = 2 } ,
{ . addr = mst - > i2c_addr , . flags = I2C_M_RD , . buf = rb , . len = 2 } ,
} ;
if ( i2c_transfer ( mst - > i2c_adap , msg , 2 ) ! = 2 )
dprintk ( " i2c read error on %d " , reg ) ;
return ( rb [ 0 ] < < 8 ) | rb [ 1 ] ;
}
static int dibx000_is_i2c_done ( struct dibx000_i2c_master * mst )
{
int i = 100 ; // max_i2c_polls;
u16 status ;
while ( ( ( status = dibx000_read_word ( mst , mst - > base_reg + 2 ) ) & 0x0100 ) = = 0 & & - - i > 0 ) ;
/* i2c timed out */
if ( i = = 0 )
return - EREMOTEIO ;
/* no acknowledge */
if ( ( status & 0x0080 ) = = 0 )
return - EREMOTEIO ;
return 0 ;
}
static int dibx000_master_i2c_write ( struct dibx000_i2c_master * mst , struct i2c_msg * msg , u8 stop )
{
u16 data ;
u16 da ;
u16 i ;
u16 txlen = msg - > len , len ;
const u8 * b = msg - > buf ;
while ( txlen ) {
dibx000_read_word ( mst , mst - > base_reg + 2 ) ; // reset fifo ptr
len = txlen > 8 ? 8 : txlen ;
for ( i = 0 ; i < len ; i + = 2 ) {
data = * b + + < < 8 ;
if ( i + 1 < len )
data | = * b + + ;
dibx000_write_word ( mst , mst - > base_reg , data ) ;
}
da = ( ( ( u8 ) ( msg - > addr ) ) < < 9 ) | // addr
( 1 < < 8 ) | // master
( 1 < < 7 ) | // rq
( 0 < < 6 ) | // stop
( 0 < < 5 ) | // start
( ( len & 0x7 ) < < 2 ) | // nb 8 bytes == 0 here
( 0 < < 1 ) | // rw
( 0 < < 0 ) ; // irqen
if ( txlen = = msg - > len )
da | = 1 < < 5 ; /* start */
if ( txlen - len = = 0 & & stop )
da | = 1 < < 6 ; /* stop */
dibx000_write_word ( mst , mst - > base_reg + 1 , da ) ;
if ( dibx000_is_i2c_done ( mst ) ! = 0 )
return - EREMOTEIO ;
txlen - = len ;
}
return 0 ;
}
static int dibx000_master_i2c_read ( struct dibx000_i2c_master * mst , struct i2c_msg * msg )
{
u16 da ;
u8 * b = msg - > buf ;
u16 rxlen = msg - > len , len ;
while ( rxlen ) {
len = rxlen > 8 ? 8 : rxlen ;
da = ( ( ( u8 ) ( msg - > addr ) ) < < 9 ) | // addr
( 1 < < 8 ) | // master
( 1 < < 7 ) | // rq
( 0 < < 6 ) | // stop
( 0 < < 5 ) | // start
( ( len & 0x7 ) < < 2 ) | // nb
( 1 < < 1 ) | // rw
( 0 < < 0 ) ; // irqen
if ( rxlen = = msg - > len )
da | = 1 < < 5 ; /* start */
if ( rxlen - len = = 0 )
da | = 1 < < 6 ; /* stop */
dibx000_write_word ( mst , mst - > base_reg + 1 , da ) ;
if ( dibx000_is_i2c_done ( mst ) ! = 0 )
return - EREMOTEIO ;
rxlen - = len ;
while ( len ) {
da = dibx000_read_word ( mst , mst - > base_reg ) ;
* b + + = ( da > > 8 ) & 0xff ;
len - - ;
if ( len > = 1 ) {
* b + + = da & 0xff ;
len - - ;
}
}
}
return 0 ;
}
int dibx000_i2c_set_speed ( struct i2c_adapter * i2c_adap , u16 speed )
{
struct dibx000_i2c_master * mst = i2c_get_adapdata ( i2c_adap ) ;
if ( mst - > device_rev < DIB7000MC & & speed < 235 )
speed = 235 ;
return dibx000_write_word ( mst , mst - > base_reg + 3 , ( u16 ) ( 60000 / speed ) ) ;
}
EXPORT_SYMBOL ( dibx000_i2c_set_speed ) ;
static u32 dibx000_i2c_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C ;
}
2006-07-30 00:33:44 +04:00
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 ;
}
2011-01-03 21:39:35 +03:00
static int dibx000_i2c_master_xfer_gpio12 ( struct i2c_adapter * i2c_adap , struct i2c_msg msg [ ] , int num )
{
struct dibx000_i2c_master * mst = i2c_get_adapdata ( i2c_adap ) ;
int msg_index ;
int ret = 0 ;
dibx000_i2c_select_interface ( mst , DIBX000_I2C_INTERFACE_GPIO_1_2 ) ;
for ( msg_index = 0 ; msg_index < num ; msg_index + + ) {
if ( msg [ msg_index ] . flags & I2C_M_RD )
{
ret = dibx000_master_i2c_read ( mst , & msg [ msg_index ] ) ;
if ( ret ! = 0 )
return 0 ;
}
else
{
ret = dibx000_master_i2c_write ( mst , & msg [ msg_index ] , 1 ) ;
if ( ret ! = 0 )
return 0 ;
}
}
return num ;
}
static int dibx000_i2c_master_xfer_gpio34 ( struct i2c_adapter * i2c_adap , struct i2c_msg msg [ ] , int num )
{
struct dibx000_i2c_master * mst = i2c_get_adapdata ( i2c_adap ) ;
int msg_index ;
int ret = 0 ;
dibx000_i2c_select_interface ( mst , DIBX000_I2C_INTERFACE_GPIO_3_4 ) ;
for ( msg_index = 0 ; msg_index < num ; msg_index + + ) {
if ( msg [ msg_index ] . flags & I2C_M_RD )
{
ret = dibx000_master_i2c_read ( mst , & msg [ msg_index ] ) ;
if ( ret ! = 0 )
return 0 ;
}
else
{
ret = dibx000_master_i2c_write ( mst , & msg [ msg_index ] , 1 ) ;
if ( ret ! = 0 )
return 0 ;
}
}
return num ;
}
static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = {
. master_xfer = dibx000_i2c_master_xfer_gpio12 ,
. functionality = dibx000_i2c_func ,
} ;
static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = {
. master_xfer = dibx000_i2c_master_xfer_gpio34 ,
. functionality = dibx000_i2c_func ,
} ;
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 ;
}
2011-01-03 21:39:35 +03:00
static int dibx000_i2c_gated_gpio67_xfer ( struct i2c_adapter * i2c_adap ,
struct i2c_msg msg [ ] , int num )
2006-07-30 00:33:44 +04:00
{
2011-01-03 21:39:35 +03:00
struct dibx000_i2c_master * mst = i2c_get_adapdata ( i2c_adap ) ;
struct i2c_msg m [ 2 + num ] ;
u8 tx_open [ 4 ] , tx_close [ 4 ] ;
memset ( m , 0 , sizeof ( struct i2c_msg ) * ( 2 + num ) ) ;
dibx000_i2c_select_interface ( mst , DIBX000_I2C_INTERFACE_GPIO_6_7 ) ;
dibx000_i2c_gate_ctrl ( mst , tx_open , msg [ 0 ] . addr , 1 ) ;
m [ 0 ] . addr = mst - > i2c_addr ;
m [ 0 ] . buf = tx_open ;
m [ 0 ] . len = 4 ;
memcpy ( & m [ 1 ] , msg , sizeof ( struct i2c_msg ) * num ) ;
dibx000_i2c_gate_ctrl ( mst , tx_close , 0 , 0 ) ;
m [ num + 1 ] . addr = mst - > i2c_addr ;
m [ num + 1 ] . buf = tx_close ;
m [ num + 1 ] . len = 4 ;
return i2c_transfer ( mst - > i2c_adap , m , 2 + num ) = = 2 + num ? num : - EIO ;
2006-07-30 00:33:44 +04:00
}
2011-01-03 21:39:35 +03:00
static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
. master_xfer = dibx000_i2c_gated_gpio67_xfer ,
. functionality = dibx000_i2c_func ,
} ;
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 ,
2011-01-03 21:39:35 +03:00
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 ;
2011-01-03 21:39:35 +03:00
case DIBX000_I2C_INTERFACE_GPIO_1_2 :
if ( ! gating )
i2c = & mst - > master_i2c_adap_gpio12 ;
break ;
case DIBX000_I2C_INTERFACE_GPIO_3_4 :
if ( ! gating )
i2c = & mst - > master_i2c_adap_gpio34 ;
break ;
case DIBX000_I2C_INTERFACE_GPIO_6_7 :
if ( gating )
i2c = & mst - > master_i2c_adap_gpio67 ;
break ;
2009-08-17 14:01:10 +04:00
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 ,
2011-01-03 21:39:35 +03:00
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 ) ) ;
2010-11-05 13:35:35 +03:00
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 ,
2011-01-03 21:39:35 +03:00
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 ;
2011-01-03 21:39:35 +03:00
mst - > gated_tuner_i2c_adap . dev . parent = mst - > i2c_adap - > dev . parent ;
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 " ) ;
mst - > master_i2c_adap_gpio12 . dev . parent = mst - > i2c_adap - > dev . parent ;
if ( i2c_adapter_init
( & mst - > master_i2c_adap_gpio12 , & dibx000_i2c_master_gpio12_xfer_algo ,
" DiBX000 master GPIO12 I2C bus " , mst ) ! = 0 )
printk ( KERN_ERR
" DiBX000: could not initialize the master i2c_adapter \n " ) ;
mst - > master_i2c_adap_gpio34 . dev . parent = mst - > i2c_adap - > dev . parent ;
if ( i2c_adapter_init
( & mst - > master_i2c_adap_gpio34 , & dibx000_i2c_master_gpio34_xfer_algo ,
" DiBX000 master GPIO34 I2C bus " , mst ) ! = 0 )
printk ( KERN_ERR
" DiBX000: could not initialize the master i2c_adapter \n " ) ;
mst - > master_i2c_adap_gpio67 . dev . parent = mst - > i2c_adap - > dev . parent ;
2009-08-17 14:01:10 +04:00
if ( i2c_adapter_init
2011-01-03 21:39:35 +03:00
( & mst - > master_i2c_adap_gpio67 , & dibx000_i2c_gated_gpio67_algo ,
" DiBX000 master GPIO67 I2C bus " , mst ) ! = 0 )
2009-08-17 14:01:10 +04:00
printk ( KERN_ERR
2011-01-03 21:39:35 +03:00
" DiBX000: could not initialize the master 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 ) ;
2011-01-03 21:39:35 +03:00
i2c_del_adapter ( & mst - > master_i2c_adap_gpio12 ) ;
i2c_del_adapter ( & mst - > master_i2c_adap_gpio34 ) ;
i2c_del_adapter ( & mst - > master_i2c_adap_gpio67 ) ;
2006-07-30 00:33:44 +04:00
}
EXPORT_SYMBOL ( dibx000_exit_i2c_master ) ;
2006-08-06 15:49:09 +04:00
2009-12-04 19:27:57 +03:00
2010-02-15 05:39:32 +03:00
u32 systime ( void )
2009-12-04 19:27:57 +03:00
{
2011-01-03 21:39:35 +03:00
struct timespec t ;
2009-12-04 19:27:57 +03:00
2011-01-03 21:39:35 +03:00
t = current_kernel_time ( ) ;
return ( t . tv_sec * 10000 ) + ( t . tv_nsec / 100000 ) ;
2009-12-04 19:27:57 +03:00
}
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 " ) ;