2006-08-08 09:10:10 -03:00
/*
Driver for Philips tda10086 DVBS Demodulator
( c ) 2006 Andrew de Quincey
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/init.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/jiffies.h>
# include <linux/string.h>
# include <linux/slab.h>
# include "dvb_frontend.h"
# include "tda10086.h"
# define SACLK 96000000
struct tda10086_state {
struct i2c_adapter * i2c ;
const struct tda10086_config * config ;
struct dvb_frontend frontend ;
/* private demod data */
u32 frequency ;
u32 symbol_rate ;
2007-05-28 18:06:27 -03:00
bool has_lock ;
2006-08-08 09:10:10 -03:00
} ;
2008-04-22 14:41:48 -03:00
static int debug ;
2006-08-08 09:10:10 -03:00
# define dprintk(args...) \
do { \
if ( debug ) printk ( KERN_DEBUG " tda10086: " args ) ; \
} while ( 0 )
static int tda10086_write_byte ( struct tda10086_state * state , int reg , int data )
{
int ret ;
u8 b0 [ ] = { reg , data } ;
struct i2c_msg msg = { . flags = 0 , . buf = b0 , . len = 2 } ;
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-08 23:20:00 -03:00
__func__ , reg , data , ret ) ;
2006-08-08 09:10:10 -03:00
return ( ret ! = 1 ) ? ret : 0 ;
}
static int tda10086_read_byte ( struct tda10086_state * state , int reg )
{
int ret ;
u8 b0 [ ] = { reg } ;
u8 b1 [ ] = { 0 } ;
struct i2c_msg msg [ ] = { { . flags = 0 , . buf = b0 , . len = 1 } ,
{ . flags = I2C_M_RD , . buf = b1 , . len = 1 } } ;
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-08 23:20:00 -03:00
dprintk ( " %s: error reg=0x%x, ret=%i \n " , __func__ , reg ,
2006-08-08 09:10:10 -03:00
ret ) ;
return ret ;
}
return b1 [ 0 ] ;
}
static int tda10086_write_mask ( struct tda10086_state * state , int reg , int mask , int data )
{
int val ;
2008-04-13 21:09:11 -03:00
/* read a byte and check */
2006-08-08 09:10:10 -03:00
val = tda10086_read_byte ( state , reg ) ;
if ( val < 0 )
return val ;
2008-04-13 21:09:11 -03:00
/* mask if off */
2006-08-08 09:10:10 -03:00
val = val & ~ mask ;
val | = data & 0xff ;
2008-04-13 21:09:11 -03:00
/* write it out again */
2006-08-08 09:10:10 -03:00
return tda10086_write_byte ( state , reg , val ) ;
}
static int tda10086_init ( struct dvb_frontend * fe )
{
struct tda10086_state * state = fe - > demodulator_priv ;
2008-02-09 23:54:24 -03:00
u8 t22k_off = 0x80 ;
2006-08-08 09:10:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-02-09 23:54:24 -03:00
if ( state - > config - > diseqc_tone )
t22k_off = 0 ;
2008-04-13 21:09:11 -03:00
/* reset */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x00 , 0x00 ) ;
msleep ( 10 ) ;
2008-04-13 21:09:11 -03:00
/* misc setup */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x01 , 0x94 ) ;
2008-04-13 21:09:11 -03:00
tda10086_write_byte ( state , 0x02 , 0x35 ) ; /* NOTE: TT drivers appear to disable CSWP */
2007-05-28 18:06:27 -03:00
tda10086_write_byte ( state , 0x03 , 0xe4 ) ;
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x04 , 0x43 ) ;
tda10086_write_byte ( state , 0x0c , 0x0c ) ;
2008-04-13 21:09:11 -03:00
tda10086_write_byte ( state , 0x1b , 0xb0 ) ; /* noise threshold */
tda10086_write_byte ( state , 0x20 , 0x89 ) ; /* misc */
tda10086_write_byte ( state , 0x30 , 0x04 ) ; /* acquisition period length */
tda10086_write_byte ( state , 0x32 , 0x00 ) ; /* irq off */
tda10086_write_byte ( state , 0x31 , 0x56 ) ; /* setup AFC */
/* setup PLL (this assumes SACLK = 96MHz) */
tda10086_write_byte ( state , 0x55 , 0x2c ) ; /* misc PLL setup */
2008-04-09 23:07:11 -03:00
if ( state - > config - > xtal_freq = = TDA10086_XTAL_16M ) {
2008-04-13 21:09:11 -03:00
tda10086_write_byte ( state , 0x3a , 0x0b ) ; /* M=12 */
tda10086_write_byte ( state , 0x3b , 0x01 ) ; /* P=2 */
2008-04-09 23:07:11 -03:00
} else {
2008-04-13 21:09:11 -03:00
tda10086_write_byte ( state , 0x3a , 0x17 ) ; /* M=24 */
tda10086_write_byte ( state , 0x3b , 0x00 ) ; /* P=1 */
2008-04-09 23:07:11 -03:00
}
2008-04-13 21:09:11 -03:00
tda10086_write_mask ( state , 0x55 , 0x20 , 0x00 ) ; /* powerup PLL */
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* setup TS interface */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x11 , 0x81 ) ;
tda10086_write_byte ( state , 0x12 , 0x81 ) ;
2008-04-13 21:09:11 -03:00
tda10086_write_byte ( state , 0x19 , 0x40 ) ; /* parallel mode A + MSBFIRST */
tda10086_write_byte ( state , 0x56 , 0x80 ) ; /* powerdown WPLL - unused in the mode we use */
tda10086_write_byte ( state , 0x57 , 0x08 ) ; /* bypass WPLL - unused in the mode we use */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x10 , 0x2a ) ;
2008-04-13 21:09:11 -03:00
/* setup ADC */
tda10086_write_byte ( state , 0x58 , 0x61 ) ; /* ADC setup */
tda10086_write_mask ( state , 0x58 , 0x01 , 0x00 ) ; /* powerup ADC */
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* setup AGC */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x05 , 0x0B ) ;
tda10086_write_byte ( state , 0x37 , 0x63 ) ;
2008-04-13 21:09:11 -03:00
tda10086_write_byte ( state , 0x3f , 0x0a ) ; /* NOTE: flydvb varies it */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x40 , 0x64 ) ;
tda10086_write_byte ( state , 0x41 , 0x4f ) ;
tda10086_write_byte ( state , 0x42 , 0x43 ) ;
2008-04-13 21:09:11 -03:00
/* setup viterbi */
tda10086_write_byte ( state , 0x1a , 0x11 ) ; /* VBER 10^6, DVB, QPSK */
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* setup carrier recovery */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x3d , 0x80 ) ;
2008-04-13 21:09:11 -03:00
/* setup SEC */
tda10086_write_byte ( state , 0x36 , t22k_off ) ; /* all SEC off, 22k tone */
tda10086_write_byte ( state , 0x34 , ( ( ( 1 < < 19 ) * ( 22000 / 1000 ) ) / ( SACLK / 1000 ) ) ) ;
tda10086_write_byte ( state , 0x35 , ( ( ( 1 < < 19 ) * ( 22000 / 1000 ) ) / ( SACLK / 1000 ) ) > > 8 ) ;
2006-08-08 09:10:10 -03:00
return 0 ;
}
static void tda10086_diseqc_wait ( struct tda10086_state * state )
{
unsigned long timeout = jiffies + msecs_to_jiffies ( 200 ) ;
while ( ! ( tda10086_read_byte ( state , 0x50 ) & 0x01 ) ) {
if ( time_after ( jiffies , timeout ) ) {
2008-04-08 23:20:00 -03:00
printk ( " %s: diseqc queue not ready, command may be lost. \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
break ;
}
msleep ( 10 ) ;
}
}
static int tda10086_set_tone ( struct dvb_frontend * fe , fe_sec_tone_mode_t tone )
{
struct tda10086_state * state = fe - > demodulator_priv ;
2008-02-09 23:54:24 -03:00
u8 t22k_off = 0x80 ;
2006-08-08 09:10:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-02-09 23:54:24 -03:00
if ( state - > config - > diseqc_tone )
t22k_off = 0 ;
2007-11-08 08:54:53 -03:00
switch ( tone ) {
2006-08-08 09:10:10 -03:00
case SEC_TONE_OFF :
2008-02-09 23:54:24 -03:00
tda10086_write_byte ( state , 0x36 , t22k_off ) ;
2006-08-08 09:10:10 -03:00
break ;
case SEC_TONE_ON :
2008-02-09 23:54:24 -03:00
tda10086_write_byte ( state , 0x36 , 0x01 + t22k_off ) ;
2006-08-08 09:10:10 -03:00
break ;
}
return 0 ;
}
static int tda10086_send_master_cmd ( struct dvb_frontend * fe ,
struct dvb_diseqc_master_cmd * cmd )
{
struct tda10086_state * state = fe - > demodulator_priv ;
int i ;
u8 oldval ;
2008-02-09 23:54:24 -03:00
u8 t22k_off = 0x80 ;
2006-08-08 09:10:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-02-09 23:54:24 -03:00
if ( state - > config - > diseqc_tone )
t22k_off = 0 ;
2006-08-08 09:10:10 -03:00
if ( cmd - > msg_len > 6 )
return - EINVAL ;
oldval = tda10086_read_byte ( state , 0x36 ) ;
for ( i = 0 ; i < cmd - > msg_len ; i + + ) {
tda10086_write_byte ( state , 0x48 + i , cmd - > msg [ i ] ) ;
}
2008-02-09 23:54:24 -03:00
tda10086_write_byte ( state , 0x36 , ( 0x08 + t22k_off )
| ( ( cmd - > msg_len - 1 ) < < 4 ) ) ;
2006-08-08 09:10:10 -03:00
tda10086_diseqc_wait ( state ) ;
tda10086_write_byte ( state , 0x36 , oldval ) ;
return 0 ;
}
static int tda10086_send_burst ( struct dvb_frontend * fe , fe_sec_mini_cmd_t minicmd )
{
struct tda10086_state * state = fe - > demodulator_priv ;
u8 oldval = tda10086_read_byte ( state , 0x36 ) ;
2008-02-09 23:54:24 -03:00
u8 t22k_off = 0x80 ;
2006-08-08 09:10:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-02-09 23:54:24 -03:00
if ( state - > config - > diseqc_tone )
t22k_off = 0 ;
2006-08-08 09:10:10 -03:00
switch ( minicmd ) {
case SEC_MINI_A :
2008-02-09 23:54:24 -03:00
tda10086_write_byte ( state , 0x36 , 0x04 + t22k_off ) ;
2006-08-08 09:10:10 -03:00
break ;
case SEC_MINI_B :
2008-02-09 23:54:24 -03:00
tda10086_write_byte ( state , 0x36 , 0x06 + t22k_off ) ;
2006-08-08 09:10:10 -03:00
break ;
}
tda10086_diseqc_wait ( state ) ;
tda10086_write_byte ( state , 0x36 , oldval ) ;
return 0 ;
}
static int tda10086_set_inversion ( struct tda10086_state * state ,
2011-12-26 14:51:41 -03:00
struct dtv_frontend_properties * fe_params )
2006-08-08 09:10:10 -03:00
{
u8 invval = 0x80 ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s %i %i \n " , __func__ , fe_params - > inversion , state - > config - > invert ) ;
2006-08-08 09:10:10 -03:00
switch ( fe_params - > inversion ) {
case INVERSION_OFF :
if ( state - > config - > invert )
invval = 0x40 ;
break ;
case INVERSION_ON :
if ( ! state - > config - > invert )
invval = 0x40 ;
break ;
case INVERSION_AUTO :
invval = 0x00 ;
break ;
}
tda10086_write_mask ( state , 0x0c , 0xc0 , invval ) ;
return 0 ;
}
static int tda10086_set_symbol_rate ( struct tda10086_state * state ,
2011-12-26 14:51:41 -03:00
struct dtv_frontend_properties * fe_params )
2006-08-08 09:10:10 -03:00
{
u8 dfn = 0 ;
u8 afs = 0 ;
u8 byp = 0 ;
u8 reg37 = 0x43 ;
u8 reg42 = 0x43 ;
u64 big ;
u32 tmp ;
u32 bdr ;
u32 bdri ;
2011-12-26 14:51:41 -03:00
u32 symbol_rate = fe_params - > symbol_rate ;
2006-08-08 09:10:10 -03:00
2008-04-08 23:20:00 -03:00
dprintk ( " %s %i \n " , __func__ , symbol_rate ) ;
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* setup the decimation and anti-aliasing filters.. */
2006-08-08 09:10:10 -03:00
if ( symbol_rate < ( u32 ) ( SACLK * 0.0137 ) ) {
dfn = 4 ;
afs = 1 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.0208 ) ) {
dfn = 4 ;
afs = 0 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.0270 ) ) {
dfn = 3 ;
afs = 1 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.0416 ) ) {
dfn = 3 ;
afs = 0 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.0550 ) ) {
dfn = 2 ;
afs = 1 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.0833 ) ) {
dfn = 2 ;
afs = 0 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.1100 ) ) {
dfn = 1 ;
afs = 1 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.1666 ) ) {
dfn = 1 ;
afs = 0 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.2200 ) ) {
dfn = 0 ;
afs = 1 ;
} else if ( symbol_rate < ( u32 ) ( SACLK * 0.3333 ) ) {
dfn = 0 ;
afs = 0 ;
} else {
reg37 = 0x63 ;
reg42 = 0x4f ;
byp = 1 ;
}
2008-04-13 21:09:11 -03:00
/* calculate BDR */
2006-08-08 09:10:10 -03:00
big = ( 1ULL < < 21 ) * ( ( u64 ) symbol_rate / 1000ULL ) * ( 1ULL < < dfn ) ;
big + = ( ( SACLK / 1000ULL ) - 1ULL ) ;
do_div ( big , ( SACLK / 1000ULL ) ) ;
bdr = big & 0xfffff ;
2008-04-13 21:09:11 -03:00
/* calculate BDRI */
2006-08-08 09:10:10 -03:00
tmp = ( 1 < < dfn ) * ( symbol_rate / 1000 ) ;
bdri = ( ( 32 * ( SACLK / 1000 ) ) + ( tmp - 1 ) ) / tmp ;
tda10086_write_byte ( state , 0x21 , ( afs < < 7 ) | dfn ) ;
tda10086_write_mask ( state , 0x20 , 0x08 , byp < < 3 ) ;
tda10086_write_byte ( state , 0x06 , bdr ) ;
tda10086_write_byte ( state , 0x07 , bdr > > 8 ) ;
tda10086_write_byte ( state , 0x08 , bdr > > 16 ) ;
tda10086_write_byte ( state , 0x09 , bdri ) ;
tda10086_write_byte ( state , 0x37 , reg37 ) ;
tda10086_write_byte ( state , 0x42 , reg42 ) ;
return 0 ;
}
static int tda10086_set_fec ( struct tda10086_state * state ,
2011-12-26 14:51:41 -03:00
struct dtv_frontend_properties * fe_params )
2006-08-08 09:10:10 -03:00
{
u8 fecval ;
2011-12-26 14:51:41 -03:00
dprintk ( " %s %i \n " , __func__ , fe_params - > fec_inner ) ;
2006-08-08 09:10:10 -03:00
2011-12-26 14:51:41 -03:00
switch ( fe_params - > fec_inner ) {
2006-08-08 09:10:10 -03:00
case FEC_1_2 :
fecval = 0x00 ;
break ;
case FEC_2_3 :
fecval = 0x01 ;
break ;
case FEC_3_4 :
fecval = 0x02 ;
break ;
case FEC_4_5 :
fecval = 0x03 ;
break ;
case FEC_5_6 :
fecval = 0x04 ;
break ;
case FEC_6_7 :
fecval = 0x05 ;
break ;
case FEC_7_8 :
fecval = 0x06 ;
break ;
case FEC_8_9 :
fecval = 0x07 ;
break ;
case FEC_AUTO :
fecval = 0x08 ;
break ;
default :
return - 1 ;
}
tda10086_write_byte ( state , 0x0d , fecval ) ;
return 0 ;
}
2011-12-26 14:51:41 -03:00
static int tda10086_set_frontend ( struct dvb_frontend * fe )
2006-08-08 09:10:10 -03:00
{
2011-12-26 14:51:41 -03:00
struct dtv_frontend_properties * fe_params = & fe - > dtv_property_cache ;
2006-08-08 09:10:10 -03:00
struct tda10086_state * state = fe - > demodulator_priv ;
int ret ;
u32 freq = 0 ;
int freqoff ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* modify parameters for tuning */
2007-05-28 18:06:27 -03:00
tda10086_write_byte ( state , 0x02 , 0x35 ) ;
state - > has_lock = false ;
2008-04-13 21:09:11 -03:00
/* set params */
2006-08-08 09:10:10 -03:00
if ( fe - > ops . tuner_ops . set_params ) {
2011-12-24 12:24:33 -03:00
fe - > ops . tuner_ops . set_params ( fe ) ;
2006-08-08 09:10:10 -03:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 0 ) ;
if ( fe - > ops . tuner_ops . get_frequency )
fe - > ops . tuner_ops . get_frequency ( fe , & freq ) ;
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 0 ) ;
}
2008-04-13 21:09:11 -03:00
/* calcluate the frequency offset (in *Hz* not kHz) */
2006-08-08 09:10:10 -03:00
freqoff = fe_params - > frequency - freq ;
freqoff = ( ( 1 < < 16 ) * freqoff ) / ( SACLK / 1000 ) ;
tda10086_write_byte ( state , 0x3d , 0x80 | ( ( freqoff > > 8 ) & 0x7f ) ) ;
tda10086_write_byte ( state , 0x3e , freqoff ) ;
if ( ( ret = tda10086_set_inversion ( state , fe_params ) ) < 0 )
return ret ;
if ( ( ret = tda10086_set_symbol_rate ( state , fe_params ) ) < 0 )
return ret ;
if ( ( ret = tda10086_set_fec ( state , fe_params ) ) < 0 )
return ret ;
2008-04-13 21:09:11 -03:00
/* soft reset + disable TS output until lock */
2006-08-08 09:10:10 -03:00
tda10086_write_mask ( state , 0x10 , 0x40 , 0x40 ) ;
tda10086_write_mask ( state , 0x00 , 0x01 , 0x00 ) ;
2011-12-26 14:51:41 -03:00
state - > symbol_rate = fe_params - > symbol_rate ;
2006-08-08 09:10:10 -03:00
state - > frequency = fe_params - > frequency ;
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 11:30:21 -03:00
static int tda10086_get_frontend ( struct dvb_frontend * fe )
2006-08-08 09:10:10 -03: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 11:30:21 -03:00
struct dtv_frontend_properties * fe_params = & fe - > dtv_property_cache ;
2006-08-08 09:10:10 -03:00
struct tda10086_state * state = fe - > demodulator_priv ;
u8 val ;
int tmp ;
u64 tmp64 ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* check for invalid symbol rate */
2011-12-26 14:51:41 -03:00
if ( fe_params - > symbol_rate < 500000 )
2006-11-22 18:01:21 -03:00
return - EINVAL ;
2008-04-13 21:09:11 -03:00
/* calculate the updated frequency (note: we convert from Hz->kHz) */
2006-08-08 09:10:10 -03:00
tmp64 = tda10086_read_byte ( state , 0x52 ) ;
tmp64 | = ( tda10086_read_byte ( state , 0x51 ) < < 8 ) ;
if ( tmp64 & 0x8000 )
tmp64 | = 0xffffffffffff0000ULL ;
tmp64 = ( tmp64 * ( SACLK / 1000ULL ) ) ;
do_div ( tmp64 , ( 1ULL < < 15 ) * ( 1ULL < < 1 ) ) ;
fe_params - > frequency = ( int ) state - > frequency + ( int ) tmp64 ;
2008-04-13 21:09:11 -03:00
/* the inversion */
2006-08-08 09:10:10 -03:00
val = tda10086_read_byte ( state , 0x0c ) ;
if ( val & 0x80 ) {
switch ( val & 0x40 ) {
case 0x00 :
fe_params - > inversion = INVERSION_OFF ;
if ( state - > config - > invert )
fe_params - > inversion = INVERSION_ON ;
break ;
default :
fe_params - > inversion = INVERSION_ON ;
if ( state - > config - > invert )
fe_params - > inversion = INVERSION_OFF ;
break ;
}
} else {
tda10086_read_byte ( state , 0x0f ) ;
switch ( val & 0x02 ) {
case 0x00 :
fe_params - > inversion = INVERSION_OFF ;
if ( state - > config - > invert )
fe_params - > inversion = INVERSION_ON ;
break ;
default :
fe_params - > inversion = INVERSION_ON ;
if ( state - > config - > invert )
fe_params - > inversion = INVERSION_OFF ;
break ;
}
}
2008-04-13 21:09:11 -03:00
/* calculate the updated symbol rate */
2006-08-08 09:10:10 -03:00
tmp = tda10086_read_byte ( state , 0x1d ) ;
if ( tmp & 0x80 )
tmp | = 0xffffff00 ;
tmp = ( tmp * 480 * ( 1 < < 1 ) ) / 128 ;
tmp = ( ( state - > symbol_rate / 1000 ) * tmp ) / ( 1000000 / 1000 ) ;
2011-12-26 14:51:41 -03:00
fe_params - > symbol_rate = state - > symbol_rate + tmp ;
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* the FEC */
2006-08-08 09:10:10 -03:00
val = ( tda10086_read_byte ( state , 0x0d ) & 0x70 ) > > 4 ;
switch ( val ) {
case 0x00 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_1_2 ;
2006-08-08 09:10:10 -03:00
break ;
case 0x01 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_2_3 ;
2006-08-08 09:10:10 -03:00
break ;
case 0x02 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_3_4 ;
2006-08-08 09:10:10 -03:00
break ;
case 0x03 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_4_5 ;
2006-08-08 09:10:10 -03:00
break ;
case 0x04 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_5_6 ;
2006-08-08 09:10:10 -03:00
break ;
case 0x05 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_6_7 ;
2006-08-08 09:10:10 -03:00
break ;
case 0x06 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_7_8 ;
2006-08-08 09:10:10 -03:00
break ;
case 0x07 :
2011-12-26 14:51:41 -03:00
fe_params - > fec_inner = FEC_8_9 ;
2006-08-08 09:10:10 -03:00
break ;
}
return 0 ;
}
static int tda10086_read_status ( struct dvb_frontend * fe , fe_status_t * fe_status )
{
struct tda10086_state * state = fe - > demodulator_priv ;
u8 val ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
val = tda10086_read_byte ( state , 0x0e ) ;
* fe_status = 0 ;
if ( val & 0x01 )
* fe_status | = FE_HAS_SIGNAL ;
if ( val & 0x02 )
* fe_status | = FE_HAS_CARRIER ;
if ( val & 0x04 )
* fe_status | = FE_HAS_VITERBI ;
if ( val & 0x08 )
* fe_status | = FE_HAS_SYNC ;
2007-05-28 18:06:27 -03:00
if ( val & 0x10 ) {
2006-08-08 09:10:10 -03:00
* fe_status | = FE_HAS_LOCK ;
2007-05-28 18:06:27 -03:00
if ( ! state - > has_lock ) {
state - > has_lock = true ;
2008-04-13 21:09:11 -03:00
/* modify parameters for stable reception */
2007-05-28 18:06:27 -03:00
tda10086_write_byte ( state , 0x02 , 0x00 ) ;
}
}
2006-08-08 09:10:10 -03:00
return 0 ;
}
static int tda10086_read_signal_strength ( struct dvb_frontend * fe , u16 * signal )
{
struct tda10086_state * state = fe - > demodulator_priv ;
u8 _str ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2007-05-28 18:06:27 -03:00
_str = 0xff - tda10086_read_byte ( state , 0x43 ) ;
2006-08-08 09:10:10 -03:00
* signal = ( _str < < 8 ) | _str ;
return 0 ;
}
static int tda10086_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
struct tda10086_state * state = fe - > demodulator_priv ;
u8 _snr ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2007-05-28 18:06:27 -03:00
_snr = 0xff - tda10086_read_byte ( state , 0x1c ) ;
2006-08-08 09:10:10 -03:00
* snr = ( _snr < < 8 ) | _snr ;
return 0 ;
}
static int tda10086_read_ucblocks ( struct dvb_frontend * fe , u32 * ucblocks )
{
struct tda10086_state * state = fe - > demodulator_priv ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* read it */
2006-08-08 09:10:10 -03:00
* ucblocks = tda10086_read_byte ( state , 0x18 ) & 0x7f ;
2008-04-13 21:09:11 -03:00
/* reset counter */
2006-08-08 09:10:10 -03:00
tda10086_write_byte ( state , 0x18 , 0x00 ) ;
tda10086_write_byte ( state , 0x18 , 0x80 ) ;
return 0 ;
}
static int tda10086_read_ber ( struct dvb_frontend * fe , u32 * ber )
{
struct tda10086_state * state = fe - > demodulator_priv ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
2008-04-13 21:09:11 -03:00
/* read it */
2006-08-08 09:10:10 -03:00
* ber = 0 ;
* ber | = tda10086_read_byte ( state , 0x15 ) ;
* ber | = tda10086_read_byte ( state , 0x16 ) < < 8 ;
* ber | = ( tda10086_read_byte ( state , 0x17 ) & 0xf ) < < 16 ;
return 0 ;
}
static int tda10086_sleep ( struct dvb_frontend * fe )
{
struct tda10086_state * state = fe - > demodulator_priv ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
tda10086_write_mask ( state , 0x00 , 0x08 , 0x08 ) ;
return 0 ;
}
static int tda10086_i2c_gate_ctrl ( struct dvb_frontend * fe , int enable )
{
struct tda10086_state * state = fe - > demodulator_priv ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
if ( enable ) {
tda10086_write_mask ( state , 0x00 , 0x10 , 0x10 ) ;
} else {
tda10086_write_mask ( state , 0x00 , 0x10 , 0x00 ) ;
}
return 0 ;
}
static int tda10086_get_tune_settings ( struct dvb_frontend * fe , struct dvb_frontend_tune_settings * fesettings )
{
2011-12-26 16:59:09 -03:00
struct dtv_frontend_properties * p = & fe - > dtv_property_cache ;
if ( p - > symbol_rate > 20000000 ) {
2006-08-08 09:10:10 -03:00
fesettings - > min_delay_ms = 50 ;
fesettings - > step_size = 2000 ;
fesettings - > max_drift = 8000 ;
2011-12-26 16:59:09 -03:00
} else if ( p - > symbol_rate > 12000000 ) {
2006-08-08 09:10:10 -03:00
fesettings - > min_delay_ms = 100 ;
fesettings - > step_size = 1500 ;
fesettings - > max_drift = 9000 ;
2011-12-26 16:59:09 -03:00
} else if ( p - > symbol_rate > 8000000 ) {
2006-08-08 09:10:10 -03:00
fesettings - > min_delay_ms = 100 ;
fesettings - > step_size = 1000 ;
fesettings - > max_drift = 8000 ;
2011-12-26 16:59:09 -03:00
} else if ( p - > symbol_rate > 4000000 ) {
2006-08-08 09:10:10 -03:00
fesettings - > min_delay_ms = 100 ;
fesettings - > step_size = 500 ;
fesettings - > max_drift = 7000 ;
2011-12-26 16:59:09 -03:00
} else if ( p - > symbol_rate > 2000000 ) {
2006-08-08 09:10:10 -03:00
fesettings - > min_delay_ms = 200 ;
2011-12-26 16:59:09 -03:00
fesettings - > step_size = p - > symbol_rate / 8000 ;
2006-08-08 09:10:10 -03:00
fesettings - > max_drift = 14 * fesettings - > step_size ;
} else {
fesettings - > min_delay_ms = 200 ;
2011-12-26 16:59:09 -03:00
fesettings - > step_size = p - > symbol_rate / 8000 ;
2006-08-08 09:10:10 -03:00
fesettings - > max_drift = 18 * fesettings - > step_size ;
}
return 0 ;
}
static void tda10086_release ( struct dvb_frontend * fe )
{
struct tda10086_state * state = fe - > demodulator_priv ;
tda10086_sleep ( fe ) ;
kfree ( state ) ;
}
static struct dvb_frontend_ops tda10086_ops = {
2011-12-26 14:51:41 -03:00
. delsys = { SYS_DVBS } ,
2006-08-08 09:10:10 -03:00
. info = {
. name = " Philips TDA10086 DVB-S " ,
. frequency_min = 950000 ,
. frequency_max = 2150000 ,
. frequency_stepsize = 125 , /* kHz for QPSK frontends */
. symbol_rate_min = 1000000 ,
. symbol_rate_max = 45000000 ,
. caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK
} ,
. release = tda10086_release ,
. init = tda10086_init ,
. sleep = tda10086_sleep ,
. i2c_gate_ctrl = tda10086_i2c_gate_ctrl ,
2011-12-26 14:51:41 -03:00
. set_frontend = tda10086_set_frontend ,
. get_frontend = tda10086_get_frontend ,
2006-08-08 09:10:10 -03:00
. get_tune_settings = tda10086_get_tune_settings ,
. read_status = tda10086_read_status ,
. read_ber = tda10086_read_ber ,
. read_signal_strength = tda10086_read_signal_strength ,
. read_snr = tda10086_read_snr ,
. read_ucblocks = tda10086_read_ucblocks ,
. diseqc_send_master_cmd = tda10086_send_master_cmd ,
. diseqc_send_burst = tda10086_send_burst ,
. set_tone = tda10086_set_tone ,
} ;
struct dvb_frontend * tda10086_attach ( const struct tda10086_config * config ,
struct i2c_adapter * i2c )
{
struct tda10086_state * state ;
2008-04-08 23:20:00 -03:00
dprintk ( " %s \n " , __func__ ) ;
2006-08-08 09:10:10 -03:00
/* allocate memory for the internal state */
2009-08-10 22:51:01 -03:00
state = kzalloc ( sizeof ( struct tda10086_state ) , GFP_KERNEL ) ;
2006-08-08 09:10:10 -03:00
if ( ! state )
return NULL ;
/* setup the state */
state - > config = config ;
state - > i2c = i2c ;
/* check if the demod is there */
if ( tda10086_read_byte ( state , 0x1e ) ! = 0xe1 ) {
kfree ( state ) ;
return NULL ;
}
/* create dvb_frontend */
memcpy ( & state - > frontend . ops , & tda10086_ops , sizeof ( struct dvb_frontend_ops ) ) ;
state - > frontend . demodulator_priv = state ;
return & state - > frontend ;
}
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Turn on/off frontend debugging (default:off). " ) ;
MODULE_DESCRIPTION ( " Philips TDA10086 DVB-S Demodulator " ) ;
MODULE_AUTHOR ( " Andrew de Quincey " ) ;
MODULE_LICENSE ( " GPL " ) ;
EXPORT_SYMBOL ( tda10086_attach ) ;