2007-03-11 20:44:05 -03:00
/*
* Driver for the Conexant CX23885 PCIe bridge
*
2008-09-03 17:12:12 -03:00
* Copyright ( c ) 2006 Steven Toth < stoth @ linuxtv . org >
2007-03-11 20:44:05 -03:00
*
* 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 .
*/
2016-11-13 09:46:11 -02:00
# include "cx23885.h"
2007-03-11 20:44:05 -03:00
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <asm/io.h>
# include <media/v4l2-common.h>
2008-01-12 11:36:36 -03:00
static unsigned int i2c_debug ;
2007-03-11 20:44:05 -03:00
module_param ( i2c_debug , int , 0644 ) ;
2007-03-20 23:00:18 -03:00
MODULE_PARM_DESC ( i2c_debug , " enable debug messages [i2c] " ) ;
2007-03-11 20:44:05 -03:00
2008-04-22 14:41:48 -03:00
static unsigned int i2c_scan ;
2007-03-11 20:44:05 -03:00
module_param ( i2c_scan , int , 0444 ) ;
2007-03-20 23:00:18 -03:00
MODULE_PARM_DESC ( i2c_scan , " scan i2c bus at insmod time " ) ;
2007-03-11 20:44:05 -03:00
2008-01-12 11:36:36 -03:00
# define dprintk(level, fmt, arg...)\
do { if ( i2c_debug > = level ) \
2016-11-13 09:46:11 -02:00
printk ( KERN_DEBUG pr_fmt ( " %s: i2c: " fmt ) , \
__func__ , # # arg ) ; \
2007-12-15 03:31:09 -03:00
} while ( 0 )
2007-03-11 20:44:05 -03:00
# define I2C_WAIT_DELAY 32
# define I2C_WAIT_RETRY 64
# define I2C_EXTEND (1 << 3)
# define I2C_NOSTOP (1 << 4)
static inline int i2c_slave_did_ack ( struct i2c_adapter * i2c_adap )
{
struct cx23885_i2c * bus = i2c_adap - > algo_data ;
struct cx23885_dev * dev = bus - > dev ;
return cx_read ( bus - > reg_stat ) & 0x01 ;
}
static inline int i2c_is_busy ( struct i2c_adapter * i2c_adap )
{
struct cx23885_i2c * bus = i2c_adap - > algo_data ;
struct cx23885_dev * dev = bus - > dev ;
return cx_read ( bus - > reg_stat ) & 0x02 ? 1 : 0 ;
}
static int i2c_wait_done ( struct i2c_adapter * i2c_adap )
{
int count ;
for ( count = 0 ; count < I2C_WAIT_RETRY ; count + + ) {
if ( ! i2c_is_busy ( i2c_adap ) )
break ;
udelay ( I2C_WAIT_DELAY ) ;
}
if ( I2C_WAIT_RETRY = = count )
return 0 ;
return 1 ;
}
2007-03-20 23:00:18 -03:00
static int i2c_sendbytes ( struct i2c_adapter * i2c_adap ,
2007-12-15 03:31:09 -03:00
const struct i2c_msg * msg , int joined_rlen )
2007-03-11 20:44:05 -03:00
{
struct cx23885_i2c * bus = i2c_adap - > algo_data ;
struct cx23885_dev * dev = bus - > dev ;
u32 wdata , addr , ctrl ;
int retval , cnt ;
2007-12-15 03:31:09 -03:00
if ( joined_rlen )
2008-04-08 23:20:00 -03:00
dprintk ( 1 , " %s(msg->wlen=%d, nextmsg->rlen=%d) \n " , __func__ ,
2007-12-15 03:31:09 -03:00
msg - > len , joined_rlen ) ;
else
2008-04-08 23:20:00 -03:00
dprintk ( 1 , " %s(msg->len=%d) \n " , __func__ , msg - > len ) ;
2007-09-20 01:44:27 -03:00
2007-03-11 20:44:05 -03:00
/* Deal with i2c probe functions with zero payload */
if ( msg - > len = = 0 ) {
cx_write ( bus - > reg_addr , msg - > addr < < 25 ) ;
cx_write ( bus - > reg_ctrl , bus - > i2c_period | ( 1 < < 2 ) ) ;
if ( ! i2c_wait_done ( i2c_adap ) )
return - EIO ;
if ( ! i2c_slave_did_ack ( i2c_adap ) )
2010-07-18 16:48:47 -03:00
return - ENXIO ;
2007-03-11 20:44:05 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( 1 , " %s() returns 0 \n " , __func__ ) ;
2007-03-11 20:44:05 -03:00
return 0 ;
}
/* dev, reg + first byte */
addr = ( msg - > addr < < 25 ) | msg - > buf [ 0 ] ;
wdata = msg - > buf [ 0 ] ;
ctrl = bus - > i2c_period | ( 1 < < 12 ) | ( 1 < < 2 ) ;
if ( msg - > len > 1 )
ctrl | = I2C_NOSTOP | I2C_EXTEND ;
2007-12-15 03:31:09 -03:00
else if ( joined_rlen )
ctrl | = I2C_NOSTOP ;
2007-03-11 20:44:05 -03:00
cx_write ( bus - > reg_addr , addr ) ;
cx_write ( bus - > reg_wdata , wdata ) ;
cx_write ( bus - > reg_ctrl , ctrl ) ;
2010-07-18 17:05:17 -03:00
if ( ! i2c_wait_done ( i2c_adap ) )
2007-03-11 20:44:05 -03:00
goto eio ;
if ( i2c_debug ) {
2016-10-14 06:50:56 -03:00
printk ( KERN_DEBUG " <W %02x %02x " , msg - > addr < < 1 , msg - > buf [ 0 ] ) ;
2007-03-11 20:44:05 -03:00
if ( ! ( ctrl & I2C_NOSTOP ) )
2016-11-13 09:46:11 -02:00
pr_cont ( " > \n " ) ;
2007-03-11 20:44:05 -03:00
}
2008-10-16 20:18:44 -03:00
for ( cnt = 1 ; cnt < msg - > len ; cnt + + ) {
2007-03-11 20:44:05 -03:00
/* following bytes */
wdata = msg - > buf [ cnt ] ;
ctrl = bus - > i2c_period | ( 1 < < 12 ) | ( 1 < < 2 ) ;
2007-09-20 01:44:27 -03:00
if ( cnt < msg - > len - 1 )
2007-03-11 20:44:05 -03:00
ctrl | = I2C_NOSTOP | I2C_EXTEND ;
2007-12-15 03:31:09 -03:00
else if ( joined_rlen )
ctrl | = I2C_NOSTOP ;
2007-03-11 20:44:05 -03:00
cx_write ( bus - > reg_addr , addr ) ;
cx_write ( bus - > reg_wdata , wdata ) ;
cx_write ( bus - > reg_ctrl , ctrl ) ;
2010-07-18 17:05:17 -03:00
if ( ! i2c_wait_done ( i2c_adap ) )
2007-03-11 20:44:05 -03:00
goto eio ;
if ( i2c_debug ) {
2016-11-13 09:46:11 -02:00
pr_cont ( " %02x " , msg - > buf [ cnt ] ) ;
2007-03-11 20:44:05 -03:00
if ( ! ( ctrl & I2C_NOSTOP ) )
2016-11-13 09:46:11 -02:00
pr_cont ( " > \n " ) ;
2007-03-11 20:44:05 -03:00
}
}
return msg - > len ;
eio :
retval = - EIO ;
2007-12-15 03:31:09 -03:00
if ( i2c_debug )
2016-11-13 09:46:11 -02:00
pr_err ( " ERR: %d \n " , retval ) ;
2007-03-11 20:44:05 -03:00
return retval ;
}
2007-03-20 23:00:18 -03:00
static int i2c_readbytes ( struct i2c_adapter * i2c_adap ,
2007-12-15 03:31:09 -03:00
const struct i2c_msg * msg , int joined )
2007-03-11 20:44:05 -03:00
{
struct cx23885_i2c * bus = i2c_adap - > algo_data ;
struct cx23885_dev * dev = bus - > dev ;
u32 ctrl , cnt ;
int retval ;
2007-12-15 03:31:09 -03:00
if ( i2c_debug & & ! joined )
2008-04-08 23:20:00 -03:00
dprintk ( 1 , " %s(msg->len=%d) \n " , __func__ , msg - > len ) ;
2007-03-11 20:44:05 -03:00
/* Deal with i2c probe functions with zero payload */
if ( msg - > len = = 0 ) {
cx_write ( bus - > reg_addr , msg - > addr < < 25 ) ;
cx_write ( bus - > reg_ctrl , bus - > i2c_period | ( 1 < < 2 ) | 1 ) ;
if ( ! i2c_wait_done ( i2c_adap ) )
return - EIO ;
if ( ! i2c_slave_did_ack ( i2c_adap ) )
2010-07-18 16:48:47 -03:00
return - ENXIO ;
2007-03-11 20:44:05 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( 1 , " %s() returns 0 \n " , __func__ ) ;
2007-03-11 20:44:05 -03:00
return 0 ;
}
2007-12-15 03:31:09 -03:00
if ( i2c_debug ) {
if ( joined )
2008-10-16 20:18:44 -03:00
dprintk ( 1 , " R " ) ;
2007-12-15 03:31:09 -03:00
else
2008-10-16 20:18:44 -03:00
dprintk ( 1 , " <R %02x " , ( msg - > addr < < 1 ) + 1 ) ;
2007-12-15 03:31:09 -03:00
}
2007-09-20 01:44:27 -03:00
2008-10-16 20:18:44 -03:00
for ( cnt = 0 ; cnt < msg - > len ; cnt + + ) {
2007-03-11 20:44:05 -03:00
ctrl = bus - > i2c_period | ( 1 < < 12 ) | ( 1 < < 2 ) | 1 ;
2007-09-20 01:44:27 -03:00
if ( cnt < msg - > len - 1 )
2007-03-11 20:44:05 -03:00
ctrl | = I2C_NOSTOP | I2C_EXTEND ;
cx_write ( bus - > reg_addr , msg - > addr < < 25 ) ;
cx_write ( bus - > reg_ctrl , ctrl ) ;
2010-07-18 17:05:17 -03:00
if ( ! i2c_wait_done ( i2c_adap ) )
2007-03-11 20:44:05 -03:00
goto eio ;
msg - > buf [ cnt ] = cx_read ( bus - > reg_rdata ) & 0xff ;
if ( i2c_debug ) {
2008-10-16 20:18:44 -03:00
dprintk ( 1 , " %02x " , msg - > buf [ cnt ] ) ;
2007-03-11 20:44:05 -03:00
if ( ! ( ctrl & I2C_NOSTOP ) )
2008-10-16 20:18:44 -03:00
dprintk ( 1 , " > \n " ) ;
2007-03-11 20:44:05 -03:00
}
}
return msg - > len ;
eio :
retval = - EIO ;
2007-12-15 03:31:09 -03:00
if ( i2c_debug )
2016-11-13 09:46:11 -02:00
pr_err ( " ERR: %d \n " , retval ) ;
2007-03-11 20:44:05 -03:00
return retval ;
}
2007-03-20 23:00:18 -03:00
static int i2c_xfer ( struct i2c_adapter * i2c_adap ,
struct i2c_msg * msgs , int num )
2007-03-11 20:44:05 -03:00
{
int i , retval = 0 ;
2008-04-08 23:20:00 -03:00
dprintk ( 1 , " %s(num = %d) \n " , __func__ , num ) ;
2007-03-11 20:44:05 -03:00
for ( i = 0 ; i < num ; i + + ) {
2007-03-20 23:00:18 -03:00
dprintk ( 1 , " %s(num = %d) addr = 0x%02x len = 0x%x \n " ,
2008-04-08 23:20:00 -03:00
__func__ , num , msgs [ i ] . addr , msgs [ i ] . len ) ;
2007-03-11 20:44:05 -03:00
if ( msgs [ i ] . flags & I2C_M_RD ) {
/* read */
2007-12-15 03:31:09 -03:00
retval = i2c_readbytes ( i2c_adap , & msgs [ i ] , 0 ) ;
} else if ( i + 1 < num & & ( msgs [ i + 1 ] . flags & I2C_M_RD ) & &
msgs [ i ] . addr = = msgs [ i + 1 ] . addr ) {
/* write then read from same address */
retval = i2c_sendbytes ( i2c_adap , & msgs [ i ] ,
msgs [ i + 1 ] . len ) ;
2007-03-11 20:44:05 -03:00
if ( retval < 0 )
goto err ;
2007-12-15 03:31:09 -03:00
i + + ;
retval = i2c_readbytes ( i2c_adap , & msgs [ i ] , 1 ) ;
2007-03-11 20:44:05 -03:00
} else {
/* write */
2007-12-15 03:31:09 -03:00
retval = i2c_sendbytes ( i2c_adap , & msgs [ i ] , 0 ) ;
2007-03-11 20:44:05 -03:00
}
2007-12-15 03:31:09 -03:00
if ( retval < 0 )
goto err ;
2007-03-11 20:44:05 -03:00
}
return num ;
err :
return retval ;
}
static u32 cx23885_functionality ( struct i2c_adapter * adap )
{
2007-03-19 18:03:03 -03:00
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C ;
2007-03-11 20:44:05 -03:00
}
2016-08-29 10:12:01 -03:00
static const struct i2c_algorithm cx23885_i2c_algo_template = {
2007-03-11 20:44:05 -03:00
. master_xfer = i2c_xfer ,
. functionality = cx23885_functionality ,
} ;
/* ----------------------------------------------------------------------- */
static struct i2c_adapter cx23885_i2c_adap_template = {
. name = " cx23885 " ,
. owner = THIS_MODULE ,
. algo = & cx23885_i2c_algo_template ,
} ;
static struct i2c_client cx23885_i2c_client_template = {
. name = " cx23885 internal " ,
} ;
static char * i2c_devs [ 128 ] = {
2008-10-16 20:18:44 -03:00
[ 0x10 > > 1 ] = " tda10048 " ,
[ 0x12 > > 1 ] = " dib7000pc " ,
[ 0x1c > > 1 ] = " lgdt3303 " ,
2015-11-30 18:08:10 -02:00
[ 0x80 > > 1 ] = " cs3308 " ,
[ 0x82 > > 1 ] = " cs3308 " ,
2008-10-16 20:18:44 -03:00
[ 0x86 > > 1 ] = " tda9887 " ,
[ 0x32 > > 1 ] = " cx24227 " ,
[ 0x88 > > 1 ] = " cx25837 " ,
[ 0x84 > > 1 ] = " tda8295 " ,
2011-10-10 11:09:55 -03:00
[ 0x98 > > 1 ] = " flatiron " ,
2008-10-16 20:18:44 -03:00
[ 0xa0 > > 1 ] = " eeprom " ,
[ 0xc0 > > 1 ] = " tuner/mt2131/tda8275 " ,
2008-04-22 15:38:26 -03:00
[ 0xc2 > > 1 ] = " tuner/mt2131/tda8275/xc5000/xc3028 " ,
2008-10-16 20:18:44 -03:00
[ 0xc8 > > 1 ] = " tuner/xc3028L " ,
2007-03-11 20:44:05 -03:00
} ;
static void do_i2c_scan ( char * name , struct i2c_client * c )
{
unsigned char buf ;
2007-03-20 23:00:18 -03:00
int i , rc ;
2007-03-11 20:44:05 -03:00
for ( i = 0 ; i < 128 ; i + + ) {
c - > addr = i ;
2007-03-20 23:00:18 -03:00
rc = i2c_master_recv ( c , & buf , 0 ) ;
2007-03-11 20:44:05 -03:00
if ( rc < 0 )
continue ;
2016-11-13 09:46:11 -02:00
pr_info ( " %s: i2c scan: found device @ 0x%04x [%s] \n " ,
2014-12-11 15:44:51 -03:00
name , i , i2c_devs [ i ] ? i2c_devs [ i ] : " ??? " ) ;
2007-03-11 20:44:05 -03:00
}
}
2011-11-09 13:27:53 -03:00
/* init + register i2c adapter */
2007-03-11 20:44:05 -03:00
int cx23885_i2c_register ( struct cx23885_i2c * bus )
{
struct cx23885_dev * dev = bus - > dev ;
2008-04-08 23:20:00 -03:00
dprintk ( 1 , " %s(bus = %d) \n " , __func__ , bus - > nr ) ;
2007-03-11 20:44:05 -03:00
2012-06-27 12:52:52 -03:00
bus - > i2c_adap = cx23885_i2c_adap_template ;
bus - > i2c_client = cx23885_i2c_client_template ;
2007-03-11 20:44:05 -03:00
bus - > i2c_adap . dev . parent = & dev - > pci - > dev ;
2007-03-20 23:00:18 -03:00
strlcpy ( bus - > i2c_adap . name , bus - > dev - > name ,
sizeof ( bus - > i2c_adap . name ) ) ;
2007-09-04 21:32:41 -03:00
2007-03-11 20:44:05 -03:00
bus - > i2c_adap . algo_data = bus ;
2009-03-13 08:02:43 -03:00
i2c_set_adapdata ( & bus - > i2c_adap , & dev - > v4l2_dev ) ;
2007-03-11 20:44:05 -03:00
i2c_add_adapter ( & bus - > i2c_adap ) ;
bus - > i2c_client . adapter = & bus - > i2c_adap ;
if ( 0 = = bus - > i2c_rc ) {
2008-10-16 20:18:44 -03:00
dprintk ( 1 , " %s: i2c bus %d registered \n " , dev - > name , bus - > nr ) ;
2009-03-29 06:53:29 -03:00
if ( i2c_scan ) {
2016-11-13 09:46:11 -02:00
pr_info ( " %s: scan bus %d: \n " ,
2009-03-29 06:53:29 -03:00
dev - > name , bus - > nr ) ;
2007-03-11 20:44:05 -03:00
do_i2c_scan ( dev - > name , & bus - > i2c_client ) ;
2009-03-29 06:53:29 -03:00
}
2007-03-11 20:44:05 -03:00
} else
2016-11-13 09:46:11 -02:00
pr_warn ( " %s: i2c bus %d register FAILED \n " ,
2008-10-16 20:18:44 -03:00
dev - > name , bus - > nr ) ;
2007-03-11 20:44:05 -03:00
2009-05-13 16:48:50 -03:00
/* Instantiate the IR receiver device, if present */
if ( 0 = = bus - > i2c_rc ) {
struct i2c_board_info info ;
const unsigned short addr_list [ ] = {
0x6b , I2C_CLIENT_END
} ;
memset ( & info , 0 , sizeof ( struct i2c_board_info ) ) ;
strlcpy ( info . type , " ir_video " , I2C_NAME_SIZE ) ;
2010-08-11 18:20:57 +02:00
/* Use quick read command for probe, some IR chips don't
* support writes */
i2c_new_probed_device ( & bus - > i2c_adap , & info , addr_list ,
i2c_probe_func_quick_read ) ;
2009-05-13 16:48:50 -03:00
}
2007-03-11 20:44:05 -03:00
return bus - > i2c_rc ;
}
int cx23885_i2c_unregister ( struct cx23885_i2c * bus )
{
i2c_del_adapter ( & bus - > i2c_adap ) ;
return 0 ;
}
2008-01-13 23:44:47 -03:00
void cx23885_av_clk ( struct cx23885_dev * dev , int enable )
{
/* write 0 to bus 2 addr 0x144 via i2x_xfer() */
char buffer [ 3 ] ;
struct i2c_msg msg ;
dprintk ( 1 , " %s(enabled = %d) \n " , __func__ , enable ) ;
/* Register 0x144 */
buffer [ 0 ] = 0x01 ;
buffer [ 1 ] = 0x44 ;
if ( enable = = 1 )
buffer [ 2 ] = 0x05 ;
else
buffer [ 2 ] = 0x00 ;
msg . addr = 0x44 ;
msg . flags = I2C_M_TEN ;
msg . len = 3 ;
msg . buf = buffer ;
i2c_xfer ( & dev - > i2c_bus [ 2 ] . i2c_adap , & msg , 1 ) ;
}