2007-12-18 07:55:51 +03:00
/*
* Driver for Xceive XC5000 " QAM/8VSB single chip tuner "
*
* Copyright ( c ) 2007 Xceive Corporation
* Copyright ( c ) 2007 Steven Toth < stoth @ hauppauge . com >
*
* 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/module.h>
# include <linux/moduleparam.h>
2008-01-16 03:57:14 +03:00
# include <linux/videodev2.h>
2007-12-18 07:55:51 +03:00
# include <linux/delay.h>
# include <linux/dvb/frontend.h>
# include <linux/i2c.h>
# include "dvb_frontend.h"
# include "xc5000.h"
# include "xc5000_priv.h"
static int debug ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Turn on/off debugging (default:off). " ) ;
2008-06-22 05:13:42 +04:00
static int xc5000_load_fw_on_attach ;
module_param_named ( init_fw , xc5000_load_fw_on_attach , int , 0644 ) ;
MODULE_PARM_DESC ( init_fw , " Load firmware during driver initialization. " ) ;
2007-12-18 07:55:51 +03:00
# define dprintk(level,fmt, arg...) if (debug >= level) \
printk ( KERN_INFO " %s: " fmt , " xc5000 " , # # arg )
# define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
2007-12-27 20:33:30 +03:00
# define XC5000_DEFAULT_FIRMWARE_SIZE 12332
2007-12-18 07:55:51 +03:00
/* Misc Defines */
# define MAX_TV_STANDARD 23
# define XC_MAX_I2C_WRITE_LENGTH 64
/* Signal Types */
# define XC_RF_MODE_AIR 0
# define XC_RF_MODE_CABLE 1
/* Result codes */
# define XC_RESULT_SUCCESS 0
# define XC_RESULT_RESET_FAILURE 1
# define XC_RESULT_I2C_WRITE_FAILURE 2
# define XC_RESULT_I2C_READ_FAILURE 3
# define XC_RESULT_OUT_OF_RANGE 5
2008-01-05 22:50:14 +03:00
/* Product id */
# define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000
# define XC_PRODUCT_ID_FW_LOADED 0x1388
2007-12-18 07:55:51 +03:00
/* Registers */
# define XREG_INIT 0x00
# define XREG_VIDEO_MODE 0x01
# define XREG_AUDIO_MODE 0x02
# define XREG_RF_FREQ 0x03
# define XREG_D_CODE 0x04
# define XREG_IF_OUT 0x05
# define XREG_SEEK_MODE 0x07
# define XREG_POWER_DOWN 0x0A
# define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
# define XREG_SMOOTHEDCVBS 0x0E
# define XREG_XTALFREQ 0x0F
# define XREG_FINERFFREQ 0x10
# define XREG_DDIMODE 0x11
# define XREG_ADC_ENV 0x00
# define XREG_QUALITY 0x01
# define XREG_FRAME_LINES 0x02
# define XREG_HSYNC_FREQ 0x03
# define XREG_LOCK 0x04
# define XREG_FREQ_ERROR 0x05
# define XREG_SNR 0x06
# define XREG_VERSION 0x07
# define XREG_PRODUCT_ID 0x08
# define XREG_BUSY 0x09
/*
Basic firmware description . This will remain with
the driver for documentation purposes .
This represents an I2C firmware file encoded as a
string of unsigned char . Format is as follows :
char [ 0 ] = len0_MSB - > len = len_MSB * 256 + len_LSB
char [ 1 ] = len0_LSB - > length of first write transaction
char [ 2 ] = data0 - > first byte to be sent
char [ 3 ] = data1
char [ 4 ] = data2
char [ ] = . . .
char [ M ] = dataN - > last byte to be sent
char [ M + 1 ] = len1_MSB - > len = len_MSB * 256 + len_LSB
char [ M + 2 ] = len1_LSB - > length of second write transaction
char [ M + 3 ] = data0
char [ M + 4 ] = data1
. . .
etc .
The [ len ] value should be interpreted as follows :
len = len_MSB _ len_LSB
len = 1111 _1111_1111_1111 : End of I2C_SEQUENCE
len = 0000 _0000_0000_0000 : Reset command : Do hardware reset
len = 0 NNN_NNNN_NNNN_NNNN : Normal transaction : number of bytes = { 1 : 32767 )
len = 1 WWW_WWWW_WWWW_WWWW : Wait command : wait for { 1 : 32767 } ms
For the RESET and WAIT commands , the two following bytes will contain
immediately the length of the following transaction .
*/
typedef struct {
char * Name ;
2007-12-20 07:14:43 +03:00
u16 AudioMode ;
u16 VideoMode ;
2007-12-18 07:55:51 +03:00
} XC_TV_STANDARD ;
/* Tuner standards */
2008-01-05 22:50:14 +03:00
# define MN_NTSC_PAL_BTSC 0
# define MN_NTSC_PAL_A2 1
# define MN_NTSC_PAL_EIAJ 2
# define MN_NTSC_PAL_Mono 3
# define BG_PAL_A2 4
# define BG_PAL_NICAM 5
# define BG_PAL_MONO 6
# define I_PAL_NICAM 7
# define I_PAL_NICAM_MONO 8
# define DK_PAL_A2 9
# define DK_PAL_NICAM 10
# define DK_PAL_MONO 11
# define DK_SECAM_A2DK1 12
# define DK_SECAM_A2LDK3 13
# define DK_SECAM_A2MONO 14
# define L_SECAM_NICAM 15
# define LC_SECAM_NICAM 16
# define DTV6 17
# define DTV8 18
# define DTV7_8 19
# define DTV7 20
# define FM_Radio_INPUT2 21
# define FM_Radio_INPUT1 22
2007-12-18 07:55:51 +03:00
2008-04-22 21:41:45 +04:00
static XC_TV_STANDARD XC5000_Standard [ MAX_TV_STANDARD ] = {
2007-12-18 07:55:51 +03:00
{ " M/N-NTSC/PAL-BTSC " , 0x0400 , 0x8020 } ,
{ " M/N-NTSC/PAL-A2 " , 0x0600 , 0x8020 } ,
{ " M/N-NTSC/PAL-EIAJ " , 0x0440 , 0x8020 } ,
{ " M/N-NTSC/PAL-Mono " , 0x0478 , 0x8020 } ,
{ " B/G-PAL-A2 " , 0x0A00 , 0x8049 } ,
{ " B/G-PAL-NICAM " , 0x0C04 , 0x8049 } ,
{ " B/G-PAL-MONO " , 0x0878 , 0x8059 } ,
{ " I-PAL-NICAM " , 0x1080 , 0x8009 } ,
{ " I-PAL-NICAM-MONO " , 0x0E78 , 0x8009 } ,
{ " D/K-PAL-A2 " , 0x1600 , 0x8009 } ,
{ " D/K-PAL-NICAM " , 0x0E80 , 0x8009 } ,
{ " D/K-PAL-MONO " , 0x1478 , 0x8009 } ,
{ " D/K-SECAM-A2 DK1 " , 0x1200 , 0x8009 } ,
{ " D/K-SECAM-A2 L/DK3 " , 0x0E00 , 0x8009 } ,
{ " D/K-SECAM-A2 MONO " , 0x1478 , 0x8009 } ,
{ " L-SECAM-NICAM " , 0x8E82 , 0x0009 } ,
{ " L'-SECAM-NICAM " , 0x8E82 , 0x4009 } ,
{ " DTV6 " , 0x00C0 , 0x8002 } ,
{ " DTV8 " , 0x00C0 , 0x800B } ,
{ " DTV7/8 " , 0x00C0 , 0x801B } ,
{ " DTV7 " , 0x00C0 , 0x8007 } ,
{ " FM Radio-INPUT2 " , 0x9802 , 0x9002 } ,
{ " FM Radio-INPUT1 " , 0x0208 , 0x9002 }
} ;
2008-06-22 04:06:02 +04:00
static int xc5000_is_firmware_loaded ( struct dvb_frontend * fe ) ;
2007-12-18 07:55:51 +03:00
static int xc5000_writeregs ( struct xc5000_priv * priv , u8 * buf , u8 len ) ;
static int xc5000_readregs ( struct xc5000_priv * priv , u8 * buf , u8 len ) ;
static void xc5000_TunerReset ( struct dvb_frontend * fe ) ;
2007-12-20 07:14:43 +03:00
static int xc_send_i2c_data ( struct xc5000_priv * priv , u8 * buf , int len )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
return xc5000_writeregs ( priv , buf , len )
2007-12-18 07:55:51 +03:00
? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS ;
}
2007-12-20 07:14:43 +03:00
static int xc_read_i2c_data ( struct xc5000_priv * priv , u8 * buf , int len )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
return xc5000_readregs ( priv , buf , len )
2007-12-18 07:55:51 +03:00
? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS ;
}
2007-12-20 07:14:43 +03:00
static int xc_reset ( struct dvb_frontend * fe )
2007-12-18 07:55:51 +03:00
{
xc5000_TunerReset ( fe ) ;
return XC_RESULT_SUCCESS ;
}
2007-12-20 07:14:43 +03:00
static void xc_wait ( int wait_ms )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
msleep ( wait_ms ) ;
2007-12-18 07:55:51 +03:00
}
static void xc5000_TunerReset ( struct dvb_frontend * fe )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
int ret ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2007-12-18 07:55:51 +03:00
2008-01-05 22:50:14 +03:00
if ( priv - > cfg - > tuner_callback ) {
2008-05-10 21:34:09 +04:00
ret = priv - > cfg - > tuner_callback ( priv - > devptr ,
2008-01-05 22:50:14 +03:00
XC5000_TUNER_RESET , 0 ) ;
2007-12-18 07:55:51 +03:00
if ( ret )
printk ( KERN_ERR " xc5000: reset failed \n " ) ;
} else
2008-01-05 22:50:14 +03:00
printk ( KERN_ERR " xc5000: no tuner reset callback function, fatal \n " ) ;
2007-12-18 07:55:51 +03:00
}
2007-12-20 07:14:43 +03:00
static int xc_write_reg ( struct xc5000_priv * priv , u16 regAddr , u16 i2cData )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
u8 buf [ 4 ] ;
2007-12-18 07:55:51 +03:00
int WatchDogTimer = 5 ;
int result ;
buf [ 0 ] = ( regAddr > > 8 ) & 0xFF ;
buf [ 1 ] = regAddr & 0xFF ;
buf [ 2 ] = ( i2cData > > 8 ) & 0xFF ;
buf [ 3 ] = i2cData & 0xFF ;
result = xc_send_i2c_data ( priv , buf , 4 ) ;
2007-12-20 07:14:43 +03:00
if ( result = = XC_RESULT_SUCCESS ) {
2007-12-18 07:55:51 +03:00
/* wait for busy flag to clear */
while ( ( WatchDogTimer > 0 ) & & ( result = = XC_RESULT_SUCCESS ) ) {
buf [ 0 ] = 0 ;
buf [ 1 ] = XREG_BUSY ;
result = xc_send_i2c_data ( priv , buf , 2 ) ;
if ( result = = XC_RESULT_SUCCESS ) {
result = xc_read_i2c_data ( priv , buf , 2 ) ;
if ( result = = XC_RESULT_SUCCESS ) {
if ( ( buf [ 0 ] = = 0 ) & & ( buf [ 1 ] = = 0 ) ) {
/* busy flag cleared */
break ;
} else {
xc_wait ( 100 ) ; /* wait 5 ms */
WatchDogTimer - - ;
}
}
}
}
}
if ( WatchDogTimer < 0 )
result = XC_RESULT_I2C_WRITE_FAILURE ;
return result ;
}
2007-12-20 07:14:43 +03:00
static int xc_read_reg ( struct xc5000_priv * priv , u16 regAddr , u16 * i2cData )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
u8 buf [ 2 ] ;
2007-12-18 07:55:51 +03:00
int result ;
buf [ 0 ] = ( regAddr > > 8 ) & 0xFF ;
buf [ 1 ] = regAddr & 0xFF ;
result = xc_send_i2c_data ( priv , buf , 2 ) ;
2007-12-20 07:14:43 +03:00
if ( result ! = XC_RESULT_SUCCESS )
2007-12-18 07:55:51 +03:00
return result ;
result = xc_read_i2c_data ( priv , buf , 2 ) ;
2007-12-20 07:14:43 +03:00
if ( result ! = XC_RESULT_SUCCESS )
2007-12-18 07:55:51 +03:00
return result ;
* i2cData = buf [ 0 ] * 256 + buf [ 1 ] ;
return result ;
}
2008-05-24 03:13:34 +04:00
static int xc_load_i2c_sequence ( struct dvb_frontend * fe , const u8 * i2c_sequence )
2007-12-18 07:55:51 +03:00
{
struct xc5000_priv * priv = fe - > tuner_priv ;
int i , nbytes_to_send , result ;
unsigned int len , pos , index ;
2007-12-20 07:14:43 +03:00
u8 buf [ XC_MAX_I2C_WRITE_LENGTH ] ;
2007-12-18 07:55:51 +03:00
index = 0 ;
while ( ( i2c_sequence [ index ] ! = 0xFF ) | | ( i2c_sequence [ index + 1 ] ! = 0xFF ) ) {
len = i2c_sequence [ index ] * 256 + i2c_sequence [ index + 1 ] ;
2007-12-20 07:14:43 +03:00
if ( len = = 0x0000 ) {
2007-12-18 07:55:51 +03:00
/* RESET command */
result = xc_reset ( fe ) ;
index + = 2 ;
2007-12-20 07:14:43 +03:00
if ( result ! = XC_RESULT_SUCCESS )
2007-12-18 07:55:51 +03:00
return result ;
} else if ( len & 0x8000 ) {
/* WAIT command */
xc_wait ( len & 0x7FFF ) ;
index + = 2 ;
} else {
/* Send i2c data whilst ensuring individual transactions
* do not exceed XC_MAX_I2C_WRITE_LENGTH bytes .
*/
index + = 2 ;
buf [ 0 ] = i2c_sequence [ index ] ;
buf [ 1 ] = i2c_sequence [ index + 1 ] ;
pos = 2 ;
while ( pos < len ) {
if ( ( len - pos ) > XC_MAX_I2C_WRITE_LENGTH - 2 ) {
nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH ;
} else {
nbytes_to_send = ( len - pos + 2 ) ;
}
for ( i = 2 ; i < nbytes_to_send ; i + + ) {
buf [ i ] = i2c_sequence [ index + pos + i - 2 ] ;
}
result = xc_send_i2c_data ( priv , buf , nbytes_to_send ) ;
2007-12-20 07:14:43 +03:00
if ( result ! = XC_RESULT_SUCCESS )
2007-12-18 07:55:51 +03:00
return result ;
pos + = nbytes_to_send - 2 ;
}
index + = len ;
}
}
return XC_RESULT_SUCCESS ;
}
2007-12-20 07:14:43 +03:00
static int xc_initialize ( struct xc5000_priv * priv )
2007-12-18 07:55:51 +03:00
{
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2007-12-18 07:55:51 +03:00
return xc_write_reg ( priv , XREG_INIT , 0 ) ;
}
2007-12-20 07:14:43 +03:00
static int xc_SetTVStandard ( struct xc5000_priv * priv ,
u16 VideoMode , u16 AudioMode )
2007-12-18 07:55:51 +03:00
{
int ret ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s(0x%04x,0x%04x) \n " , __func__ , VideoMode , AudioMode ) ;
2007-12-18 07:55:51 +03:00
dprintk ( 1 , " %s() Standard = %s \n " ,
2008-04-09 06:20:00 +04:00
__func__ ,
2007-12-18 07:55:51 +03:00
XC5000_Standard [ priv - > video_standard ] . Name ) ;
ret = xc_write_reg ( priv , XREG_VIDEO_MODE , VideoMode ) ;
if ( ret = = XC_RESULT_SUCCESS )
ret = xc_write_reg ( priv , XREG_AUDIO_MODE , AudioMode ) ;
return ret ;
}
2007-12-20 07:14:43 +03:00
static int xc_shutdown ( struct xc5000_priv * priv )
2007-12-18 07:55:51 +03:00
{
2008-06-22 04:06:02 +04:00
return XC_RESULT_SUCCESS ;
2008-01-05 22:50:14 +03:00
/* Fixme: cannot bring tuner back alive once shutdown
* without reloading the driver modules .
* return xc_write_reg ( priv , XREG_POWER_DOWN , 0 ) ;
*/
2007-12-18 07:55:51 +03:00
}
2007-12-20 07:14:43 +03:00
static int xc_SetSignalSource ( struct xc5000_priv * priv , u16 rf_mode )
2007-12-18 07:55:51 +03:00
{
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s(%d) Source = %s \n " , __func__ , rf_mode ,
2007-12-18 07:55:51 +03:00
rf_mode = = XC_RF_MODE_AIR ? " ANTENNA " : " CABLE " ) ;
2007-12-20 07:14:43 +03:00
if ( ( rf_mode ! = XC_RF_MODE_AIR ) & & ( rf_mode ! = XC_RF_MODE_CABLE ) )
2007-12-18 07:55:51 +03:00
{
rf_mode = XC_RF_MODE_CABLE ;
printk ( KERN_ERR
" %s(), Invalid mode, defaulting to CABLE " ,
2008-04-09 06:20:00 +04:00
__func__ ) ;
2007-12-18 07:55:51 +03:00
}
return xc_write_reg ( priv , XREG_SIGNALSOURCE , rf_mode ) ;
}
2007-12-20 07:14:43 +03:00
static const struct dvb_tuner_ops xc5000_tuner_ops ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
static int xc_set_RF_frequency ( struct xc5000_priv * priv , u32 freq_hz )
{
u16 freq_code ;
2007-12-18 07:55:51 +03:00
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s(%u) \n " , __func__ , freq_hz ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
if ( ( freq_hz > xc5000_tuner_ops . info . frequency_max ) | |
( freq_hz < xc5000_tuner_ops . info . frequency_min ) )
2007-12-18 07:55:51 +03:00
return XC_RESULT_OUT_OF_RANGE ;
2007-12-20 07:14:43 +03:00
freq_code = ( u16 ) ( freq_hz / 15625 ) ;
return xc_write_reg ( priv , XREG_RF_FREQ , freq_code ) ;
2007-12-18 07:55:51 +03:00
}
2007-12-20 07:14:43 +03:00
static int xc_set_IF_frequency ( struct xc5000_priv * priv , u32 freq_khz )
{
u32 freq_code = ( freq_khz * 1024 ) / 1000 ;
dprintk ( 1 , " %s(freq_khz = %d) freq_code = 0x%x \n " ,
2008-04-09 06:20:00 +04:00
__func__ , freq_khz , freq_code ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
return xc_write_reg ( priv , XREG_IF_OUT , freq_code ) ;
2007-12-18 07:55:51 +03:00
}
2007-12-20 07:14:43 +03:00
static int xc_get_ADC_Envelope ( struct xc5000_priv * priv , u16 * adc_envelope )
2007-12-18 07:55:51 +03:00
{
return xc_read_reg ( priv , XREG_ADC_ENV , adc_envelope ) ;
}
2007-12-20 07:14:43 +03:00
static int xc_get_frequency_error ( struct xc5000_priv * priv , u32 * freq_error_hz )
2007-12-18 07:55:51 +03:00
{
int result ;
2007-12-20 07:14:43 +03:00
u16 regData ;
2007-12-18 07:55:51 +03:00
u32 tmp ;
result = xc_read_reg ( priv , XREG_FREQ_ERROR , & regData ) ;
if ( result )
return result ;
tmp = ( u32 ) regData ;
2007-12-20 07:14:43 +03:00
( * freq_error_hz ) = ( tmp * 15625 ) / 1000 ;
2007-12-18 07:55:51 +03:00
return result ;
}
2007-12-20 07:14:43 +03:00
static int xc_get_lock_status ( struct xc5000_priv * priv , u16 * lock_status )
2007-12-18 07:55:51 +03:00
{
return xc_read_reg ( priv , XREG_LOCK , lock_status ) ;
}
2007-12-20 07:14:43 +03:00
static int xc_get_version ( struct xc5000_priv * priv ,
u8 * hw_majorversion , u8 * hw_minorversion ,
u8 * fw_majorversion , u8 * fw_minorversion )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
u16 data ;
2007-12-18 07:55:51 +03:00
int result ;
result = xc_read_reg ( priv , XREG_VERSION , & data ) ;
if ( result )
return result ;
2007-12-20 07:14:43 +03:00
( * hw_majorversion ) = ( data > > 12 ) & 0x0F ;
( * hw_minorversion ) = ( data > > 8 ) & 0x0F ;
( * fw_majorversion ) = ( data > > 4 ) & 0x0F ;
( * fw_minorversion ) = data & 0x0F ;
2007-12-18 07:55:51 +03:00
return 0 ;
}
2007-12-20 07:14:43 +03:00
static int xc_get_hsync_freq ( struct xc5000_priv * priv , u32 * hsync_freq_hz )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
u16 regData ;
2007-12-18 07:55:51 +03:00
int result ;
result = xc_read_reg ( priv , XREG_HSYNC_FREQ , & regData ) ;
if ( result )
return result ;
( * hsync_freq_hz ) = ( ( regData & 0x0fff ) * 763 ) / 100 ;
return result ;
}
2007-12-20 07:14:43 +03:00
static int xc_get_frame_lines ( struct xc5000_priv * priv , u16 * frame_lines )
2007-12-18 07:55:51 +03:00
{
return xc_read_reg ( priv , XREG_FRAME_LINES , frame_lines ) ;
}
2007-12-20 07:14:43 +03:00
static int xc_get_quality ( struct xc5000_priv * priv , u16 * quality )
2007-12-18 07:55:51 +03:00
{
return xc_read_reg ( priv , XREG_QUALITY , quality ) ;
}
2007-12-20 07:14:43 +03:00
static u16 WaitForLock ( struct xc5000_priv * priv )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
u16 lockState = 0 ;
2007-12-18 07:55:51 +03:00
int watchDogCount = 40 ;
2007-12-20 07:14:43 +03:00
while ( ( lockState = = 0 ) & & ( watchDogCount > 0 ) ) {
2007-12-18 07:55:51 +03:00
xc_get_lock_status ( priv , & lockState ) ;
2007-12-20 07:14:43 +03:00
if ( lockState ! = 1 ) {
2007-12-18 07:55:51 +03:00
xc_wait ( 5 ) ;
watchDogCount - - ;
}
}
return lockState ;
}
2007-12-20 07:14:43 +03:00
static int xc_tune_channel ( struct xc5000_priv * priv , u32 freq_hz )
2007-12-18 07:55:51 +03:00
{
int found = 0 ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s(%u) \n " , __func__ , freq_hz ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
if ( xc_set_RF_frequency ( priv , freq_hz ) ! = XC_RESULT_SUCCESS )
2007-12-18 07:55:51 +03:00
return 0 ;
2007-12-20 07:14:43 +03:00
if ( WaitForLock ( priv ) = = 1 )
2007-12-18 07:55:51 +03:00
found = 1 ;
return found ;
}
static int xc5000_readreg ( struct xc5000_priv * priv , u16 reg , u16 * val )
{
u8 buf [ 2 ] = { reg > > 8 , reg & 0xff } ;
u8 bval [ 2 ] = { 0 , 0 } ;
struct i2c_msg msg [ 2 ] = {
{ . addr = priv - > cfg - > i2c_address ,
. flags = 0 , . buf = & buf [ 0 ] , . len = 2 } ,
{ . addr = priv - > cfg - > i2c_address ,
. flags = I2C_M_RD , . buf = & bval [ 0 ] , . len = 2 } ,
} ;
if ( i2c_transfer ( priv - > i2c , msg , 2 ) ! = 2 ) {
2008-01-05 22:50:14 +03:00
printk ( KERN_WARNING " xc5000: I2C read failed \n " ) ;
2007-12-18 07:55:51 +03:00
return - EREMOTEIO ;
}
* val = ( bval [ 0 ] < < 8 ) | bval [ 1 ] ;
return 0 ;
}
static int xc5000_writeregs ( struct xc5000_priv * priv , u8 * buf , u8 len )
{
struct i2c_msg msg = { . addr = priv - > cfg - > i2c_address ,
. flags = 0 , . buf = buf , . len = len } ;
if ( i2c_transfer ( priv - > i2c , & msg , 1 ) ! = 1 ) {
2008-01-05 22:50:14 +03:00
printk ( KERN_ERR " xc5000: I2C write failed (len=%i) \n " ,
2007-12-18 07:55:51 +03:00
( int ) len ) ;
return - EREMOTEIO ;
}
return 0 ;
}
static int xc5000_readregs ( struct xc5000_priv * priv , u8 * buf , u8 len )
{
struct i2c_msg msg = { . addr = priv - > cfg - > i2c_address ,
. flags = I2C_M_RD , . buf = buf , . len = len } ;
if ( i2c_transfer ( priv - > i2c , & msg , 1 ) ! = 1 ) {
printk ( KERN_ERR " xc5000 I2C read failed (len=%i) \n " , ( int ) len ) ;
return - EREMOTEIO ;
}
return 0 ;
}
static int xc5000_fwupload ( struct dvb_frontend * fe )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
const struct firmware * fw ;
int ret ;
2007-12-20 07:14:43 +03:00
/* request the firmware, this will block and timeout */
printk ( KERN_INFO " xc5000: waiting for firmware upload (%s)... \n " ,
XC5000_DEFAULT_FIRMWARE ) ;
2008-01-05 22:50:14 +03:00
ret = request_firmware ( & fw , XC5000_DEFAULT_FIRMWARE , & priv - > i2c - > dev ) ;
2007-12-18 07:55:51 +03:00
if ( ret ) {
printk ( KERN_ERR " xc5000: Upload failed. (file not found?) \n " ) ;
ret = XC_RESULT_RESET_FAILURE ;
2008-01-25 04:29:46 +03:00
goto out ;
2007-12-18 07:55:51 +03:00
} else {
2007-12-21 22:20:23 +03:00
printk ( KERN_INFO " xc5000: firmware read %Zu bytes. \n " ,
fw - > size ) ;
2007-12-18 07:55:51 +03:00
ret = XC_RESULT_SUCCESS ;
}
2007-12-20 07:14:43 +03:00
if ( fw - > size ! = XC5000_DEFAULT_FIRMWARE_SIZE ) {
2007-12-18 07:55:51 +03:00
printk ( KERN_ERR " xc5000: firmware incorrect size \n " ) ;
ret = XC_RESULT_RESET_FAILURE ;
} else {
printk ( KERN_INFO " xc5000: firmware upload \n " ) ;
ret = xc_load_i2c_sequence ( fe , fw - > data ) ;
}
2008-01-25 04:29:46 +03:00
out :
2007-12-18 07:55:51 +03:00
release_firmware ( fw ) ;
return ret ;
}
2007-12-20 07:14:43 +03:00
static void xc_debug_dump ( struct xc5000_priv * priv )
2007-12-18 07:55:51 +03:00
{
2007-12-20 07:14:43 +03:00
u16 adc_envelope ;
u32 freq_error_hz = 0 ;
u16 lock_status ;
u32 hsync_freq_hz = 0 ;
u16 frame_lines ;
u16 quality ;
u8 hw_majorversion = 0 , hw_minorversion = 0 ;
u8 fw_majorversion = 0 , fw_minorversion = 0 ;
2007-12-18 07:55:51 +03:00
/* Wait for stats to stabilize.
* Frame Lines needs two frame times after initial lock
* before it is valid .
*/
2007-12-20 07:14:43 +03:00
xc_wait ( 100 ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
xc_get_ADC_Envelope ( priv , & adc_envelope ) ;
dprintk ( 1 , " *** ADC envelope (0-1023) = %d \n " , adc_envelope ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
xc_get_frequency_error ( priv , & freq_error_hz ) ;
dprintk ( 1 , " *** Frequency error = %d Hz \n " , freq_error_hz ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
xc_get_lock_status ( priv , & lock_status ) ;
dprintk ( 1 , " *** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d \n " ,
2007-12-18 07:55:51 +03:00
lock_status ) ;
xc_get_version ( priv , & hw_majorversion , & hw_minorversion ,
2007-12-20 07:14:43 +03:00
& fw_majorversion , & fw_minorversion ) ;
2007-12-18 07:55:51 +03:00
dprintk ( 1 , " *** HW: V%02x.%02x, FW: V%02x.%02x \n " ,
hw_majorversion , hw_minorversion ,
fw_majorversion , fw_minorversion ) ;
2007-12-20 07:14:43 +03:00
xc_get_hsync_freq ( priv , & hsync_freq_hz ) ;
dprintk ( 1 , " *** Horizontal sync frequency = %d Hz \n " , hsync_freq_hz ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
xc_get_frame_lines ( priv , & frame_lines ) ;
dprintk ( 1 , " *** Frame lines = %d \n " , frame_lines ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
xc_get_quality ( priv , & quality ) ;
dprintk ( 1 , " *** Quality (0:<8dB, 7:>56dB) = %d \n " , quality ) ;
2007-12-18 07:55:51 +03:00
}
static int xc5000_set_params ( struct dvb_frontend * fe ,
struct dvb_frontend_parameters * params )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
2007-12-20 07:14:43 +03:00
int ret ;
2007-12-18 07:55:51 +03:00
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() frequency=%d (Hz) \n " , __func__ , params - > frequency ) ;
2007-12-18 07:55:51 +03:00
switch ( params - > u . vsb . modulation ) {
case VSB_8 :
case VSB_16 :
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() VSB modulation \n " , __func__ ) ;
2007-12-18 07:55:51 +03:00
priv - > rf_mode = XC_RF_MODE_AIR ;
2007-12-20 07:14:43 +03:00
priv - > freq_hz = params - > frequency - 1750000 ;
priv - > bandwidth = BANDWIDTH_6_MHZ ;
priv - > video_standard = DTV6 ;
2007-12-18 07:55:51 +03:00
break ;
case QAM_64 :
case QAM_256 :
case QAM_AUTO :
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() QAM modulation \n " , __func__ ) ;
2007-12-18 07:55:51 +03:00
priv - > rf_mode = XC_RF_MODE_CABLE ;
2007-12-20 07:14:43 +03:00
priv - > freq_hz = params - > frequency - 1750000 ;
priv - > bandwidth = BANDWIDTH_6_MHZ ;
priv - > video_standard = DTV6 ;
2007-12-18 07:55:51 +03:00
break ;
default :
return - EINVAL ;
}
dprintk ( 1 , " %s() frequency=%d (compensated) \n " ,
2008-04-09 06:20:00 +04:00
__func__ , priv - > freq_hz ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
ret = xc_SetSignalSource ( priv , priv - > rf_mode ) ;
if ( ret ! = XC_RESULT_SUCCESS ) {
printk ( KERN_ERR
" xc5000: xc_SetSignalSource(%d) failed \n " ,
priv - > rf_mode ) ;
return - EREMOTEIO ;
}
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
ret = xc_SetTVStandard ( priv ,
2007-12-18 07:55:51 +03:00
XC5000_Standard [ priv - > video_standard ] . VideoMode ,
XC5000_Standard [ priv - > video_standard ] . AudioMode ) ;
2007-12-20 07:14:43 +03:00
if ( ret ! = XC_RESULT_SUCCESS ) {
printk ( KERN_ERR " xc5000: xc_SetTVStandard failed \n " ) ;
return - EREMOTEIO ;
}
ret = xc_set_IF_frequency ( priv , priv - > cfg - > if_khz ) ;
if ( ret ! = XC_RESULT_SUCCESS ) {
printk ( KERN_ERR " xc5000: xc_Set_IF_frequency(%d) failed \n " ,
priv - > cfg - > if_khz ) ;
return - EIO ;
}
xc_tune_channel ( priv , priv - > freq_hz ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
if ( debug )
xc_debug_dump ( priv ) ;
2007-12-18 07:55:51 +03:00
return 0 ;
}
2008-06-22 04:06:02 +04:00
static int xc5000_is_firmware_loaded ( struct dvb_frontend * fe )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
int ret ;
u16 id ;
ret = xc5000_readreg ( priv , XREG_PRODUCT_ID , & id ) ;
if ( ret = = XC_RESULT_SUCCESS ) {
if ( id = = XC_PRODUCT_ID_FW_NOT_LOADED )
ret = XC_RESULT_RESET_FAILURE ;
else
ret = XC_RESULT_SUCCESS ;
}
dprintk ( 1 , " %s() returns %s id = 0x%x \n " , __func__ ,
ret = = XC_RESULT_SUCCESS ? " True " : " False " , id ) ;
return ret ;
}
2008-01-05 22:50:14 +03:00
static int xc_load_fw_and_init_tuner ( struct dvb_frontend * fe ) ;
static int xc5000_set_analog_params ( struct dvb_frontend * fe ,
struct analog_parameters * params )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
int ret ;
2008-06-22 04:06:02 +04:00
if ( xc5000_is_firmware_loaded ( fe ) ! = XC_RESULT_SUCCESS )
2008-01-05 22:50:14 +03:00
xc_load_fw_and_init_tuner ( fe ) ;
dprintk ( 1 , " %s() frequency=%d (in units of 62.5khz) \n " ,
2008-04-09 06:20:00 +04:00
__func__ , params - > frequency ) ;
2008-01-05 22:50:14 +03:00
priv - > rf_mode = XC_RF_MODE_CABLE ; /* Fix me: it could be air. */
/* params->frequency is in units of 62.5khz */
priv - > freq_hz = params - > frequency * 62500 ;
/* FIX ME: Some video standards may have several possible audio
standards . We simply default to one of them here .
*/
if ( params - > std & V4L2_STD_MN ) {
/* default to BTSC audio standard */
priv - > video_standard = MN_NTSC_PAL_BTSC ;
goto tune_channel ;
}
if ( params - > std & V4L2_STD_PAL_BG ) {
/* default to NICAM audio standard */
priv - > video_standard = BG_PAL_NICAM ;
goto tune_channel ;
}
if ( params - > std & V4L2_STD_PAL_I ) {
/* default to NICAM audio standard */
priv - > video_standard = I_PAL_NICAM ;
goto tune_channel ;
}
if ( params - > std & V4L2_STD_PAL_DK ) {
/* default to NICAM audio standard */
priv - > video_standard = DK_PAL_NICAM ;
goto tune_channel ;
}
if ( params - > std & V4L2_STD_SECAM_DK ) {
/* default to A2 DK1 audio standard */
priv - > video_standard = DK_SECAM_A2DK1 ;
goto tune_channel ;
}
if ( params - > std & V4L2_STD_SECAM_L ) {
priv - > video_standard = L_SECAM_NICAM ;
goto tune_channel ;
}
if ( params - > std & V4L2_STD_SECAM_LC ) {
priv - > video_standard = LC_SECAM_NICAM ;
goto tune_channel ;
}
tune_channel :
ret = xc_SetSignalSource ( priv , priv - > rf_mode ) ;
if ( ret ! = XC_RESULT_SUCCESS ) {
printk ( KERN_ERR
" xc5000: xc_SetSignalSource(%d) failed \n " ,
priv - > rf_mode ) ;
return - EREMOTEIO ;
}
ret = xc_SetTVStandard ( priv ,
XC5000_Standard [ priv - > video_standard ] . VideoMode ,
XC5000_Standard [ priv - > video_standard ] . AudioMode ) ;
if ( ret ! = XC_RESULT_SUCCESS ) {
printk ( KERN_ERR " xc5000: xc_SetTVStandard failed \n " ) ;
return - EREMOTEIO ;
}
xc_tune_channel ( priv , priv - > freq_hz ) ;
if ( debug )
xc_debug_dump ( priv ) ;
return 0 ;
}
2007-12-18 07:55:51 +03:00
static int xc5000_get_frequency ( struct dvb_frontend * fe , u32 * freq )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2007-12-20 07:14:43 +03:00
* freq = priv - > freq_hz ;
2007-12-18 07:55:51 +03:00
return 0 ;
}
static int xc5000_get_bandwidth ( struct dvb_frontend * fe , u32 * bw )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2008-01-05 22:50:14 +03:00
2007-12-18 07:55:51 +03:00
* bw = priv - > bandwidth ;
return 0 ;
}
static int xc5000_get_status ( struct dvb_frontend * fe , u32 * status )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
2007-12-20 07:14:43 +03:00
u16 lock_status = 0 ;
2007-12-18 07:55:51 +03:00
xc_get_lock_status ( priv , & lock_status ) ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() lock_status = 0x%08x \n " , __func__ , lock_status ) ;
2007-12-18 07:55:51 +03:00
* status = lock_status ;
return 0 ;
}
2007-12-20 07:14:43 +03:00
static int xc_load_fw_and_init_tuner ( struct dvb_frontend * fe )
2007-12-18 07:55:51 +03:00
{
struct xc5000_priv * priv = fe - > tuner_priv ;
2008-01-05 22:50:14 +03:00
int ret = 0 ;
2007-12-18 07:55:51 +03:00
2008-06-22 04:06:02 +04:00
if ( xc5000_is_firmware_loaded ( fe ) ! = XC_RESULT_SUCCESS ) {
2007-12-18 07:55:51 +03:00
ret = xc5000_fwupload ( fe ) ;
2007-12-20 07:14:43 +03:00
if ( ret ! = XC_RESULT_SUCCESS )
return ret ;
2007-12-18 07:55:51 +03:00
}
/* Start the tuner self-calibration process */
ret | = xc_initialize ( priv ) ;
/* Wait for calibration to complete.
* We could continue but XC5000 will clock stretch subsequent
* I2C transactions until calibration is complete . This way we
* don ' t have to rely on clock stretching working .
*/
xc_wait ( 100 ) ;
/* Default to "CABLE" mode */
ret | = xc_write_reg ( priv , XREG_SIGNALSOURCE , XC_RF_MODE_CABLE ) ;
return ret ;
}
2007-12-20 07:14:43 +03:00
static int xc5000_sleep ( struct dvb_frontend * fe )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
2008-01-05 22:50:14 +03:00
int ret ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2007-12-20 07:14:43 +03:00
2008-01-05 22:50:14 +03:00
/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
* once shutdown without reloading the driver . Maybe I am not
* doing something right .
*
*/
ret = xc_shutdown ( priv ) ;
if ( ret ! = XC_RESULT_SUCCESS ) {
printk ( KERN_ERR
" xc5000: %s() unable to shutdown tuner \n " ,
2008-04-09 06:20:00 +04:00
__func__ ) ;
2008-01-05 22:50:14 +03:00
return - EREMOTEIO ;
}
else {
return XC_RESULT_SUCCESS ;
}
2007-12-20 07:14:43 +03:00
}
2007-12-18 07:55:51 +03:00
static int xc5000_init ( struct dvb_frontend * fe )
{
struct xc5000_priv * priv = fe - > tuner_priv ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2007-12-18 07:55:51 +03:00
2007-12-20 07:14:43 +03:00
if ( xc_load_fw_and_init_tuner ( fe ) ! = XC_RESULT_SUCCESS ) {
printk ( KERN_ERR " xc5000: Unable to initialise tuner \n " ) ;
return - EREMOTEIO ;
}
if ( debug )
xc_debug_dump ( priv ) ;
2007-12-18 07:55:51 +03:00
return 0 ;
}
static int xc5000_release ( struct dvb_frontend * fe )
{
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2007-12-18 07:55:51 +03:00
kfree ( fe - > tuner_priv ) ;
fe - > tuner_priv = NULL ;
return 0 ;
}
static const struct dvb_tuner_ops xc5000_tuner_ops = {
. info = {
. name = " Xceive XC5000 " ,
. frequency_min = 1000000 ,
. frequency_max = 1023000000 ,
. frequency_step = 50000 ,
} ,
2008-01-05 22:50:14 +03:00
. release = xc5000_release ,
. init = xc5000_init ,
. sleep = xc5000_sleep ,
2007-12-18 07:55:51 +03:00
2008-01-05 22:50:14 +03:00
. set_params = xc5000_set_params ,
. set_analog_params = xc5000_set_analog_params ,
. get_frequency = xc5000_get_frequency ,
. get_bandwidth = xc5000_get_bandwidth ,
. get_status = xc5000_get_status
2007-12-18 07:55:51 +03:00
} ;
2008-05-10 21:34:09 +04:00
struct dvb_frontend * xc5000_attach ( struct dvb_frontend * fe ,
struct i2c_adapter * i2c ,
struct xc5000_config * cfg , void * devptr )
2007-12-18 07:55:51 +03:00
{
struct xc5000_priv * priv = NULL ;
u16 id = 0 ;
2008-04-09 06:20:00 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2007-12-18 07:55:51 +03:00
priv = kzalloc ( sizeof ( struct xc5000_priv ) , GFP_KERNEL ) ;
if ( priv = = NULL )
return NULL ;
priv - > cfg = cfg ;
2007-12-20 07:14:43 +03:00
priv - > bandwidth = BANDWIDTH_6_MHZ ;
2007-12-18 07:55:51 +03:00
priv - > i2c = i2c ;
2008-05-10 21:34:09 +04:00
priv - > devptr = devptr ;
2007-12-18 07:55:51 +03:00
2008-01-05 22:50:14 +03:00
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware .
*/
2007-12-18 07:55:51 +03:00
if ( xc5000_readreg ( priv , XREG_PRODUCT_ID , & id ) ! = 0 ) {
kfree ( priv ) ;
return NULL ;
}
2008-01-05 22:50:14 +03:00
switch ( id ) {
case XC_PRODUCT_ID_FW_LOADED :
printk ( KERN_INFO
" xc5000: Successfully identified at address 0x%02x \n " ,
cfg - > i2c_address ) ;
printk ( KERN_INFO
" xc5000: Firmware has been loaded previously \n " ) ;
break ;
case XC_PRODUCT_ID_FW_NOT_LOADED :
printk ( KERN_INFO
" xc5000: Successfully identified at address 0x%02x \n " ,
cfg - > i2c_address ) ;
printk ( KERN_INFO
" xc5000: Firmware has not been loaded previously \n " ) ;
break ;
default :
2007-12-18 07:55:51 +03:00
printk ( KERN_ERR
" xc5000: Device not found at addr 0x%02x (0x%x) \n " ,
cfg - > i2c_address , id ) ;
kfree ( priv ) ;
return NULL ;
}
memcpy ( & fe - > ops . tuner_ops , & xc5000_tuner_ops ,
sizeof ( struct dvb_tuner_ops ) ) ;
fe - > tuner_priv = priv ;
2008-06-22 05:13:42 +04:00
if ( xc5000_load_fw_on_attach )
xc5000_init ( fe ) ;
2007-12-18 07:55:51 +03:00
return fe ;
}
EXPORT_SYMBOL ( xc5000_attach ) ;
MODULE_AUTHOR ( " Steven Toth " ) ;
2007-12-20 07:14:43 +03:00
MODULE_DESCRIPTION ( " Xceive xc5000 silicon tuner driver " ) ;
2007-12-18 07:55:51 +03:00
MODULE_LICENSE ( " GPL " ) ;