2009-09-14 16:42:41 +04:00
/*
2010-10-20 13:35:54 +04:00
* tm6000 - i2c . c - driver for TM5600 / TM6000 / TM6010 USB video capture devices
*
* Copyright ( C ) 2006 - 2007 Mauro Carvalho Chehab < mchehab @ infradead . org >
*
* Copyright ( C ) 2007 Michel Ludwig < michel . ludwig @ gmail . com >
* - Fix SMBus Read Byte command
*
* 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 version 2
*
* 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 .
2009-09-14 16:42:41 +04:00
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/usb.h>
# include <linux/i2c.h>
# include "tm6000.h"
# include "tm6000-regs.h"
# include <media/v4l2-common.h>
# include <media/tuner.h>
# include "tuner-xc2028.h"
/* ----------------------------------------------------------- */
2010-10-20 13:34:40 +04:00
static unsigned int i2c_debug ;
2009-09-14 16:42:41 +04:00
module_param ( i2c_debug , int , 0644 ) ;
MODULE_PARM_DESC ( i2c_debug , " enable debug messages [i2c] " ) ;
2010-05-29 20:52:46 +04:00
# define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
2009-09-14 16:42:41 +04:00
printk ( KERN_DEBUG " %s at %s: " fmt , \
2011-06-03 04:33:32 +04:00
dev - > name , __func__ , # # args ) ; } while ( 0 )
2009-09-14 16:42:41 +04:00
2010-02-22 20:35:05 +03:00
static int tm6000_i2c_send_regs ( struct tm6000_core * dev , unsigned char addr ,
__u8 reg , char * buf , int len )
{
2010-04-28 05:32:43 +04:00
int rc ;
unsigned int i2c_packet_limit = 16 ;
if ( dev - > dev_type = = TM6010 )
2011-12-16 21:15:07 +04:00
i2c_packet_limit = 80 ;
2010-04-28 05:32:43 +04:00
if ( ! buf )
return - 1 ;
if ( len < 1 | | len > i2c_packet_limit ) {
printk ( KERN_ERR " Incorrect length of i2c packet = %d, limit set to %d \n " ,
len , i2c_packet_limit ) ;
return - 1 ;
}
/* capture mutex */
rc = tm6000_read_write_usb ( dev , USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_DEVICE , REQ_16_SET_GET_I2C_WR1_RDN ,
addr | reg < < 8 , 0 , buf , len ) ;
if ( rc < 0 ) {
/* release mutex */
return rc ;
}
/* release mutex */
return rc ;
2010-02-22 20:35:05 +03:00
}
/* Generic read - doesn't work fine with 16bit registers */
static int tm6000_i2c_recv_regs ( struct tm6000_core * dev , unsigned char addr ,
__u8 reg , char * buf , int len )
{
int rc ;
2010-02-22 20:35:06 +03:00
u8 b [ 2 ] ;
2010-04-28 05:32:43 +04:00
unsigned int i2c_packet_limit = 16 ;
if ( dev - > dev_type = = TM6010 )
i2c_packet_limit = 64 ;
if ( ! buf )
return - 1 ;
if ( len < 1 | | len > i2c_packet_limit ) {
printk ( KERN_ERR " Incorrect length of i2c packet = %d, limit set to %d \n " ,
len , i2c_packet_limit ) ;
return - 1 ;
}
2010-02-22 20:35:05 +03:00
2010-04-28 05:32:43 +04:00
/* capture mutex */
2010-02-22 20:35:06 +03:00
if ( ( dev - > caps . has_zl10353 ) & & ( dev - > demod_addr < < 1 = = addr ) & & ( reg % 2 = = 0 ) ) {
/*
* Workaround an I2C bug when reading from zl10353
*/
reg - = 1 ;
len + = 1 ;
rc = tm6000_read_write_usb ( dev , USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
REQ_16_SET_GET_I2C_WR1_RDN , addr | reg < < 8 , 0 , b , len ) ;
* buf = b [ 1 ] ;
} else {
rc = tm6000_read_write_usb ( dev , USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
2010-02-22 20:35:05 +03:00
REQ_16_SET_GET_I2C_WR1_RDN , addr | reg < < 8 , 0 , buf , len ) ;
2010-02-22 20:35:06 +03:00
}
2010-02-22 20:35:05 +03:00
2010-04-28 05:32:43 +04:00
/* release mutex */
2010-02-22 20:35:05 +03:00
return rc ;
}
/*
* read from a 16 bit register
* for example xc2028 , xc3028 or xc3028L
*/
static int tm6000_i2c_recv_regs16 ( struct tm6000_core * dev , unsigned char addr ,
__u16 reg , char * buf , int len )
{
2010-04-28 05:32:43 +04:00
int rc ;
unsigned char ureg ;
if ( ! buf | | len ! = 2 )
return - 1 ;
/* capture mutex */
if ( dev - > dev_type = = TM6010 ) {
ureg = reg & 0xFF ;
rc = tm6000_read_write_usb ( dev , USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_DEVICE , REQ_16_SET_GET_I2C_WR1_RDN ,
addr | ( reg & 0xFF00 ) , 0 , & ureg , 1 ) ;
if ( rc < 0 ) {
/* release mutex */
return rc ;
}
rc = tm6000_read_write_usb ( dev , USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE , REQ_35_AFTEK_TUNER_READ ,
reg , 0 , buf , len ) ;
} else {
rc = tm6000_read_write_usb ( dev , USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE , REQ_14_SET_GET_I2C_WR2_RDN ,
addr , reg , buf , len ) ;
}
/* release mutex */
return rc ;
2010-02-22 20:35:05 +03:00
}
2009-09-14 16:42:41 +04:00
static int tm6000_i2c_xfer ( struct i2c_adapter * i2c_adap ,
struct i2c_msg msgs [ ] , int num )
{
struct tm6000_core * dev = i2c_adap - > algo_data ;
int addr , rc , i , byte ;
if ( num < = 0 )
return 0 ;
for ( i = 0 ; i < num ; i + + ) {
2007-11-24 10:34:42 +03:00
addr = ( msgs [ i ] . addr < < 1 ) & 0xff ;
2010-05-29 20:52:46 +04:00
i2c_dprintk ( 2 , " %s %s addr=0x%x len=%d: " ,
2009-09-14 16:42:41 +04:00
( msgs [ i ] . flags & I2C_M_RD ) ? " read " : " write " ,
i = = num - 1 ? " stop " : " nonstop " , addr , msgs [ i ] . len ) ;
2009-09-14 23:37:13 +04:00
if ( msgs [ i ] . flags & I2C_M_RD ) {
2007-11-24 10:34:42 +03:00
/* read request without preceding register selection */
/*
* The TM6000 only supports a read transaction
* immediately after a 1 or 2 byte write to select
* a register . We cannot fulfil this request .
*/
i2c_dprintk ( 2 , " read without preceding write not "
" supported " ) ;
rc = - EOPNOTSUPP ;
goto err ;
} else if ( i + 1 < num & & msgs [ i ] . len < = 2 & &
( msgs [ i + 1 ] . flags & I2C_M_RD ) & &
msgs [ i ] . addr = = msgs [ i + 1 ] . addr ) {
/* 1 or 2 byte write followed by a read */
if ( i2c_debug > = 2 )
for ( byte = 0 ; byte < msgs [ i ] . len ; byte + + )
2011-09-23 16:26:22 +04:00
printk ( KERN_CONT " %02x " , msgs [ i ] . buf [ byte ] ) ;
2007-11-24 10:34:42 +03:00
i2c_dprintk ( 2 , " ; joined to read %s len=%d: " ,
i = = num - 2 ? " stop " : " nonstop " ,
msgs [ i + 1 ] . len ) ;
2010-02-22 20:35:05 +03:00
if ( msgs [ i ] . len = = 2 ) {
rc = tm6000_i2c_recv_regs16 ( dev , addr ,
msgs [ i ] . buf [ 0 ] < < 8 | msgs [ i ] . buf [ 1 ] ,
msgs [ i + 1 ] . buf , msgs [ i + 1 ] . len ) ;
} else {
rc = tm6000_i2c_recv_regs ( dev , addr , msgs [ i ] . buf [ 0 ] ,
msgs [ i + 1 ] . buf , msgs [ i + 1 ] . len ) ;
}
2007-11-23 19:18:56 +03:00
i + + ;
2010-02-06 01:57:04 +03:00
2010-02-21 23:10:36 +03:00
if ( addr = = dev - > tuner_addr < < 1 ) {
2010-04-02 20:52:50 +04:00
tm6000_set_reg ( dev , REQ_50_SET_START , 0 , 0 ) ;
tm6000_set_reg ( dev , REQ_51_SET_STOP , 0 , 0 ) ;
2010-02-06 01:57:04 +03:00
}
2007-11-24 10:34:42 +03:00
if ( i2c_debug > = 2 )
for ( byte = 0 ; byte < msgs [ i ] . len ; byte + + )
2011-09-23 16:26:22 +04:00
printk ( KERN_CONT " %02x " , msgs [ i ] . buf [ byte ] ) ;
2009-09-14 16:42:41 +04:00
} else {
/* write bytes */
2007-11-24 10:34:42 +03:00
if ( i2c_debug > = 2 )
2009-09-14 16:42:41 +04:00
for ( byte = 0 ; byte < msgs [ i ] . len ; byte + + )
2011-09-23 16:26:22 +04:00
printk ( KERN_CONT " %02x " , msgs [ i ] . buf [ byte ] ) ;
2010-02-22 20:35:05 +03:00
rc = tm6000_i2c_send_regs ( dev , addr , msgs [ i ] . buf [ 0 ] ,
2007-11-24 10:34:42 +03:00
msgs [ i ] . buf + 1 , msgs [ i ] . len - 1 ) ;
2009-09-14 16:42:41 +04:00
}
2007-11-24 10:34:42 +03:00
if ( i2c_debug > = 2 )
2011-09-23 16:26:22 +04:00
printk ( KERN_CONT " \n " ) ;
2009-09-14 16:42:41 +04:00
if ( rc < 0 )
goto err ;
}
return num ;
err :
2010-05-29 20:52:46 +04:00
i2c_dprintk ( 2 , " ERROR: %i \n " , rc ) ;
2009-09-14 16:42:41 +04:00
return rc ;
}
2011-04-21 01:43:24 +04:00
static int tm6000_i2c_eeprom ( struct tm6000_core * dev )
2009-09-14 16:42:41 +04:00
{
int i , rc ;
2011-04-21 01:43:24 +04:00
unsigned char * p = dev - > eedata ;
2009-09-14 16:42:41 +04:00
unsigned char bytes [ 17 ] ;
dev - > i2c_client . addr = 0xa0 > > 1 ;
2011-04-21 01:43:24 +04:00
dev - > eedata_size = 0 ;
2009-09-14 16:42:41 +04:00
2007-11-05 21:39:41 +03:00
bytes [ 16 ] = ' \0 ' ;
2011-04-21 01:43:24 +04:00
for ( i = 0 ; i < sizeof ( dev - > eedata ) ; ) {
* p = i ;
rc = tm6000_i2c_recv_regs ( dev , 0xa0 , i , p , 1 ) ;
2007-11-05 21:39:41 +03:00
if ( rc < 1 ) {
2011-04-21 01:43:24 +04:00
if ( p = = dev - > eedata )
2007-11-05 21:39:41 +03:00
goto noeeprom ;
else {
2009-09-14 16:42:41 +04:00
printk ( KERN_WARNING
" %s: i2c eeprom read error (err=%d) \n " ,
dev - > name , rc ) ;
}
2011-04-21 01:43:24 +04:00
return - EINVAL ;
2009-09-14 16:42:41 +04:00
}
2011-04-21 01:43:24 +04:00
dev - > eedata_size + + ;
2009-09-14 16:42:41 +04:00
p + + ;
if ( 0 = = ( i % 16 ) )
printk ( KERN_INFO " %s: i2c eeprom %02x: " , dev - > name , i ) ;
2011-09-23 16:26:22 +04:00
printk ( KERN_CONT " %02x " , dev - > eedata [ i ] ) ;
2011-04-21 01:43:24 +04:00
if ( ( dev - > eedata [ i ] > = ' ' ) & & ( dev - > eedata [ i ] < = ' z ' ) )
bytes [ i % 16 ] = dev - > eedata [ i ] ;
2010-05-29 20:52:46 +04:00
else
bytes [ i % 16 ] = ' . ' ;
2007-11-05 21:39:41 +03:00
i + + ;
if ( 0 = = ( i % 16 ) ) {
bytes [ 16 ] = ' \0 ' ;
2011-09-23 16:26:22 +04:00
printk ( KERN_CONT " %s \n " , bytes ) ;
2009-09-14 16:42:41 +04:00
}
}
2007-11-05 21:39:41 +03:00
if ( 0 ! = ( i % 16 ) ) {
bytes [ i % 16 ] = ' \0 ' ;
for ( i % = 16 ; i < 16 ; i + + )
2011-09-23 16:26:22 +04:00
printk ( KERN_CONT " " ) ;
printk ( KERN_CONT " %s \n " , bytes ) ;
2009-09-14 16:42:41 +04:00
}
2007-11-05 21:39:41 +03:00
2009-09-14 16:42:41 +04:00
return 0 ;
2007-11-05 21:39:41 +03:00
noeeprom :
printk ( KERN_INFO " %s: Huh, no eeprom present (err=%d)? \n " ,
2011-04-21 01:43:24 +04:00
dev - > name , rc ) ;
return - EINVAL ;
2009-09-14 16:42:41 +04:00
}
/* ----------------------------------------------------------- */
/*
* functionality ( )
*/
static u32 functionality ( struct i2c_adapter * adap )
{
return I2C_FUNC_SMBUS_EMUL ;
}
2010-11-07 18:53:44 +03:00
static const struct i2c_algorithm tm6000_algo = {
2009-09-14 16:42:41 +04:00
. master_xfer = tm6000_i2c_xfer ,
. functionality = functionality ,
} ;
/* ----------------------------------------------------------- */
/*
* tm6000_i2c_register ( )
* register i2c bus
*/
int tm6000_i2c_register ( struct tm6000_core * dev )
{
2010-11-07 18:53:44 +03:00
int rc ;
2007-11-05 21:39:41 +03:00
2010-11-07 18:53:44 +03:00
dev - > i2c_adap . owner = THIS_MODULE ;
dev - > i2c_adap . algo = & tm6000_algo ;
2009-09-14 16:42:41 +04:00
dev - > i2c_adap . dev . parent = & dev - > udev - > dev ;
2010-11-07 18:53:44 +03:00
strlcpy ( dev - > i2c_adap . name , dev - > name , sizeof ( dev - > i2c_adap . name ) ) ;
2009-09-14 16:42:41 +04:00
dev - > i2c_adap . algo_data = dev ;
2010-11-07 18:53:44 +03:00
i2c_set_adapdata ( & dev - > i2c_adap , & dev - > v4l2_dev ) ;
rc = i2c_add_adapter ( & dev - > i2c_adap ) ;
if ( rc )
return rc ;
2009-09-14 16:42:41 +04:00
dev - > i2c_client . adapter = & dev - > i2c_adap ;
2010-11-07 18:53:44 +03:00
strlcpy ( dev - > i2c_client . name , " tm6000 internal " , I2C_NAME_SIZE ) ;
2011-04-21 01:43:24 +04:00
tm6000_i2c_eeprom ( dev ) ;
2007-11-05 21:39:41 +03:00
2009-09-14 16:42:41 +04:00
return 0 ;
}
/*
* tm6000_i2c_unregister ( )
* unregister i2c_bus
*/
int tm6000_i2c_unregister ( struct tm6000_core * dev )
{
i2c_del_adapter ( & dev - > i2c_adap ) ;
return 0 ;
}