2005-04-17 02:20:36 +04:00
/*
Driver for Philips tda1004xh OFDM Demodulator
( c ) 2003 , 2004 Andrew de Quincey & Robert Schlabbach
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 .
*/
/*
* This driver needs external firmware . Please use the commands
* " <kerneldir>/Documentation/dvb/get_dvb_firmware tda10045 " ,
* " <kerneldir>/Documentation/dvb/get_dvb_firmware tda10046 " to
2006-01-09 20:25:38 +03:00
* download / extract them , and then copy them to / usr / lib / hotplug / firmware
* or / lib / firmware ( depending on configuration of firmware hotplug ) .
2005-04-17 02:20:36 +04:00
*/
# define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
# define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
# include <linux/init.h>
# include <linux/module.h>
# include <linux/device.h>
2005-10-31 02:03:48 +03:00
# include <linux/jiffies.h>
# include <linux/string.h>
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
# include "dvb_frontend.h"
# include "tda1004x.h"
static int debug ;
# define dprintk(args...) \
do { \
if ( debug ) printk ( KERN_DEBUG " tda1004x: " args ) ; \
} while ( 0 )
# define TDA1004X_CHIPID 0x00
# define TDA1004X_AUTO 0x01
# define TDA1004X_IN_CONF1 0x02
# define TDA1004X_IN_CONF2 0x03
# define TDA1004X_OUT_CONF1 0x04
# define TDA1004X_OUT_CONF2 0x05
# define TDA1004X_STATUS_CD 0x06
# define TDA1004X_CONFC4 0x07
# define TDA1004X_DSSPARE2 0x0C
# define TDA10045H_CODE_IN 0x0D
# define TDA10045H_FWPAGE 0x0E
# define TDA1004X_SCAN_CPT 0x10
# define TDA1004X_DSP_CMD 0x11
# define TDA1004X_DSP_ARG 0x12
# define TDA1004X_DSP_DATA1 0x13
# define TDA1004X_DSP_DATA2 0x14
# define TDA1004X_CONFADC1 0x15
# define TDA1004X_CONFC1 0x16
# define TDA10045H_S_AGC 0x1a
# define TDA10046H_AGC_TUN_LEVEL 0x1a
# define TDA1004X_SNR 0x1c
# define TDA1004X_CONF_TS1 0x1e
# define TDA1004X_CONF_TS2 0x1f
# define TDA1004X_CBER_RESET 0x20
# define TDA1004X_CBER_MSB 0x21
# define TDA1004X_CBER_LSB 0x22
# define TDA1004X_CVBER_LUT 0x23
# define TDA1004X_VBER_MSB 0x24
# define TDA1004X_VBER_MID 0x25
# define TDA1004X_VBER_LSB 0x26
# define TDA1004X_UNCOR 0x27
# define TDA10045H_CONFPLL_P 0x2D
# define TDA10045H_CONFPLL_M_MSB 0x2E
# define TDA10045H_CONFPLL_M_LSB 0x2F
# define TDA10045H_CONFPLL_N 0x30
# define TDA10046H_CONFPLL1 0x2D
# define TDA10046H_CONFPLL2 0x2F
# define TDA10046H_CONFPLL3 0x30
# define TDA10046H_TIME_WREF1 0x31
# define TDA10046H_TIME_WREF2 0x32
# define TDA10046H_TIME_WREF3 0x33
# define TDA10046H_TIME_WREF4 0x34
# define TDA10046H_TIME_WREF5 0x35
# define TDA10045H_UNSURW_MSB 0x31
# define TDA10045H_UNSURW_LSB 0x32
# define TDA10045H_WREF_MSB 0x33
# define TDA10045H_WREF_MID 0x34
# define TDA10045H_WREF_LSB 0x35
# define TDA10045H_MUXOUT 0x36
# define TDA1004X_CONFADC2 0x37
# define TDA10045H_IOFFSET 0x38
# define TDA10046H_CONF_TRISTATE1 0x3B
# define TDA10046H_CONF_TRISTATE2 0x3C
# define TDA10046H_CONF_POLARITY 0x3D
# define TDA10046H_FREQ_OFFSET 0x3E
# define TDA10046H_GPIO_OUT_SEL 0x41
# define TDA10046H_GPIO_SELECT 0x42
# define TDA10046H_AGC_CONF 0x43
2005-07-08 04:57:43 +04:00
# define TDA10046H_AGC_THR 0x44
# define TDA10046H_AGC_RENORM 0x45
2005-04-17 02:20:36 +04:00
# define TDA10046H_AGC_GAINS 0x46
# define TDA10046H_AGC_TUN_MIN 0x47
# define TDA10046H_AGC_TUN_MAX 0x48
# define TDA10046H_AGC_IF_MIN 0x49
# define TDA10046H_AGC_IF_MAX 0x4A
# define TDA10046H_FREQ_PHY2_MSB 0x4D
# define TDA10046H_FREQ_PHY2_LSB 0x4E
# define TDA10046H_CVBER_CTRL 0x4F
# define TDA10046H_AGC_IF_LEVEL 0x52
# define TDA10046H_CODE_CPT 0x57
# define TDA10046H_CODE_IN 0x58
static int tda1004x_write_byteI ( struct tda1004x_state * state , int reg , int data )
{
int ret ;
u8 buf [ ] = { reg , data } ;
2005-05-17 08:54:30 +04:00
struct i2c_msg msg = { . flags = 0 , . buf = buf , . len = 2 } ;
2005-04-17 02:20:36 +04:00
2008-04-09 06:20:00 +04:00
dprintk ( " %s: reg=0x%x, data=0x%x \n " , __func__ , reg , data ) ;
2005-04-17 02:20:36 +04:00
msg . addr = state - > config - > demod_address ;
ret = i2c_transfer ( state - > i2c , & msg , 1 ) ;
if ( ret ! = 1 )
dprintk ( " %s: error reg=0x%x, data=0x%x, ret=%i \n " ,
2008-04-09 06:20:00 +04:00
__func__ , reg , data , ret ) ;
2005-04-17 02:20:36 +04:00
2008-04-09 06:20:00 +04:00
dprintk ( " %s: success reg=0x%x, data=0x%x, ret=%i \n " , __func__ ,
2005-04-17 02:20:36 +04:00
reg , data , ret ) ;
return ( ret ! = 1 ) ? - 1 : 0 ;
}
static int tda1004x_read_byte ( struct tda1004x_state * state , int reg )
{
int ret ;
u8 b0 [ ] = { reg } ;
u8 b1 [ ] = { 0 } ;
2005-05-17 08:54:30 +04:00
struct i2c_msg msg [ ] = { { . flags = 0 , . buf = b0 , . len = 1 } ,
{ . flags = I2C_M_RD , . buf = b1 , . len = 1 } } ;
2005-04-17 02:20:36 +04:00
2008-04-09 06:20:00 +04:00
dprintk ( " %s: reg=0x%x \n " , __func__ , reg ) ;
2005-04-17 02:20:36 +04:00
msg [ 0 ] . addr = state - > config - > demod_address ;
msg [ 1 ] . addr = state - > config - > demod_address ;
ret = i2c_transfer ( state - > i2c , msg , 2 ) ;
if ( ret ! = 2 ) {
2008-04-09 06:20:00 +04:00
dprintk ( " %s: error reg=0x%x, ret=%i \n " , __func__ , reg ,
2005-04-17 02:20:36 +04:00
ret ) ;
2009-02-09 19:12:41 +03:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2008-04-09 06:20:00 +04:00
dprintk ( " %s: success reg=0x%x, data=0x%x, ret=%i \n " , __func__ ,
2005-04-17 02:20:36 +04:00
reg , b1 [ 0 ] , ret ) ;
return b1 [ 0 ] ;
}
static int tda1004x_write_mask ( struct tda1004x_state * state , int reg , int mask , int data )
{
int val ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s: reg=0x%x, mask=0x%x, data=0x%x \n " , __func__ , reg ,
2005-04-17 02:20:36 +04:00
mask , data ) ;
// read a byte and check
val = tda1004x_read_byte ( state , reg ) ;
if ( val < 0 )
return val ;
// mask if off
val = val & ~ mask ;
val | = data & 0xff ;
// write it out again
return tda1004x_write_byteI ( state , reg , val ) ;
}
static int tda1004x_write_buf ( struct tda1004x_state * state , int reg , unsigned char * buf , int len )
{
int i ;
int result ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s: reg=0x%x, len=0x%x \n " , __func__ , reg , len ) ;
2005-04-17 02:20:36 +04:00
result = 0 ;
for ( i = 0 ; i < len ; i + + ) {
result = tda1004x_write_byteI ( state , reg + i , buf [ i ] ) ;
if ( result ! = 0 )
break ;
}
return result ;
}
static int tda1004x_enable_tuner_i2c ( struct tda1004x_state * state )
{
int result ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
result = tda1004x_write_mask ( state , TDA1004X_CONFC4 , 2 , 2 ) ;
2006-02-07 11:49:10 +03:00
msleep ( 20 ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
static int tda1004x_disable_tuner_i2c ( struct tda1004x_state * state )
{
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return tda1004x_write_mask ( state , TDA1004X_CONFC4 , 2 , 0 ) ;
}
static int tda10045h_set_bandwidth ( struct tda1004x_state * state ,
2011-12-26 20:19:48 +04:00
u32 bandwidth )
2005-04-17 02:20:36 +04:00
{
static u8 bandwidth_6mhz [ ] = { 0x02 , 0x00 , 0x3d , 0x00 , 0x60 , 0x1e , 0xa7 , 0x45 , 0x4f } ;
static u8 bandwidth_7mhz [ ] = { 0x02 , 0x00 , 0x37 , 0x00 , 0x4a , 0x2f , 0x6d , 0x76 , 0xdb } ;
static u8 bandwidth_8mhz [ ] = { 0x02 , 0x00 , 0x3d , 0x00 , 0x48 , 0x17 , 0x89 , 0xc7 , 0x14 } ;
switch ( bandwidth ) {
2011-12-26 20:19:48 +04:00
case 6000000 :
2005-04-17 02:20:36 +04:00
tda1004x_write_buf ( state , TDA10045H_CONFPLL_P , bandwidth_6mhz , sizeof ( bandwidth_6mhz ) ) ;
break ;
2011-12-26 20:19:48 +04:00
case 7000000 :
2005-04-17 02:20:36 +04:00
tda1004x_write_buf ( state , TDA10045H_CONFPLL_P , bandwidth_7mhz , sizeof ( bandwidth_7mhz ) ) ;
break ;
2011-12-26 20:19:48 +04:00
case 8000000 :
2005-04-17 02:20:36 +04:00
tda1004x_write_buf ( state , TDA10045H_CONFPLL_P , bandwidth_8mhz , sizeof ( bandwidth_8mhz ) ) ;
break ;
default :
return - EINVAL ;
}
tda1004x_write_byteI ( state , TDA10045H_IOFFSET , 0 ) ;
return 0 ;
}
static int tda10046h_set_bandwidth ( struct tda1004x_state * state ,
2011-12-26 20:19:48 +04:00
u32 bandwidth )
2005-04-17 02:20:36 +04:00
{
2006-01-09 20:25:04 +03:00
static u8 bandwidth_6mhz_53M [ ] = { 0x7b , 0x2e , 0x11 , 0xf0 , 0xd2 } ;
static u8 bandwidth_7mhz_53M [ ] = { 0x6a , 0x02 , 0x6a , 0x43 , 0x9f } ;
static u8 bandwidth_8mhz_53M [ ] = { 0x5c , 0x32 , 0xc2 , 0x96 , 0x6d } ;
static u8 bandwidth_6mhz_48M [ ] = { 0x70 , 0x02 , 0x49 , 0x24 , 0x92 } ;
static u8 bandwidth_7mhz_48M [ ] = { 0x60 , 0x02 , 0xaa , 0xaa , 0xab } ;
static u8 bandwidth_8mhz_48M [ ] = { 0x54 , 0x03 , 0x0c , 0x30 , 0xc3 } ;
int tda10046_clk53m ;
if ( ( state - > config - > if_freq = = TDA10046_FREQ_045 ) | |
( state - > config - > if_freq = = TDA10046_FREQ_052 ) )
tda10046_clk53m = 0 ;
else
tda10046_clk53m = 1 ;
2005-04-17 02:20:36 +04:00
switch ( bandwidth ) {
2011-12-26 20:19:48 +04:00
case 6000000 :
2006-01-09 20:25:04 +03:00
if ( tda10046_clk53m )
tda1004x_write_buf ( state , TDA10046H_TIME_WREF1 , bandwidth_6mhz_53M ,
2006-01-09 20:25:34 +03:00
sizeof ( bandwidth_6mhz_53M ) ) ;
2006-01-09 20:25:04 +03:00
else
tda1004x_write_buf ( state , TDA10046H_TIME_WREF1 , bandwidth_6mhz_48M ,
2006-01-09 20:25:34 +03:00
sizeof ( bandwidth_6mhz_48M ) ) ;
2005-07-08 04:57:43 +04:00
if ( state - > config - > if_freq = = TDA10046_FREQ_045 ) {
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_MSB , 0x0a ) ;
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_LSB , 0xab ) ;
2005-07-08 04:57:43 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
2011-12-26 20:19:48 +04:00
case 7000000 :
2006-01-09 20:25:04 +03:00
if ( tda10046_clk53m )
tda1004x_write_buf ( state , TDA10046H_TIME_WREF1 , bandwidth_7mhz_53M ,
2006-01-09 20:25:34 +03:00
sizeof ( bandwidth_7mhz_53M ) ) ;
2006-01-09 20:25:04 +03:00
else
tda1004x_write_buf ( state , TDA10046H_TIME_WREF1 , bandwidth_7mhz_48M ,
2006-01-09 20:25:34 +03:00
sizeof ( bandwidth_7mhz_48M ) ) ;
2005-07-08 04:57:43 +04:00
if ( state - > config - > if_freq = = TDA10046_FREQ_045 ) {
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_MSB , 0x0c ) ;
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_LSB , 0x00 ) ;
2005-07-08 04:57:43 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
2011-12-26 20:19:48 +04:00
case 8000000 :
2006-01-09 20:25:04 +03:00
if ( tda10046_clk53m )
tda1004x_write_buf ( state , TDA10046H_TIME_WREF1 , bandwidth_8mhz_53M ,
2006-01-09 20:25:34 +03:00
sizeof ( bandwidth_8mhz_53M ) ) ;
2006-01-09 20:25:04 +03:00
else
tda1004x_write_buf ( state , TDA10046H_TIME_WREF1 , bandwidth_8mhz_48M ,
2006-01-09 20:25:34 +03:00
sizeof ( bandwidth_8mhz_48M ) ) ;
2005-07-08 04:57:43 +04:00
if ( state - > config - > if_freq = = TDA10046_FREQ_045 ) {
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_MSB , 0x0d ) ;
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_LSB , 0x55 ) ;
2005-07-08 04:57:43 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int tda1004x_do_upload ( struct tda1004x_state * state ,
2008-05-24 03:12:23 +04:00
const unsigned char * mem , unsigned int len ,
2005-04-17 02:20:36 +04:00
u8 dspCodeCounterReg , u8 dspCodeInReg )
{
u8 buf [ 65 ] ;
2005-05-17 08:54:30 +04:00
struct i2c_msg fw_msg = { . flags = 0 , . buf = buf , . len = 0 } ;
2005-04-17 02:20:36 +04:00
int tx_size ;
int pos = 0 ;
/* clear code counter */
tda1004x_write_byteI ( state , dspCodeCounterReg , 0 ) ;
fw_msg . addr = state - > config - > demod_address ;
2012-09-28 23:28:51 +04:00
i2c_lock_adapter ( state - > i2c ) ;
2005-04-17 02:20:36 +04:00
buf [ 0 ] = dspCodeInReg ;
while ( pos ! = len ) {
// work out how much to send this time
tx_size = len - pos ;
2005-05-17 08:54:30 +04:00
if ( tx_size > 0x10 )
2005-04-17 02:20:36 +04:00
tx_size = 0x10 ;
// send the chunk
memcpy ( buf + 1 , mem + pos , tx_size ) ;
fw_msg . len = tx_size + 1 ;
2012-09-28 23:28:51 +04:00
if ( __i2c_transfer ( state - > i2c , & fw_msg , 1 ) ! = 1 ) {
2005-07-08 04:57:40 +04:00
printk ( KERN_ERR " tda1004x: Error during firmware upload \n " ) ;
2012-09-28 23:28:51 +04:00
i2c_unlock_adapter ( state - > i2c ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
}
pos + = tx_size ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s: fw_pos=0x%x \n " , __func__ , pos ) ;
2005-04-17 02:20:36 +04:00
}
2012-09-28 23:28:51 +04:00
i2c_unlock_adapter ( state - > i2c ) ;
/* give the DSP a chance to settle 03/10/05 Hac */
2005-07-08 04:57:40 +04:00
msleep ( 100 ) ;
2005-05-17 08:54:30 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-07-08 04:57:40 +04:00
static int tda1004x_check_upload_ok ( struct tda1004x_state * state )
2005-04-17 02:20:36 +04:00
{
u8 data1 , data2 ;
2005-07-08 04:57:40 +04:00
unsigned long timeout ;
if ( state - > demod_type = = TDA1004X_DEMOD_TDA10046 ) {
timeout = jiffies + 2 * HZ ;
while ( ! ( tda1004x_read_byte ( state , TDA1004X_STATUS_CD ) & 0x20 ) ) {
if ( time_after ( jiffies , timeout ) ) {
printk ( KERN_ERR " tda1004x: timeout waiting for DSP ready \n " ) ;
break ;
}
msleep ( 1 ) ;
}
} else
msleep ( 100 ) ;
2005-04-17 02:20:36 +04:00
// check upload was OK
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 0x10 , 0 ) ; // we want to read from the DSP
tda1004x_write_byteI ( state , TDA1004X_DSP_CMD , 0x67 ) ;
data1 = tda1004x_read_byte ( state , TDA1004X_DSP_DATA1 ) ;
data2 = tda1004x_read_byte ( state , TDA1004X_DSP_DATA2 ) ;
2005-07-08 04:57:42 +04:00
if ( data1 ! = 0x67 | | data2 < 0x20 | | data2 > 0x2e ) {
2005-07-08 04:57:40 +04:00
printk ( KERN_INFO " tda1004x: found firmware revision %x -- invalid \n " , data2 ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
2005-07-08 04:57:40 +04:00
}
printk ( KERN_INFO " tda1004x: found firmware revision %x -- ok \n " , data2 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int tda10045_fwupload ( struct dvb_frontend * fe )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
int ret ;
const struct firmware * fw ;
/* don't re-upload unless necessary */
2005-07-08 04:57:40 +04:00
if ( tda1004x_check_upload_ok ( state ) = = 0 )
2005-05-17 08:54:30 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/* request the firmware, this will block until someone uploads it */
2005-07-08 04:57:40 +04:00
printk ( KERN_INFO " tda1004x: waiting for firmware upload (%s)... \n " , TDA10045_DEFAULT_FIRMWARE ) ;
2005-04-17 02:20:36 +04:00
ret = state - > config - > request_firmware ( fe , & fw , TDA10045_DEFAULT_FIRMWARE ) ;
if ( ret ) {
2005-07-08 04:57:40 +04:00
printk ( KERN_ERR " tda1004x: no firmware upload (timeout or file not found?) \n " ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
/* reset chip */
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 0x10 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 8 , 8 ) ;
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 8 , 0 ) ;
msleep ( 10 ) ;
/* set parameters */
2011-12-26 20:19:48 +04:00
tda10045h_set_bandwidth ( state , 8000000 ) ;
2005-04-17 02:20:36 +04:00
ret = tda1004x_do_upload ( state , fw - > data , fw - > size , TDA10045H_FWPAGE , TDA10045H_CODE_IN ) ;
2005-07-08 04:57:42 +04:00
release_firmware ( fw ) ;
2005-04-17 02:20:36 +04:00
if ( ret )
return ret ;
2005-07-08 04:57:40 +04:00
printk ( KERN_INFO " tda1004x: firmware upload complete \n " ) ;
2005-04-17 02:20:36 +04:00
/* wait for DSP to initialise */
/* DSPREADY doesn't seem to work on the TDA10045H */
msleep ( 100 ) ;
2005-07-08 04:57:40 +04:00
return tda1004x_check_upload_ok ( state ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:40 +04:00
static void tda10046_init_plls ( struct dvb_frontend * fe )
2005-05-17 08:54:36 +04:00
{
2005-07-08 04:57:40 +04:00
struct tda1004x_state * state = fe - > demodulator_priv ;
2006-01-09 20:25:04 +03:00
int tda10046_clk53m ;
if ( ( state - > config - > if_freq = = TDA10046_FREQ_045 ) | |
( state - > config - > if_freq = = TDA10046_FREQ_052 ) )
tda10046_clk53m = 0 ;
else
tda10046_clk53m = 1 ;
2005-05-17 08:54:36 +04:00
2005-07-08 04:57:40 +04:00
tda1004x_write_byteI ( state , TDA10046H_CONFPLL1 , 0xf0 ) ;
2006-01-09 20:25:04 +03:00
if ( tda10046_clk53m ) {
printk ( KERN_INFO " tda1004x: setting up plls for 53MHz sampling clock \n " ) ;
tda1004x_write_byteI ( state , TDA10046H_CONFPLL2 , 0x08 ) ; // PLL M = 8
} else {
printk ( KERN_INFO " tda1004x: setting up plls for 48MHz sampling clock \n " ) ;
tda1004x_write_byteI ( state , TDA10046H_CONFPLL2 , 0x03 ) ; // PLL M = 3
}
2005-07-08 04:57:40 +04:00
if ( state - > config - > xtal_freq = = TDA10046_XTAL_4M ) {
2008-04-09 06:20:00 +04:00
dprintk ( " %s: setting up PLLs for a 4 MHz Xtal \n " , __func__ ) ;
2005-07-08 04:57:40 +04:00
tda1004x_write_byteI ( state , TDA10046H_CONFPLL3 , 0 ) ; // PLL P = N = 0
} else {
2008-04-09 06:20:00 +04:00
dprintk ( " %s: setting up PLLs for a 16 MHz Xtal \n " , __func__ ) ;
2005-07-08 04:57:40 +04:00
tda1004x_write_byteI ( state , TDA10046H_CONFPLL3 , 3 ) ; // PLL P = 0, N = 3
}
2006-01-09 20:25:04 +03:00
if ( tda10046_clk53m )
tda1004x_write_byteI ( state , TDA10046H_FREQ_OFFSET , 0x67 ) ;
else
tda1004x_write_byteI ( state , TDA10046H_FREQ_OFFSET , 0x72 ) ;
/* Note clock frequency is handled implicitly */
2005-07-08 04:57:40 +04:00
switch ( state - > config - > if_freq ) {
2005-07-08 04:57:43 +04:00
case TDA10046_FREQ_045 :
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_MSB , 0x0c ) ;
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_LSB , 0x00 ) ;
2005-07-08 04:57:43 +04:00
break ;
case TDA10046_FREQ_052 :
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_MSB , 0x0d ) ;
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_LSB , 0xc7 ) ;
break ;
case TDA10046_FREQ_3617 :
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_MSB , 0xd7 ) ;
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_LSB , 0x59 ) ;
break ;
case TDA10046_FREQ_3613 :
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_MSB , 0xd7 ) ;
tda1004x_write_byteI ( state , TDA10046H_FREQ_PHY2_LSB , 0x3f ) ;
2005-07-08 04:57:43 +04:00
break ;
2005-07-08 04:57:40 +04:00
}
2011-12-26 20:19:48 +04:00
tda10046h_set_bandwidth ( state , 8000000 ) ; /* default bandwidth 8 MHz */
2006-01-09 20:25:04 +03:00
/* let the PLLs settle */
msleep ( 120 ) ;
2005-05-17 08:54:36 +04:00
}
2005-04-17 02:20:36 +04:00
static int tda10046_fwupload ( struct dvb_frontend * fe )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
2009-02-09 19:12:41 +03:00
int ret , confc4 ;
2005-04-17 02:20:36 +04:00
const struct firmware * fw ;
/* reset + wake up chip */
2006-02-07 11:49:10 +03:00
if ( state - > config - > xtal_freq = = TDA10046_XTAL_4M ) {
2009-02-09 19:12:41 +03:00
confc4 = 0 ;
2006-02-07 11:49:10 +03:00
} else {
2008-04-09 06:20:00 +04:00
dprintk ( " %s: 16MHz Xtal, reducing I2C speed \n " , __func__ ) ;
2009-02-09 19:12:41 +03:00
confc4 = 0x80 ;
2006-02-07 11:49:10 +03:00
}
2009-02-09 19:12:41 +03:00
tda1004x_write_byteI ( state , TDA1004X_CONFC4 , confc4 ) ;
2005-04-17 02:20:36 +04:00
tda1004x_write_mask ( state , TDA10046H_CONF_TRISTATE1 , 1 , 0 ) ;
2007-04-27 19:31:10 +04:00
/* set GPIO 1 and 3 */
if ( state - > config - > gpio_config ! = TDA10046_GPTRI ) {
tda1004x_write_byteI ( state , TDA10046H_CONF_TRISTATE2 , 0x33 ) ;
tda1004x_write_mask ( state , TDA10046H_CONF_POLARITY , 0x0f , state - > config - > gpio_config & 0x0f ) ;
}
2005-07-08 04:57:40 +04:00
/* let the clocks recover from sleep */
2007-04-27 19:31:10 +04:00
msleep ( 10 ) ;
2005-04-17 02:20:36 +04:00
2006-01-09 20:25:04 +03:00
/* The PLLs need to be reprogrammed after sleep */
tda10046_init_plls ( fe ) ;
2007-04-27 19:31:15 +04:00
tda1004x_write_mask ( state , TDA1004X_CONFADC2 , 0xc0 , 0 ) ;
2006-01-09 20:25:04 +03:00
2005-04-17 02:20:36 +04:00
/* don't re-upload unless necessary */
2005-07-08 04:57:40 +04:00
if ( tda1004x_check_upload_ok ( state ) = = 0 )
2005-05-17 08:54:30 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2009-02-09 19:12:41 +03:00
/*
For i2c normal work , we need to slow down the bus speed .
However , the slow down breaks the eeprom firmware load .
So , use normal speed for eeprom booting and then restore the
i2c speed after that . Tested with MSI TV @ nyware A / D board ,
that comes with firmware version 29 inside their eeprom .
It should also be noticed that no other I2C transfer should
be in course while booting from eeprom , otherwise , tda10046
goes into an instable state . So , proper locking are needed
at the i2c bus master .
*/
2007-04-27 19:31:10 +04:00
printk ( KERN_INFO " tda1004x: trying to boot from eeprom \n " ) ;
2009-02-09 19:12:41 +03:00
tda1004x_write_byteI ( state , TDA1004X_CONFC4 , 4 ) ;
2007-04-27 19:31:10 +04:00
msleep ( 300 ) ;
2009-02-09 19:12:41 +03:00
tda1004x_write_byteI ( state , TDA1004X_CONFC4 , confc4 ) ;
/* Checks if eeprom firmware went without troubles */
2007-04-27 19:31:10 +04:00
if ( tda1004x_check_upload_ok ( state ) = = 0 )
return 0 ;
2009-02-09 19:12:41 +03:00
/* eeprom firmware didn't work. Load one manually. */
2007-04-27 19:31:13 +04:00
if ( state - > config - > request_firmware ! = NULL ) {
/* request the firmware, this will block until someone uploads it */
printk ( KERN_INFO " tda1004x: waiting for firmware upload... \n " ) ;
ret = state - > config - > request_firmware ( fe , & fw , TDA10046_DEFAULT_FIRMWARE ) ;
2005-07-08 04:57:40 +04:00
if ( ret ) {
2007-04-27 19:31:13 +04:00
/* remain compatible to old bug: try to load with tda10045 image name */
ret = state - > config - > request_firmware ( fe , & fw , TDA10045_DEFAULT_FIRMWARE ) ;
if ( ret ) {
printk ( KERN_ERR " tda1004x: no firmware upload (timeout or file not found?) \n " ) ;
return ret ;
} else {
printk ( KERN_INFO " tda1004x: please rename the firmware file to %s \n " ,
TDA10046_DEFAULT_FIRMWARE ) ;
}
}
} else {
printk ( KERN_ERR " tda1004x: no request function defined, can't upload from file \n " ) ;
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2007-04-27 19:31:10 +04:00
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 8 , 8 ) ; // going to boot from HOST
ret = tda1004x_do_upload ( state , fw - > data , fw - > size , TDA10046H_CODE_CPT , TDA10046H_CODE_IN ) ;
release_firmware ( fw ) ;
2005-07-08 04:57:40 +04:00
return tda1004x_check_upload_ok ( state ) ;
2005-04-17 02:20:36 +04:00
}
static int tda1004x_encode_fec ( int fec )
{
// convert known FEC values
switch ( fec ) {
case FEC_1_2 :
return 0 ;
case FEC_2_3 :
return 1 ;
case FEC_3_4 :
return 2 ;
case FEC_5_6 :
return 3 ;
case FEC_7_8 :
return 4 ;
}
// unsupported
return - EINVAL ;
}
static int tda1004x_decode_fec ( int tdafec )
{
// convert known FEC values
switch ( tdafec ) {
case 0 :
return FEC_1_2 ;
case 1 :
return FEC_2_3 ;
case 2 :
return FEC_3_4 ;
case 3 :
return FEC_5_6 ;
case 4 :
return FEC_7_8 ;
}
// unsupported
return - 1 ;
}
2010-08-25 16:50:20 +04:00
static int tda1004x_write ( struct dvb_frontend * fe , const u8 buf [ ] , int len )
2005-04-17 02:20:36 +04:00
{
struct tda1004x_state * state = fe - > demodulator_priv ;
2006-08-08 16:10:08 +04:00
if ( len ! = 2 )
return - EINVAL ;
return tda1004x_write_byteI ( state , buf [ 0 ] , buf [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
}
static int tda10045_init ( struct dvb_frontend * fe )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( tda10045_fwupload ( fe ) ) {
printk ( " tda1004x: firmware upload failed \n " ) ;
return - EIO ;
}
tda1004x_write_mask ( state , TDA1004X_CONFADC1 , 0x10 , 0 ) ; // wake up the ADC
// tda setup
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 0x20 , 0 ) ; // disable DSP watchdog timer
tda1004x_write_mask ( state , TDA1004X_AUTO , 8 , 0 ) ; // select HP stream
tda1004x_write_mask ( state , TDA1004X_CONFC1 , 0x40 , 0 ) ; // set polarity of VAGC signal
tda1004x_write_mask ( state , TDA1004X_CONFC1 , 0x80 , 0x80 ) ; // enable pulse killer
tda1004x_write_mask ( state , TDA1004X_AUTO , 0x10 , 0x10 ) ; // enable auto offset
tda1004x_write_mask ( state , TDA1004X_IN_CONF2 , 0xC0 , 0x0 ) ; // no frequency offset
tda1004x_write_byteI ( state , TDA1004X_CONF_TS1 , 0 ) ; // setup MPEG2 TS interface
tda1004x_write_byteI ( state , TDA1004X_CONF_TS2 , 0 ) ; // setup MPEG2 TS interface
tda1004x_write_mask ( state , TDA1004X_VBER_MSB , 0xe0 , 0xa0 ) ; // 10^6 VBER measurement bits
tda1004x_write_mask ( state , TDA1004X_CONFC1 , 0x10 , 0 ) ; // VAGC polarity
tda1004x_write_byteI ( state , TDA1004X_CONFADC1 , 0x2e ) ;
tda1004x_write_mask ( state , 0x1f , 0x01 , state - > config - > invert_oclk ) ;
return 0 ;
}
static int tda10046_init ( struct dvb_frontend * fe )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( tda10046_fwupload ( fe ) ) {
printk ( " tda1004x: firmware upload failed \n " ) ;
2005-07-08 04:57:40 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
// tda setup
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 0x20 , 0 ) ; // disable DSP watchdog timer
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA1004X_AUTO , 0x87 ) ; // 100 ppm crystal, select HP stream
2006-02-07 11:49:10 +03:00
tda1004x_write_byteI ( state , TDA1004X_CONFC1 , 0x88 ) ; // enable pulse killer
2005-07-08 04:57:40 +04:00
switch ( state - > config - > agc_config ) {
case TDA10046_AGC_DEFAULT :
tda1004x_write_byteI ( state , TDA10046H_AGC_CONF , 0x00 ) ; // AGC setup
2007-04-27 19:31:10 +04:00
tda1004x_write_mask ( state , TDA10046H_CONF_POLARITY , 0xf0 , 0x60 ) ; // set AGC polarities
2005-07-08 04:57:40 +04:00
break ;
case TDA10046_AGC_IFO_AUTO_NEG :
tda1004x_write_byteI ( state , TDA10046H_AGC_CONF , 0x0a ) ; // AGC setup
2007-04-27 19:31:10 +04:00
tda1004x_write_mask ( state , TDA10046H_CONF_POLARITY , 0xf0 , 0x60 ) ; // set AGC polarities
2005-07-08 04:57:40 +04:00
break ;
2005-07-08 04:57:43 +04:00
case TDA10046_AGC_IFO_AUTO_POS :
tda1004x_write_byteI ( state , TDA10046H_AGC_CONF , 0x0a ) ; // AGC setup
2007-04-27 19:31:10 +04:00
tda1004x_write_mask ( state , TDA10046H_CONF_POLARITY , 0xf0 , 0x00 ) ; // set AGC polarities
2006-02-07 11:49:10 +03:00
break ;
2007-04-27 19:31:10 +04:00
case TDA10046_AGC_TDA827X :
2006-11-16 03:31:54 +03:00
tda1004x_write_byteI ( state , TDA10046H_AGC_CONF , 0x02 ) ; // AGC setup
tda1004x_write_byteI ( state , TDA10046H_AGC_THR , 0x70 ) ; // AGC Threshold
tda1004x_write_byteI ( state , TDA10046H_AGC_RENORM , 0x08 ) ; // Gain Renormalize
2007-04-27 19:31:10 +04:00
tda1004x_write_mask ( state , TDA10046H_CONF_POLARITY , 0xf0 , 0x60 ) ; // set AGC polarities
2006-11-16 03:31:54 +03:00
break ;
2005-07-08 04:57:40 +04:00
}
2007-03-19 01:23:20 +03:00
if ( state - > config - > ts_mode = = 0 ) {
tda1004x_write_mask ( state , TDA10046H_CONF_TRISTATE1 , 0xc0 , 0x40 ) ;
tda1004x_write_mask ( state , 0x3a , 0x80 , state - > config - > invert_oclk < < 7 ) ;
} else {
tda1004x_write_mask ( state , TDA10046H_CONF_TRISTATE1 , 0xc0 , 0x80 ) ;
tda1004x_write_mask ( state , TDA10046H_CONF_POLARITY , 0x10 ,
state - > config - > invert_oclk < < 4 ) ;
}
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA1004X_CONFADC2 , 0x38 ) ;
2007-03-19 01:23:20 +03:00
tda1004x_write_mask ( state , TDA10046H_CONF_TRISTATE1 , 0x3e , 0x38 ) ; // Turn IF AGC output on
2005-04-17 02:20:36 +04:00
tda1004x_write_byteI ( state , TDA10046H_AGC_TUN_MIN , 0 ) ; // }
tda1004x_write_byteI ( state , TDA10046H_AGC_TUN_MAX , 0xff ) ; // } AGC min/max values
tda1004x_write_byteI ( state , TDA10046H_AGC_IF_MIN , 0 ) ; // }
tda1004x_write_byteI ( state , TDA10046H_AGC_IF_MAX , 0xff ) ; // }
2006-01-09 20:25:04 +03:00
tda1004x_write_byteI ( state , TDA10046H_AGC_GAINS , 0x12 ) ; // IF gain 2, TUN gain 1
2005-07-08 04:57:40 +04:00
tda1004x_write_byteI ( state , TDA10046H_CVBER_CTRL , 0x1a ) ; // 10^6 VBER measurement bits
2005-04-17 02:20:36 +04:00
tda1004x_write_byteI ( state , TDA1004X_CONF_TS1 , 7 ) ; // MPEG2 interface config
2005-07-08 04:57:40 +04:00
tda1004x_write_byteI ( state , TDA1004X_CONF_TS2 , 0xc0 ) ; // MPEG2 interface config
2006-02-07 11:49:10 +03:00
// tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes
2005-07-08 04:57:40 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-12-26 20:19:48 +04:00
static int tda1004x_set_fe ( struct dvb_frontend * fe )
2005-04-17 02:20:36 +04:00
{
2011-12-26 20:19:48 +04:00
struct dtv_frontend_properties * fe_params = & fe - > dtv_property_cache ;
2005-04-17 02:20:36 +04:00
struct tda1004x_state * state = fe - > demodulator_priv ;
int tmp ;
int inversion ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( state - > demod_type = = TDA1004X_DEMOD_TDA10046 ) {
// setup auto offset
tda1004x_write_mask ( state , TDA1004X_AUTO , 0x10 , 0x10 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x80 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF2 , 0xC0 , 0 ) ;
// disable agc_conf[2]
tda1004x_write_mask ( state , TDA10046H_AGC_CONF , 4 , 0 ) ;
}
// set frequency
2006-05-14 12:01:31 +04:00
if ( fe - > ops . tuner_ops . set_params ) {
2011-12-24 19:24:33 +04:00
fe - > ops . tuner_ops . set_params ( fe ) ;
2007-04-27 19:31:32 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 0 ) ;
2005-11-09 08:35:13 +03:00
}
2005-04-17 02:20:36 +04:00
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
if ( state - > demod_type = = TDA1004X_DEMOD_TDA10045 ) {
2011-12-26 20:19:48 +04:00
fe_params - > code_rate_HP = FEC_AUTO ;
fe_params - > guard_interval = GUARD_INTERVAL_AUTO ;
fe_params - > transmission_mode = TRANSMISSION_MODE_AUTO ;
2005-04-17 02:20:36 +04:00
}
// Set standard params.. or put them to auto
2011-12-26 20:19:48 +04:00
if ( ( fe_params - > code_rate_HP = = FEC_AUTO ) | |
( fe_params - > code_rate_LP = = FEC_AUTO ) | |
( fe_params - > modulation = = QAM_AUTO ) | |
( fe_params - > hierarchy = = HIERARCHY_AUTO ) ) {
2005-04-17 02:20:36 +04:00
tda1004x_write_mask ( state , TDA1004X_AUTO , 1 , 1 ) ; // enable auto
2011-12-26 20:19:48 +04:00
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x03 , 0 ) ; /* turn off modulation bits */
2005-04-17 02:20:36 +04:00
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x60 , 0 ) ; // turn off hierarchy bits
tda1004x_write_mask ( state , TDA1004X_IN_CONF2 , 0x3f , 0 ) ; // turn off FEC bits
} else {
tda1004x_write_mask ( state , TDA1004X_AUTO , 1 , 0 ) ; // disable auto
// set HP FEC
2011-12-26 20:19:48 +04:00
tmp = tda1004x_encode_fec ( fe_params - > code_rate_HP ) ;
2005-05-17 08:54:30 +04:00
if ( tmp < 0 )
return tmp ;
2005-04-17 02:20:36 +04:00
tda1004x_write_mask ( state , TDA1004X_IN_CONF2 , 7 , tmp ) ;
// set LP FEC
2011-12-26 20:19:48 +04:00
tmp = tda1004x_encode_fec ( fe_params - > code_rate_LP ) ;
2005-05-17 08:54:30 +04:00
if ( tmp < 0 )
return tmp ;
2005-04-17 02:20:36 +04:00
tda1004x_write_mask ( state , TDA1004X_IN_CONF2 , 0x38 , tmp < < 3 ) ;
2011-12-26 20:19:48 +04:00
/* set modulation */
switch ( fe_params - > modulation ) {
2005-04-17 02:20:36 +04:00
case QPSK :
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 3 , 0 ) ;
break ;
case QAM_16 :
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 3 , 1 ) ;
break ;
case QAM_64 :
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 3 , 2 ) ;
break ;
default :
return - EINVAL ;
}
// set hierarchy
2011-12-26 20:19:48 +04:00
switch ( fe_params - > hierarchy ) {
2005-04-17 02:20:36 +04:00
case HIERARCHY_NONE :
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x60 , 0 < < 5 ) ;
break ;
case HIERARCHY_1 :
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x60 , 1 < < 5 ) ;
break ;
case HIERARCHY_2 :
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x60 , 2 < < 5 ) ;
break ;
case HIERARCHY_4 :
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x60 , 3 < < 5 ) ;
break ;
default :
return - EINVAL ;
}
}
// set bandwidth
2005-05-17 08:54:30 +04:00
switch ( state - > demod_type ) {
2005-04-17 02:20:36 +04:00
case TDA1004X_DEMOD_TDA10045 :
2011-12-26 20:19:48 +04:00
tda10045h_set_bandwidth ( state , fe_params - > bandwidth_hz ) ;
2005-04-17 02:20:36 +04:00
break ;
case TDA1004X_DEMOD_TDA10046 :
2011-12-26 20:19:48 +04:00
tda10046h_set_bandwidth ( state , fe_params - > bandwidth_hz ) ;
2005-04-17 02:20:36 +04:00
break ;
}
// set inversion
inversion = fe_params - > inversion ;
2005-05-17 08:54:30 +04:00
if ( state - > config - > invert )
inversion = inversion ? INVERSION_OFF : INVERSION_ON ;
2005-04-17 02:20:36 +04:00
switch ( inversion ) {
case INVERSION_OFF :
tda1004x_write_mask ( state , TDA1004X_CONFC1 , 0x20 , 0 ) ;
break ;
case INVERSION_ON :
tda1004x_write_mask ( state , TDA1004X_CONFC1 , 0x20 , 0x20 ) ;
break ;
default :
return - EINVAL ;
}
// set guard interval
2011-12-26 20:19:48 +04:00
switch ( fe_params - > guard_interval ) {
2005-04-17 02:20:36 +04:00
case GUARD_INTERVAL_1_32 :
tda1004x_write_mask ( state , TDA1004X_AUTO , 2 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x0c , 0 < < 2 ) ;
break ;
case GUARD_INTERVAL_1_16 :
tda1004x_write_mask ( state , TDA1004X_AUTO , 2 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x0c , 1 < < 2 ) ;
break ;
case GUARD_INTERVAL_1_8 :
tda1004x_write_mask ( state , TDA1004X_AUTO , 2 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x0c , 2 < < 2 ) ;
break ;
case GUARD_INTERVAL_1_4 :
tda1004x_write_mask ( state , TDA1004X_AUTO , 2 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x0c , 3 < < 2 ) ;
break ;
case GUARD_INTERVAL_AUTO :
tda1004x_write_mask ( state , TDA1004X_AUTO , 2 , 2 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x0c , 0 < < 2 ) ;
break ;
default :
return - EINVAL ;
}
// set transmission mode
2011-12-26 20:19:48 +04:00
switch ( fe_params - > transmission_mode ) {
2005-04-17 02:20:36 +04:00
case TRANSMISSION_MODE_2K :
tda1004x_write_mask ( state , TDA1004X_AUTO , 4 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x10 , 0 < < 4 ) ;
break ;
case TRANSMISSION_MODE_8K :
tda1004x_write_mask ( state , TDA1004X_AUTO , 4 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x10 , 1 < < 4 ) ;
break ;
case TRANSMISSION_MODE_AUTO :
tda1004x_write_mask ( state , TDA1004X_AUTO , 4 , 4 ) ;
tda1004x_write_mask ( state , TDA1004X_IN_CONF1 , 0x10 , 0 ) ;
break ;
default :
return - EINVAL ;
}
// start the lock
2005-05-17 08:54:30 +04:00
switch ( state - > demod_type ) {
2005-04-17 02:20:36 +04:00
case TDA1004X_DEMOD_TDA10045 :
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 8 , 8 ) ;
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 8 , 0 ) ;
break ;
case TDA1004X_DEMOD_TDA10046 :
tda1004x_write_mask ( state , TDA1004X_AUTO , 0x40 , 0x40 ) ;
2005-11-09 08:35:13 +03:00
msleep ( 1 ) ;
tda1004x_write_mask ( state , TDA10046H_AGC_CONF , 4 , 1 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2005-05-17 08:54:30 +04:00
msleep ( 10 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
[media] dvb: don't require a parameter for get_frontend
Just like set_frontend, use the dvb cache properties for get_frontend.
This is more consistent, as both functions are now symetric. Also,
at the places get_frontend is called, it makes sense to update the
cache.
Most of this patch were generated by this small perl script:
while (<>) { $file .= $_; }
if ($file =~ m/\.get_frontend\s*=\s*([\d\w_]+)/) {
my $get = $1;
$file =~ s/($get)(\s*\([^\,\)]+)\,\s*struct\s+dtv_frontend_properties\s*\*\s*([_\d\w]+)\)\s*\{/\1\2)\n{\n\tstruct dtv_frontend_properties *\3 = &fe->dtv_property_cache;/g;
}
print $file;
Of course, the changes at dvb_frontend.[ch] were made by hand,
as well as the changes on a few other places, where get_frontend()
is called internally inside the driver.
On some places, get_frontend() were just a void function. Those
occurrences were removed, as the DVB core handles such cases.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-12-30 18:30:21 +04:00
static int tda1004x_get_fe ( struct dvb_frontend * fe )
2005-04-17 02:20:36 +04:00
{
[media] dvb: don't require a parameter for get_frontend
Just like set_frontend, use the dvb cache properties for get_frontend.
This is more consistent, as both functions are now symetric. Also,
at the places get_frontend is called, it makes sense to update the
cache.
Most of this patch were generated by this small perl script:
while (<>) { $file .= $_; }
if ($file =~ m/\.get_frontend\s*=\s*([\d\w_]+)/) {
my $get = $1;
$file =~ s/($get)(\s*\([^\,\)]+)\,\s*struct\s+dtv_frontend_properties\s*\*\s*([_\d\w]+)\)\s*\{/\1\2)\n{\n\tstruct dtv_frontend_properties *\3 = &fe->dtv_property_cache;/g;
}
print $file;
Of course, the changes at dvb_frontend.[ch] were made by hand,
as well as the changes on a few other places, where get_frontend()
is called internally inside the driver.
On some places, get_frontend() were just a void function. Those
occurrences were removed, as the DVB core handles such cases.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-12-30 18:30:21 +04:00
struct dtv_frontend_properties * fe_params = & fe - > dtv_property_cache ;
2005-04-17 02:20:36 +04:00
struct tda1004x_state * state = fe - > demodulator_priv ;
2006-01-09 20:25:04 +03:00
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
// inversion status
fe_params - > inversion = INVERSION_OFF ;
2005-05-17 08:54:30 +04:00
if ( tda1004x_read_byte ( state , TDA1004X_CONFC1 ) & 0x20 )
2005-04-17 02:20:36 +04:00
fe_params - > inversion = INVERSION_ON ;
2005-05-17 08:54:30 +04:00
if ( state - > config - > invert )
fe_params - > inversion = fe_params - > inversion ? INVERSION_OFF : INVERSION_ON ;
2005-04-17 02:20:36 +04:00
// bandwidth
2005-05-17 08:54:30 +04:00
switch ( state - > demod_type ) {
2005-04-17 02:20:36 +04:00
case TDA1004X_DEMOD_TDA10045 :
switch ( tda1004x_read_byte ( state , TDA10045H_WREF_LSB ) ) {
case 0x14 :
2011-12-26 20:19:48 +04:00
fe_params - > bandwidth_hz = 8000000 ;
2005-04-17 02:20:36 +04:00
break ;
case 0xdb :
2011-12-26 20:19:48 +04:00
fe_params - > bandwidth_hz = 7000000 ;
2005-04-17 02:20:36 +04:00
break ;
case 0x4f :
2011-12-26 20:19:48 +04:00
fe_params - > bandwidth_hz = 6000000 ;
2005-04-17 02:20:36 +04:00
break ;
}
break ;
case TDA1004X_DEMOD_TDA10046 :
switch ( tda1004x_read_byte ( state , TDA10046H_TIME_WREF1 ) ) {
2006-01-09 20:25:04 +03:00
case 0x5c :
case 0x54 :
2011-12-26 20:19:48 +04:00
fe_params - > bandwidth_hz = 8000000 ;
2005-04-17 02:20:36 +04:00
break ;
2006-01-09 20:25:04 +03:00
case 0x6a :
case 0x60 :
2011-12-26 20:19:48 +04:00
fe_params - > bandwidth_hz = 7000000 ;
2005-04-17 02:20:36 +04:00
break ;
2006-01-09 20:25:04 +03:00
case 0x7b :
case 0x70 :
2011-12-26 20:19:48 +04:00
fe_params - > bandwidth_hz = 6000000 ;
2005-04-17 02:20:36 +04:00
break ;
}
break ;
}
// FEC
2011-12-26 20:19:48 +04:00
fe_params - > code_rate_HP =
2005-04-17 02:20:36 +04:00
tda1004x_decode_fec ( tda1004x_read_byte ( state , TDA1004X_OUT_CONF2 ) & 7 ) ;
2011-12-26 20:19:48 +04:00
fe_params - > code_rate_LP =
2005-04-17 02:20:36 +04:00
tda1004x_decode_fec ( ( tda1004x_read_byte ( state , TDA1004X_OUT_CONF2 ) > > 3 ) & 7 ) ;
2011-12-26 20:19:48 +04:00
/* modulation */
2005-04-17 02:20:36 +04:00
switch ( tda1004x_read_byte ( state , TDA1004X_OUT_CONF1 ) & 3 ) {
case 0 :
2011-12-26 20:19:48 +04:00
fe_params - > modulation = QPSK ;
2005-04-17 02:20:36 +04:00
break ;
case 1 :
2011-12-26 20:19:48 +04:00
fe_params - > modulation = QAM_16 ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2011-12-26 20:19:48 +04:00
fe_params - > modulation = QAM_64 ;
2005-04-17 02:20:36 +04:00
break ;
}
// transmission mode
2011-12-26 20:19:48 +04:00
fe_params - > transmission_mode = TRANSMISSION_MODE_2K ;
2005-05-17 08:54:30 +04:00
if ( tda1004x_read_byte ( state , TDA1004X_OUT_CONF1 ) & 0x10 )
2011-12-26 20:19:48 +04:00
fe_params - > transmission_mode = TRANSMISSION_MODE_8K ;
2005-04-17 02:20:36 +04:00
// guard interval
switch ( ( tda1004x_read_byte ( state , TDA1004X_OUT_CONF1 ) & 0x0c ) > > 2 ) {
case 0 :
2011-12-26 20:19:48 +04:00
fe_params - > guard_interval = GUARD_INTERVAL_1_32 ;
2005-04-17 02:20:36 +04:00
break ;
case 1 :
2011-12-26 20:19:48 +04:00
fe_params - > guard_interval = GUARD_INTERVAL_1_16 ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2011-12-26 20:19:48 +04:00
fe_params - > guard_interval = GUARD_INTERVAL_1_8 ;
2005-04-17 02:20:36 +04:00
break ;
case 3 :
2011-12-26 20:19:48 +04:00
fe_params - > guard_interval = GUARD_INTERVAL_1_4 ;
2005-04-17 02:20:36 +04:00
break ;
}
// hierarchy
switch ( ( tda1004x_read_byte ( state , TDA1004X_OUT_CONF1 ) & 0x60 ) > > 5 ) {
case 0 :
2011-12-26 20:19:48 +04:00
fe_params - > hierarchy = HIERARCHY_NONE ;
2005-04-17 02:20:36 +04:00
break ;
case 1 :
2011-12-26 20:19:48 +04:00
fe_params - > hierarchy = HIERARCHY_1 ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2011-12-26 20:19:48 +04:00
fe_params - > hierarchy = HIERARCHY_2 ;
2005-04-17 02:20:36 +04:00
break ;
case 3 :
2011-12-26 20:19:48 +04:00
fe_params - > hierarchy = HIERARCHY_4 ;
2005-04-17 02:20:36 +04:00
break ;
}
return 0 ;
}
static int tda1004x_read_status ( struct dvb_frontend * fe , fe_status_t * fe_status )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
int status ;
int cber ;
int vber ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
// read status
status = tda1004x_read_byte ( state , TDA1004X_STATUS_CD ) ;
2005-05-17 08:54:30 +04:00
if ( status = = - 1 )
2005-04-17 02:20:36 +04:00
return - EIO ;
// decode
* fe_status = 0 ;
2005-05-17 08:54:30 +04:00
if ( status & 4 )
* fe_status | = FE_HAS_SIGNAL ;
if ( status & 2 )
* fe_status | = FE_HAS_CARRIER ;
if ( status & 8 )
* fe_status | = FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK ;
2005-04-17 02:20:36 +04:00
// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
// is getting anything valid
if ( ! ( * fe_status & FE_HAS_VITERBI ) ) {
// read the CBER
cber = tda1004x_read_byte ( state , TDA1004X_CBER_LSB ) ;
2005-05-17 08:54:30 +04:00
if ( cber = = - 1 )
return - EIO ;
2005-04-17 02:20:36 +04:00
status = tda1004x_read_byte ( state , TDA1004X_CBER_MSB ) ;
2005-05-17 08:54:30 +04:00
if ( status = = - 1 )
return - EIO ;
2005-04-17 02:20:36 +04:00
cber | = ( status < < 8 ) ;
2006-02-07 11:49:10 +03:00
// The address 0x20 should be read to cope with a TDA10046 bug
2005-04-17 02:20:36 +04:00
tda1004x_read_byte ( state , TDA1004X_CBER_RESET ) ;
2005-05-17 08:54:30 +04:00
if ( cber ! = 65535 )
2005-04-17 02:20:36 +04:00
* fe_status | = FE_HAS_VITERBI ;
}
// if we DO have some valid VITERBI output, but don't already have SYNC
// bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
if ( ( * fe_status & FE_HAS_VITERBI ) & & ( ! ( * fe_status & FE_HAS_SYNC ) ) ) {
// read the VBER
vber = tda1004x_read_byte ( state , TDA1004X_VBER_LSB ) ;
2005-05-17 08:54:30 +04:00
if ( vber = = - 1 )
return - EIO ;
2005-04-17 02:20:36 +04:00
status = tda1004x_read_byte ( state , TDA1004X_VBER_MID ) ;
2005-05-17 08:54:30 +04:00
if ( status = = - 1 )
return - EIO ;
2005-04-17 02:20:36 +04:00
vber | = ( status < < 8 ) ;
status = tda1004x_read_byte ( state , TDA1004X_VBER_MSB ) ;
2005-05-17 08:54:30 +04:00
if ( status = = - 1 )
return - EIO ;
2006-02-07 11:49:10 +03:00
vber | = ( status & 0x0f ) < < 16 ;
// The CVBER_LUT should be read to cope with TDA10046 hardware bug
2005-04-17 02:20:36 +04:00
tda1004x_read_byte ( state , TDA1004X_CVBER_LUT ) ;
// if RS has passed some valid TS packets, then we must be
// getting some SYNC bytes
2005-05-17 08:54:30 +04:00
if ( vber < 16632 )
2005-04-17 02:20:36 +04:00
* fe_status | = FE_HAS_SYNC ;
}
// success
2008-04-09 06:20:00 +04:00
dprintk ( " %s: fe_status=0x%x \n " , __func__ , * fe_status ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int tda1004x_read_signal_strength ( struct dvb_frontend * fe , u16 * signal )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
int tmp ;
int reg = 0 ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
// determine the register to use
2005-05-17 08:54:30 +04:00
switch ( state - > demod_type ) {
2005-04-17 02:20:36 +04:00
case TDA1004X_DEMOD_TDA10045 :
reg = TDA10045H_S_AGC ;
break ;
case TDA1004X_DEMOD_TDA10046 :
reg = TDA10046H_AGC_IF_LEVEL ;
break ;
}
// read it
tmp = tda1004x_read_byte ( state , reg ) ;
if ( tmp < 0 )
return - EIO ;
* signal = ( tmp < < 8 ) | tmp ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s: signal=0x%x \n " , __func__ , * signal ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int tda1004x_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
int tmp ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
// read it
tmp = tda1004x_read_byte ( state , TDA1004X_SNR ) ;
if ( tmp < 0 )
return - EIO ;
2005-09-10 00:02:33 +04:00
tmp = 255 - tmp ;
2005-04-17 02:20:36 +04:00
* snr = ( ( tmp < < 8 ) | tmp ) ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s: snr=0x%x \n " , __func__ , * snr ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int tda1004x_read_ucblocks ( struct dvb_frontend * fe , u32 * ucblocks )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
int tmp ;
int tmp2 ;
int counter ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
// read the UCBLOCKS and reset
counter = 0 ;
tmp = tda1004x_read_byte ( state , TDA1004X_UNCOR ) ;
if ( tmp < 0 )
return - EIO ;
tmp & = 0x7f ;
while ( counter + + < 5 ) {
tda1004x_write_mask ( state , TDA1004X_UNCOR , 0x80 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_UNCOR , 0x80 , 0 ) ;
tda1004x_write_mask ( state , TDA1004X_UNCOR , 0x80 , 0 ) ;
tmp2 = tda1004x_read_byte ( state , TDA1004X_UNCOR ) ;
if ( tmp2 < 0 )
return - EIO ;
tmp2 & = 0x7f ;
if ( ( tmp2 < tmp ) | | ( tmp2 = = 0 ) )
break ;
}
2005-05-17 08:54:30 +04:00
if ( tmp ! = 0x7f )
2005-04-17 02:20:36 +04:00
* ucblocks = tmp ;
2005-05-17 08:54:30 +04:00
else
2005-04-17 02:20:36 +04:00
* ucblocks = 0xffffffff ;
2005-05-17 08:54:30 +04:00
2008-04-09 06:20:00 +04:00
dprintk ( " %s: ucblocks=0x%x \n " , __func__ , * ucblocks ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int tda1004x_read_ber ( struct dvb_frontend * fe , u32 * ber )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
int tmp ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
// read it in
tmp = tda1004x_read_byte ( state , TDA1004X_CBER_LSB ) ;
2005-05-17 08:54:30 +04:00
if ( tmp < 0 )
return - EIO ;
2005-04-17 02:20:36 +04:00
* ber = tmp < < 1 ;
tmp = tda1004x_read_byte ( state , TDA1004X_CBER_MSB ) ;
2005-05-17 08:54:30 +04:00
if ( tmp < 0 )
return - EIO ;
2005-04-17 02:20:36 +04:00
* ber | = ( tmp < < 9 ) ;
2006-02-07 11:49:10 +03:00
// The address 0x20 should be read to cope with a TDA10046 bug
2005-04-17 02:20:36 +04:00
tda1004x_read_byte ( state , TDA1004X_CBER_RESET ) ;
2008-04-09 06:20:00 +04:00
dprintk ( " %s: ber=0x%x \n " , __func__ , * ber ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int tda1004x_sleep ( struct dvb_frontend * fe )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
2007-04-27 19:31:10 +04:00
int gpio_conf ;
2005-04-17 02:20:36 +04:00
2005-05-17 08:54:30 +04:00
switch ( state - > demod_type ) {
2005-04-17 02:20:36 +04:00
case TDA1004X_DEMOD_TDA10045 :
tda1004x_write_mask ( state , TDA1004X_CONFADC1 , 0x10 , 0x10 ) ;
break ;
case TDA1004X_DEMOD_TDA10046 :
2006-02-07 11:49:10 +03:00
/* set outputs to tristate */
tda1004x_write_byteI ( state , TDA10046H_CONF_TRISTATE1 , 0xff ) ;
2007-04-27 19:31:10 +04:00
/* invert GPIO 1 and 3 if desired*/
gpio_conf = state - > config - > gpio_config ;
if ( gpio_conf > = TDA10046_GP00_I )
tda1004x_write_mask ( state , TDA10046H_CONF_POLARITY , 0x0f ,
( gpio_conf & 0x0f ) ^ 0x0a ) ;
2007-04-27 19:31:15 +04:00
tda1004x_write_mask ( state , TDA1004X_CONFADC2 , 0xc0 , 0xc0 ) ;
2005-07-08 04:57:43 +04:00
tda1004x_write_mask ( state , TDA1004X_CONFC4 , 1 , 1 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
return 0 ;
}
2006-04-19 00:47:10 +04:00
static int tda1004x_i2c_gate_ctrl ( struct dvb_frontend * fe , int enable )
{
struct tda1004x_state * state = fe - > demodulator_priv ;
if ( enable ) {
return tda1004x_enable_tuner_i2c ( state ) ;
} else {
return tda1004x_disable_tuner_i2c ( state ) ;
}
}
2005-04-17 02:20:36 +04:00
static int tda1004x_get_tune_settings ( struct dvb_frontend * fe , struct dvb_frontend_tune_settings * fesettings )
{
fesettings - > min_delay_ms = 800 ;
2005-07-08 04:57:43 +04:00
/* Drift compensation makes no sense for DVB-T */
fesettings - > step_size = 0 ;
fesettings - > max_drift = 0 ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-08-08 16:10:09 +04:00
static void tda1004x_release ( struct dvb_frontend * fe )
2005-04-17 02:20:36 +04:00
{
2005-05-17 08:54:30 +04:00
struct tda1004x_state * state = fe - > demodulator_priv ;
2005-04-17 02:20:36 +04:00
kfree ( state ) ;
}
static struct dvb_frontend_ops tda10045_ops = {
2011-12-26 20:19:48 +04:00
. delsys = { SYS_DVBT } ,
2005-04-17 02:20:36 +04:00
. info = {
. name = " Philips TDA10045H DVB-T " ,
. frequency_min = 51000000 ,
. frequency_max = 858000000 ,
. frequency_stepsize = 166667 ,
. caps =
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
} ,
2006-08-08 16:10:09 +04:00
. release = tda1004x_release ,
2005-04-17 02:20:36 +04:00
. init = tda10045_init ,
. sleep = tda1004x_sleep ,
2006-08-08 16:10:08 +04:00
. write = tda1004x_write ,
2006-04-19 00:47:10 +04:00
. i2c_gate_ctrl = tda1004x_i2c_gate_ctrl ,
2005-04-17 02:20:36 +04:00
2011-12-26 20:19:48 +04:00
. set_frontend = tda1004x_set_fe ,
. get_frontend = tda1004x_get_fe ,
2005-04-17 02:20:36 +04:00
. get_tune_settings = tda1004x_get_tune_settings ,
. read_status = tda1004x_read_status ,
. read_ber = tda1004x_read_ber ,
. read_signal_strength = tda1004x_read_signal_strength ,
. read_snr = tda1004x_read_snr ,
. read_ucblocks = tda1004x_read_ucblocks ,
} ;
2005-05-17 08:54:30 +04:00
struct dvb_frontend * tda10045_attach ( const struct tda1004x_config * config ,
struct i2c_adapter * i2c )
{
struct tda1004x_state * state ;
2008-06-14 18:27:34 +04:00
int id ;
2005-05-17 08:54:30 +04:00
/* allocate memory for the internal state */
2009-08-11 05:51:01 +04:00
state = kzalloc ( sizeof ( struct tda1004x_state ) , GFP_KERNEL ) ;
2008-06-14 17:44:04 +04:00
if ( ! state ) {
2012-02-03 16:56:59 +04:00
printk ( KERN_ERR " Can't allocate memory for tda10045 state \n " ) ;
2005-05-17 08:54:30 +04:00
return NULL ;
2008-06-14 17:44:04 +04:00
}
2005-05-17 08:54:30 +04:00
/* setup the state */
state - > config = config ;
state - > i2c = i2c ;
state - > demod_type = TDA1004X_DEMOD_TDA10045 ;
/* check if the demod is there */
2008-06-14 17:44:04 +04:00
id = tda1004x_read_byte ( state , TDA1004X_CHIPID ) ;
2008-06-14 18:27:34 +04:00
if ( id < 0 ) {
printk ( KERN_ERR " tda10045: chip is not answering. Giving up. \n " ) ;
kfree ( state ) ;
return NULL ;
}
2008-06-14 17:44:04 +04:00
if ( id ! = 0x25 ) {
printk ( KERN_ERR " Invalid tda1004x ID = 0x%02x. Can't proceed \n " , id ) ;
2005-05-17 08:54:30 +04:00
kfree ( state ) ;
return NULL ;
}
/* create dvb_frontend */
2006-05-14 12:01:31 +04:00
memcpy ( & state - > frontend . ops , & tda10045_ops , sizeof ( struct dvb_frontend_ops ) ) ;
2005-05-17 08:54:30 +04:00
state - > frontend . demodulator_priv = state ;
return & state - > frontend ;
}
2005-04-17 02:20:36 +04:00
2005-05-17 08:54:30 +04:00
static struct dvb_frontend_ops tda10046_ops = {
2011-12-26 20:19:48 +04:00
. delsys = { SYS_DVBT } ,
2005-04-17 02:20:36 +04:00
. info = {
. name = " Philips TDA10046H DVB-T " ,
. frequency_min = 51000000 ,
. frequency_max = 858000000 ,
. frequency_stepsize = 166667 ,
. caps =
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
} ,
2006-08-08 16:10:09 +04:00
. release = tda1004x_release ,
2005-04-17 02:20:36 +04:00
. init = tda10046_init ,
. sleep = tda1004x_sleep ,
2006-08-08 16:10:08 +04:00
. write = tda1004x_write ,
2006-04-20 01:31:03 +04:00
. i2c_gate_ctrl = tda1004x_i2c_gate_ctrl ,
2005-04-17 02:20:36 +04:00
2011-12-26 20:19:48 +04:00
. set_frontend = tda1004x_set_fe ,
. get_frontend = tda1004x_get_fe ,
2005-04-17 02:20:36 +04:00
. get_tune_settings = tda1004x_get_tune_settings ,
. read_status = tda1004x_read_status ,
. read_ber = tda1004x_read_ber ,
. read_signal_strength = tda1004x_read_signal_strength ,
. read_snr = tda1004x_read_snr ,
. read_ucblocks = tda1004x_read_ucblocks ,
} ;
2005-05-17 08:54:30 +04:00
struct dvb_frontend * tda10046_attach ( const struct tda1004x_config * config ,
struct i2c_adapter * i2c )
{
struct tda1004x_state * state ;
2008-06-14 18:27:34 +04:00
int id ;
2005-05-17 08:54:30 +04:00
/* allocate memory for the internal state */
2009-08-11 05:51:01 +04:00
state = kzalloc ( sizeof ( struct tda1004x_state ) , GFP_KERNEL ) ;
2008-06-14 17:44:04 +04:00
if ( ! state ) {
2012-02-03 16:56:59 +04:00
printk ( KERN_ERR " Can't allocate memory for tda10046 state \n " ) ;
2005-05-17 08:54:30 +04:00
return NULL ;
2008-06-14 17:44:04 +04:00
}
2005-05-17 08:54:30 +04:00
/* setup the state */
state - > config = config ;
state - > i2c = i2c ;
state - > demod_type = TDA1004X_DEMOD_TDA10046 ;
/* check if the demod is there */
2008-06-14 17:44:04 +04:00
id = tda1004x_read_byte ( state , TDA1004X_CHIPID ) ;
2008-06-14 18:27:34 +04:00
if ( id < 0 ) {
printk ( KERN_ERR " tda10046: chip is not answering. Giving up. \n " ) ;
kfree ( state ) ;
return NULL ;
}
2008-06-14 17:44:04 +04:00
if ( id ! = 0x46 ) {
printk ( KERN_ERR " Invalid tda1004x ID = 0x%02x. Can't proceed \n " , id ) ;
2005-05-17 08:54:30 +04:00
kfree ( state ) ;
return NULL ;
}
/* create dvb_frontend */
2006-05-14 12:01:31 +04:00
memcpy ( & state - > frontend . ops , & tda10046_ops , sizeof ( struct dvb_frontend_ops ) ) ;
2005-05-17 08:54:30 +04:00
state - > frontend . demodulator_priv = state ;
return & state - > frontend ;
}
2005-04-17 02:20:36 +04:00
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Turn on/off frontend debugging (default:off). " ) ;
MODULE_DESCRIPTION ( " Philips TDA10045H & TDA10046H DVB-T Demodulator " ) ;
MODULE_AUTHOR ( " Andrew de Quincey & Robert Schlabbach " ) ;
MODULE_LICENSE ( " GPL " ) ;
EXPORT_SYMBOL ( tda10045_attach ) ;
EXPORT_SYMBOL ( tda10046_attach ) ;