2007-10-22 16:56:38 +04:00
/*
2007-11-23 22:52:15 +03:00
tda18271 - fe . c - driver for the Philips / NXP TDA18271 silicon tuner
2007-10-22 16:56:38 +04:00
2008-01-02 07:58:26 +03:00
Copyright ( C ) 2007 , 2008 Michael Krufky < mkrufky @ linuxtv . org >
2007-10-22 16:56:38 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
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/delay.h>
# include <linux/videodev2.h>
2007-11-23 22:52:15 +03:00
# include "tda18271-priv.h"
2013-04-06 21:29:29 +04:00
# include "tda8290.h"
2007-10-22 16:56:38 +04:00
2007-12-02 22:36:05 +03:00
int tda18271_debug ;
2007-11-24 00:14:53 +03:00
module_param_named ( debug , tda18271_debug , int , 0644 ) ;
2008-01-03 07:40:47 +03:00
MODULE_PARM_DESC ( debug , " set debug level "
2008-01-09 06:34:30 +03:00
" (info=1, map=2, reg=4, adv=8, cal=16 (or-able)) " ) ;
2007-10-22 16:56:38 +04:00
2009-08-27 23:58:06 +04:00
static int tda18271_cal_on_startup = - 1 ;
2008-01-14 04:01:07 +03:00
module_param_named ( cal , tda18271_cal_on_startup , int , 0644 ) ;
MODULE_PARM_DESC ( cal , " perform RF tracking filter calibration on startup " ) ;
2008-01-06 21:52:56 +03:00
static DEFINE_MUTEX ( tda18271_list_mutex ) ;
2008-04-22 21:41:54 +04:00
static LIST_HEAD ( hybrid_tuner_instance_list ) ;
2008-01-06 21:52:56 +03:00
2007-10-22 16:56:38 +04:00
/*---------------------------------------------------------------------*/
2009-08-29 23:25:37 +04:00
static int tda18271_toggle_output ( struct dvb_frontend * fe , int standby )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
int ret = tda18271_set_standby_mode ( fe , standby ? 1 : 0 ,
priv - > output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0 ,
priv - > output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0 ) ;
if ( tda_fail ( ret ) )
goto fail ;
tda_dbg ( " %s mode: xtal oscillator %s, slave tuner loop thru %s \n " ,
standby ? " standby " : " active " ,
priv - > output_opt & TDA18271_OUTPUT_XT_OFF ? " off " : " on " ,
priv - > output_opt & TDA18271_OUTPUT_LT_OFF ? " off " : " on " ) ;
fail :
return ret ;
}
/*---------------------------------------------------------------------*/
2008-04-22 21:46:23 +04:00
static inline int charge_pump_source ( struct dvb_frontend * fe , int force )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
return tda18271_charge_pump_source ( fe ,
( priv - > role = = TDA18271_SLAVE ) ?
TDA18271_CAL_PLL :
TDA18271_MAIN_PLL , force ) ;
}
2008-06-09 03:10:29 +04:00
static inline void tda18271_set_if_notch ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
switch ( priv - > mode ) {
case TDA18271_ANALOG :
regs [ R_MPD ] & = ~ 0x80 ; /* IF notch = 0 */
break ;
case TDA18271_DIGITAL :
regs [ R_MPD ] | = 0x80 ; /* IF notch = 1 */
break ;
}
}
2008-01-02 04:52:09 +03:00
static int tda18271_channel_configuration ( struct dvb_frontend * fe ,
2008-04-22 21:46:06 +04:00
struct tda18271_std_map_item * map ,
u32 freq , u32 bw )
2008-01-02 04:52:09 +03:00
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
2008-05-05 02:37:27 +04:00
int ret ;
2008-01-02 04:52:09 +03:00
u32 N ;
/* update TV broadcast parameters */
/* set standard */
regs [ R_EP3 ] & = ~ 0x1f ; /* clear std bits */
2008-04-22 21:46:06 +04:00
regs [ R_EP3 ] | = ( map - > agc_mode < < 3 ) | map - > std ;
2008-01-02 04:52:09 +03:00
2008-06-09 09:03:31 +04:00
if ( priv - > id = = TDA18271HDC2 ) {
/* set rfagc to high speed mode */
regs [ R_EP3 ] & = ~ 0x04 ;
}
2008-04-22 21:46:22 +04:00
2008-01-02 04:52:09 +03:00
/* set cal mode to normal */
regs [ R_EP4 ] & = ~ 0x03 ;
2008-06-09 03:10:29 +04:00
/* update IF output level */
2008-01-02 04:52:09 +03:00
regs [ R_EP4 ] & = ~ 0x1c ; /* clear if level bits */
2008-04-22 21:46:21 +04:00
regs [ R_EP4 ] | = ( map - > if_lvl < < 2 ) ;
2008-01-02 04:52:09 +03:00
2008-04-22 21:46:06 +04:00
/* update FM_RFn */
regs [ R_EP4 ] & = ~ 0x80 ;
regs [ R_EP4 ] | = map - > fm_rfn < < 7 ;
2008-01-02 04:52:09 +03:00
2008-04-22 21:46:22 +04:00
/* update rf top / if top */
regs [ R_EB22 ] = 0x00 ;
regs [ R_EB22 ] | = map - > rfagc_top ;
2008-05-05 02:37:27 +04:00
ret = tda18271_write_regs ( fe , R_EB22 , 1 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-05 02:37:27 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
/* --------------------------------------------------------------- */
/* disable Power Level Indicator */
regs [ R_EP1 ] | = 0x40 ;
2008-06-11 20:52:49 +04:00
/* make sure thermometer is off */
regs [ R_TM ] & = ~ 0x10 ;
2008-01-02 04:52:09 +03:00
/* frequency dependent parameters */
tda18271_calc_ir_measure ( fe , & freq ) ;
tda18271_calc_bp_filter ( fe , & freq ) ;
tda18271_calc_rf_band ( fe , & freq ) ;
tda18271_calc_gain_taper ( fe , & freq ) ;
/* --------------------------------------------------------------- */
/* dual tuner and agc1 extra configuration */
2008-04-22 21:46:23 +04:00
switch ( priv - > role ) {
case TDA18271_MASTER :
regs [ R_EB1 ] | = 0x04 ; /* main vco */
break ;
case TDA18271_SLAVE :
regs [ R_EB1 ] & = ~ 0x04 ; /* cal vco */
break ;
}
2008-01-02 04:52:09 +03:00
/* agc1 always active */
regs [ R_EB1 ] & = ~ 0x02 ;
/* agc1 has priority on agc2 */
regs [ R_EB1 ] & = ~ 0x01 ;
2008-05-05 02:37:27 +04:00
ret = tda18271_write_regs ( fe , R_EB1 , 1 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-05 02:37:27 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
/* --------------------------------------------------------------- */
2008-04-22 21:46:06 +04:00
N = map - > if_freq * 1000 + freq ;
2008-01-02 04:52:09 +03:00
2008-04-22 21:46:23 +04:00
switch ( priv - > role ) {
case TDA18271_MASTER :
tda18271_calc_main_pll ( fe , N ) ;
2008-06-09 03:10:29 +04:00
tda18271_set_if_notch ( fe ) ;
2008-04-22 21:46:23 +04:00
tda18271_write_regs ( fe , R_MPD , 4 ) ;
break ;
case TDA18271_SLAVE :
tda18271_calc_cal_pll ( fe , N ) ;
tda18271_write_regs ( fe , R_CPD , 4 ) ;
regs [ R_MPD ] = regs [ R_CPD ] & 0x7f ;
2008-06-09 03:10:29 +04:00
tda18271_set_if_notch ( fe ) ;
2008-04-22 21:46:23 +04:00
tda18271_write_regs ( fe , R_MPD , 1 ) ;
break ;
}
2008-01-02 04:52:09 +03:00
2008-05-05 02:37:27 +04:00
ret = tda18271_write_regs ( fe , R_TM , 7 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-05 02:37:27 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
2008-04-22 21:46:23 +04:00
/* force charge pump source */
charge_pump_source ( fe , 1 ) ;
2008-01-02 04:52:09 +03:00
msleep ( 1 ) ;
2008-04-22 21:46:23 +04:00
/* return pll to normal operation */
charge_pump_source ( fe , 0 ) ;
2008-01-02 04:52:09 +03:00
2008-04-22 21:46:22 +04:00
msleep ( 20 ) ;
2008-06-09 09:03:31 +04:00
if ( priv - > id = = TDA18271HDC2 ) {
/* set rfagc to normal speed mode */
if ( map - > fm_rfn )
regs [ R_EP3 ] & = ~ 0x04 ;
else
regs [ R_EP3 ] | = 0x04 ;
ret = tda18271_write_regs ( fe , R_EP3 , 1 ) ;
}
2008-05-05 02:37:27 +04:00
fail :
return ret ;
2008-01-02 04:52:09 +03:00
}
static int tda18271_read_thermometer ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
int tm ;
/* switch thermometer on */
regs [ R_TM ] | = 0x10 ;
tda18271_write_regs ( fe , R_TM , 1 ) ;
/* read thermometer info */
tda18271_read_regs ( fe ) ;
if ( ( ( ( regs [ R_TM ] & 0x0f ) = = 0x00 ) & & ( ( regs [ R_TM ] & 0x20 ) = = 0x20 ) ) | |
( ( ( regs [ R_TM ] & 0x0f ) = = 0x08 ) & & ( ( regs [ R_TM ] & 0x20 ) = = 0x00 ) ) ) {
if ( ( regs [ R_TM ] & 0x20 ) = = 0x20 )
regs [ R_TM ] & = ~ 0x20 ;
else
regs [ R_TM ] | = 0x20 ;
tda18271_write_regs ( fe , R_TM , 1 ) ;
msleep ( 10 ) ; /* temperature sensing */
/* read thermometer info */
tda18271_read_regs ( fe ) ;
}
tm = tda18271_lookup_thermometer ( fe ) ;
/* switch thermometer off */
regs [ R_TM ] & = ~ 0x10 ;
tda18271_write_regs ( fe , R_TM , 1 ) ;
/* set CAL mode to normal */
regs [ R_EP4 ] & = ~ 0x03 ;
tda18271_write_regs ( fe , R_EP4 , 1 ) ;
return tm ;
}
2008-04-22 21:42:07 +04:00
/* ------------------------------------------------------------------ */
2008-04-22 21:42:07 +04:00
static int tda18271c2_rf_tracking_filters_correction ( struct dvb_frontend * fe ,
u32 freq )
2008-01-02 04:52:09 +03:00
{
struct tda18271_priv * priv = fe - > tuner_priv ;
struct tda18271_rf_tracking_filter_cal * map = priv - > rf_cal_state ;
unsigned char * regs = priv - > tda18271_regs ;
2009-09-28 06:10:20 +04:00
int i , ret ;
u8 tm_current , dc_over_dt , rf_tab ;
s32 rfcal_comp , approx ;
2008-01-02 04:52:09 +03:00
/* power up */
2008-05-05 02:57:06 +04:00
ret = tda18271_set_standby_mode ( fe , 0 , 0 , 0 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-05 02:57:06 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
/* read die current temperature */
tm_current = tda18271_read_thermometer ( fe ) ;
/* frequency dependent parameters */
tda18271_calc_rf_cal ( fe , & freq ) ;
rf_tab = regs [ R_EB14 ] ;
i = tda18271_lookup_rf_band ( fe , & freq , NULL ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( i ) )
return i ;
2008-01-02 04:52:09 +03:00
if ( ( 0 = = map [ i ] . rf3 ) | | ( freq / 1000 < map [ i ] . rf2 ) ) {
2009-09-28 06:10:20 +04:00
approx = map [ i ] . rf_a1 * ( s32 ) ( freq / 1000 - map [ i ] . rf1 ) +
map [ i ] . rf_b1 + rf_tab ;
2008-01-02 04:52:09 +03:00
} else {
2009-09-28 06:10:20 +04:00
approx = map [ i ] . rf_a2 * ( s32 ) ( freq / 1000 - map [ i ] . rf2 ) +
map [ i ] . rf_b2 + rf_tab ;
2008-01-02 04:52:09 +03:00
}
if ( approx < 0 )
approx = 0 ;
if ( approx > 255 )
approx = 255 ;
tda18271_lookup_map ( fe , RF_CAL_DC_OVER_DT , & freq , & dc_over_dt ) ;
/* calculate temperature compensation */
2009-09-28 06:10:20 +04:00
rfcal_comp = dc_over_dt * ( s32 ) ( tm_current - priv - > tm_rfcal ) / 1000 ;
2008-01-02 04:52:09 +03:00
2009-09-28 06:10:20 +04:00
regs [ R_EB14 ] = ( unsigned char ) ( approx + rfcal_comp ) ;
2008-05-05 02:57:06 +04:00
ret = tda18271_write_regs ( fe , R_EB14 , 1 ) ;
fail :
return ret ;
2008-01-02 04:52:09 +03:00
}
static int tda18271_por ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
2008-05-04 02:28:00 +04:00
int ret ;
2008-01-02 04:52:09 +03:00
/* power up detector 1 */
regs [ R_EB12 ] & = ~ 0x20 ;
2008-05-04 02:28:00 +04:00
ret = tda18271_write_regs ( fe , R_EB12 , 1 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
regs [ R_EB18 ] & = ~ 0x80 ; /* turn agc1 loop on */
regs [ R_EB18 ] & = ~ 0x03 ; /* set agc1_gain to 6 dB */
2008-05-04 02:28:00 +04:00
ret = tda18271_write_regs ( fe , R_EB18 , 1 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
regs [ R_EB21 ] | = 0x03 ; /* set agc2_gain to -6 dB */
/* POR mode */
2008-05-04 02:28:00 +04:00
ret = tda18271_set_standby_mode ( fe , 1 , 0 , 0 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
/* disable 1.5 MHz low pass filter */
regs [ R_EB23 ] & = ~ 0x04 ; /* forcelp_fc2_en = 0 */
regs [ R_EB23 ] & = ~ 0x02 ; /* XXX: lp_fc[2] = 0 */
2008-05-04 02:28:00 +04:00
ret = tda18271_write_regs ( fe , R_EB21 , 3 ) ;
fail :
return ret ;
2008-01-02 04:52:09 +03:00
}
static int tda18271_calibrate_rf ( struct dvb_frontend * fe , u32 freq )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
u32 N ;
/* set CAL mode to normal */
regs [ R_EP4 ] & = ~ 0x03 ;
tda18271_write_regs ( fe , R_EP4 , 1 ) ;
/* switch off agc1 */
regs [ R_EP3 ] | = 0x40 ; /* sm_lt = 1 */
regs [ R_EB18 ] | = 0x03 ; /* set agc1_gain to 15 dB */
tda18271_write_regs ( fe , R_EB18 , 1 ) ;
/* frequency dependent parameters */
tda18271_calc_bp_filter ( fe , & freq ) ;
tda18271_calc_gain_taper ( fe , & freq ) ;
tda18271_calc_rf_band ( fe , & freq ) ;
tda18271_calc_km ( fe , & freq ) ;
tda18271_write_regs ( fe , R_EP1 , 3 ) ;
tda18271_write_regs ( fe , R_EB13 , 1 ) ;
/* main pll charge pump source */
2008-04-22 21:46:23 +04:00
tda18271_charge_pump_source ( fe , TDA18271_MAIN_PLL , 1 ) ;
2008-01-02 04:52:09 +03:00
/* cal pll charge pump source */
2008-04-22 21:46:23 +04:00
tda18271_charge_pump_source ( fe , TDA18271_CAL_PLL , 1 ) ;
2008-01-02 04:52:09 +03:00
/* force dcdc converter to 0 V */
regs [ R_EB14 ] = 0x00 ;
tda18271_write_regs ( fe , R_EB14 , 1 ) ;
/* disable plls lock */
regs [ R_EB20 ] & = ~ 0x20 ;
tda18271_write_regs ( fe , R_EB20 , 1 ) ;
/* set CAL mode to RF tracking filter calibration */
regs [ R_EP4 ] | = 0x03 ;
tda18271_write_regs ( fe , R_EP4 , 2 ) ;
/* --------------------------------------------------------------- */
/* set the internal calibration signal */
N = freq ;
2008-04-22 21:46:21 +04:00
tda18271_calc_cal_pll ( fe , N ) ;
tda18271_write_regs ( fe , R_CPD , 4 ) ;
2008-01-02 04:52:09 +03:00
/* downconvert internal calibration */
N + = 1000000 ;
tda18271_calc_main_pll ( fe , N ) ;
tda18271_write_regs ( fe , R_MPD , 4 ) ;
msleep ( 5 ) ;
tda18271_write_regs ( fe , R_EP2 , 1 ) ;
tda18271_write_regs ( fe , R_EP1 , 1 ) ;
tda18271_write_regs ( fe , R_EP2 , 1 ) ;
tda18271_write_regs ( fe , R_EP1 , 1 ) ;
/* --------------------------------------------------------------- */
/* normal operation for the main pll */
2008-04-22 21:46:23 +04:00
tda18271_charge_pump_source ( fe , TDA18271_MAIN_PLL , 0 ) ;
2008-01-02 04:52:09 +03:00
/* normal operation for the cal pll */
2008-04-22 21:46:23 +04:00
tda18271_charge_pump_source ( fe , TDA18271_CAL_PLL , 0 ) ;
2008-01-02 04:52:09 +03:00
2008-04-22 21:46:21 +04:00
msleep ( 10 ) ; /* plls locking */
2008-01-02 04:52:09 +03:00
/* launch the rf tracking filters calibration */
regs [ R_EB20 ] | = 0x20 ;
tda18271_write_regs ( fe , R_EB20 , 1 ) ;
msleep ( 60 ) ; /* calibration */
/* --------------------------------------------------------------- */
/* set CAL mode to normal */
regs [ R_EP4 ] & = ~ 0x03 ;
/* switch on agc1 */
regs [ R_EP3 ] & = ~ 0x40 ; /* sm_lt = 0 */
regs [ R_EB18 ] & = ~ 0x03 ; /* set agc1_gain to 6 dB */
tda18271_write_regs ( fe , R_EB18 , 1 ) ;
tda18271_write_regs ( fe , R_EP3 , 2 ) ;
/* synchronization */
tda18271_write_regs ( fe , R_EP1 , 1 ) ;
/* get calibration result */
tda18271_read_extended ( fe ) ;
return regs [ R_EB14 ] ;
}
static int tda18271_powerscan ( struct dvb_frontend * fe ,
u32 * freq_in , u32 * freq_out )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
2008-05-04 02:28:00 +04:00
int sgn , bcal , count , wait , ret ;
2008-01-02 04:52:09 +03:00
u8 cid_target ;
u16 count_limit ;
u32 freq ;
freq = * freq_in ;
tda18271_calc_rf_band ( fe , & freq ) ;
tda18271_calc_rf_cal ( fe , & freq ) ;
tda18271_calc_gain_taper ( fe , & freq ) ;
tda18271_lookup_cid_target ( fe , & freq , & cid_target , & count_limit ) ;
tda18271_write_regs ( fe , R_EP2 , 1 ) ;
tda18271_write_regs ( fe , R_EB14 , 1 ) ;
/* downconvert frequency */
freq + = 1000000 ;
tda18271_calc_main_pll ( fe , freq ) ;
tda18271_write_regs ( fe , R_MPD , 4 ) ;
msleep ( 5 ) ; /* pll locking */
/* detection mode */
regs [ R_EP4 ] & = ~ 0x03 ;
regs [ R_EP4 ] | = 0x01 ;
tda18271_write_regs ( fe , R_EP4 , 1 ) ;
/* launch power detection measurement */
tda18271_write_regs ( fe , R_EP2 , 1 ) ;
/* read power detection info, stored in EB10 */
2008-05-04 02:28:00 +04:00
ret = tda18271_read_extended ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
return ret ;
2008-01-02 04:52:09 +03:00
/* algorithm initialization */
sgn = 1 ;
* freq_out = * freq_in ;
bcal = 0 ;
count = 0 ;
wait = false ;
while ( ( regs [ R_EB10 ] & 0x3f ) < cid_target ) {
/* downconvert updated freq to 1 MHz */
freq = * freq_in + ( sgn * count ) + 1000000 ;
tda18271_calc_main_pll ( fe , freq ) ;
tda18271_write_regs ( fe , R_MPD , 4 ) ;
if ( wait ) {
msleep ( 5 ) ; /* pll locking */
wait = false ;
} else
udelay ( 100 ) ; /* pll locking */
/* launch power detection measurement */
tda18271_write_regs ( fe , R_EP2 , 1 ) ;
/* read power detection info, stored in EB10 */
2008-05-04 02:28:00 +04:00
ret = tda18271_read_extended ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
return ret ;
2008-01-02 04:52:09 +03:00
count + = 200 ;
2008-04-22 21:46:22 +04:00
if ( count < = count_limit )
2008-01-02 04:52:09 +03:00
continue ;
if ( sgn < = 0 )
break ;
sgn = - 1 * sgn ;
count = 200 ;
wait = true ;
}
if ( ( regs [ R_EB10 ] & 0x3f ) > = cid_target ) {
bcal = 1 ;
* freq_out = freq - 1000000 ;
} else
bcal = 0 ;
2008-01-09 06:34:30 +03:00
tda_cal ( " bcal = %d, freq_in = %d, freq_out = %d (freq = %d) \n " ,
2008-01-02 04:52:09 +03:00
bcal , * freq_in , * freq_out , freq ) ;
return bcal ;
}
static int tda18271_powerscan_init ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
2008-05-04 02:28:00 +04:00
int ret ;
2008-01-02 04:52:09 +03:00
/* set standard to digital */
regs [ R_EP3 ] & = ~ 0x1f ; /* clear std bits */
regs [ R_EP3 ] | = 0x12 ;
/* set cal mode to normal */
regs [ R_EP4 ] & = ~ 0x03 ;
2008-06-09 03:10:29 +04:00
/* update IF output level */
2008-01-02 04:52:09 +03:00
regs [ R_EP4 ] & = ~ 0x1c ; /* clear if level bits */
2008-05-04 02:28:00 +04:00
ret = tda18271_write_regs ( fe , R_EP3 , 2 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
regs [ R_EB18 ] & = ~ 0x03 ; /* set agc1_gain to 6 dB */
2008-05-04 02:28:00 +04:00
ret = tda18271_write_regs ( fe , R_EB18 , 1 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
regs [ R_EB21 ] & = ~ 0x03 ; /* set agc2_gain to -15 dB */
/* 1.5 MHz low pass filter */
regs [ R_EB23 ] | = 0x04 ; /* forcelp_fc2_en = 1 */
regs [ R_EB23 ] | = 0x02 ; /* lp_fc[2] = 1 */
2008-05-04 02:28:00 +04:00
ret = tda18271_write_regs ( fe , R_EB21 , 3 ) ;
fail :
return ret ;
2008-01-02 04:52:09 +03:00
}
static int tda18271_rf_tracking_filters_init ( struct dvb_frontend * fe , u32 freq )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
struct tda18271_rf_tracking_filter_cal * map = priv - > rf_cal_state ;
unsigned char * regs = priv - > tda18271_regs ;
int bcal , rf , i ;
2009-09-28 00:00:13 +04:00
s32 divisor , dividend ;
2008-01-02 04:52:09 +03:00
# define RF1 0
# define RF2 1
# define RF3 2
u32 rf_default [ 3 ] ;
u32 rf_freq [ 3 ] ;
2011-04-16 20:22:10 +04:00
s32 prog_cal [ 3 ] ;
s32 prog_tab [ 3 ] ;
2008-01-02 04:52:09 +03:00
i = tda18271_lookup_rf_band ( fe , & freq , NULL ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( i ) )
2008-01-02 04:52:09 +03:00
return i ;
rf_default [ RF1 ] = 1000 * map [ i ] . rf1_def ;
rf_default [ RF2 ] = 1000 * map [ i ] . rf2_def ;
rf_default [ RF3 ] = 1000 * map [ i ] . rf3_def ;
for ( rf = RF1 ; rf < = RF3 ; rf + + ) {
if ( 0 = = rf_default [ rf ] )
return 0 ;
2008-01-09 06:34:30 +03:00
tda_cal ( " freq = %d, rf = %d \n " , freq , rf ) ;
2008-01-02 04:52:09 +03:00
/* look for optimized calibration frequency */
bcal = tda18271_powerscan ( fe , & rf_default [ rf ] , & rf_freq [ rf ] ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( bcal ) )
2008-05-04 02:28:00 +04:00
return bcal ;
2008-01-02 04:52:09 +03:00
tda18271_calc_rf_cal ( fe , & rf_freq [ rf ] ) ;
2011-04-16 20:22:10 +04:00
prog_tab [ rf ] = ( s32 ) regs [ R_EB14 ] ;
2008-01-02 04:52:09 +03:00
if ( 1 = = bcal )
2011-04-16 20:22:10 +04:00
prog_cal [ rf ] =
( s32 ) tda18271_calibrate_rf ( fe , rf_freq [ rf ] ) ;
2008-01-02 04:52:09 +03:00
else
prog_cal [ rf ] = prog_tab [ rf ] ;
switch ( rf ) {
case RF1 :
map [ i ] . rf_a1 = 0 ;
2011-04-16 20:22:10 +04:00
map [ i ] . rf_b1 = ( prog_cal [ RF1 ] - prog_tab [ RF1 ] ) ;
2008-01-02 04:52:09 +03:00
map [ i ] . rf1 = rf_freq [ RF1 ] / 1000 ;
break ;
case RF2 :
2011-04-16 20:22:10 +04:00
dividend = ( prog_cal [ RF2 ] - prog_tab [ RF2 ] -
prog_cal [ RF1 ] + prog_tab [ RF1 ] ) ;
2009-09-28 00:00:13 +04:00
divisor = ( s32 ) ( rf_freq [ RF2 ] - rf_freq [ RF1 ] ) / 1000 ;
map [ i ] . rf_a1 = ( dividend / divisor ) ;
2008-01-02 04:52:09 +03:00
map [ i ] . rf2 = rf_freq [ RF2 ] / 1000 ;
break ;
case RF3 :
2011-04-16 20:22:10 +04:00
dividend = ( prog_cal [ RF3 ] - prog_tab [ RF3 ] -
prog_cal [ RF2 ] + prog_tab [ RF2 ] ) ;
2009-09-28 00:00:13 +04:00
divisor = ( s32 ) ( rf_freq [ RF3 ] - rf_freq [ RF2 ] ) / 1000 ;
map [ i ] . rf_a2 = ( dividend / divisor ) ;
2011-04-16 20:22:10 +04:00
map [ i ] . rf_b2 = ( prog_cal [ RF2 ] - prog_tab [ RF2 ] ) ;
2008-01-02 04:52:09 +03:00
map [ i ] . rf3 = rf_freq [ RF3 ] / 1000 ;
break ;
default :
BUG ( ) ;
}
}
return 0 ;
}
2008-01-06 02:00:09 +03:00
static int tda18271_calc_rf_filter_curve ( struct dvb_frontend * fe )
2008-01-02 04:52:09 +03:00
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned int i ;
2008-05-04 02:28:00 +04:00
int ret ;
2008-01-02 04:52:09 +03:00
tda_info ( " tda18271: performing RF tracking filter calibration \n " ) ;
/* wait for die temperature stabilization */
msleep ( 200 ) ;
2008-05-04 02:28:00 +04:00
ret = tda18271_powerscan_init ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
/* rf band calibration */
2008-05-05 00:54:23 +04:00
for ( i = 0 ; priv - > rf_cal_state [ i ] . rfmax ! = 0 ; i + + ) {
ret =
2008-01-02 04:52:09 +03:00
tda18271_rf_tracking_filters_init ( fe , 1000 *
priv - > rf_cal_state [ i ] . rfmax ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-05 00:54:23 +04:00
goto fail ;
}
2008-01-02 04:52:09 +03:00
2008-01-06 02:00:09 +03:00
priv - > tm_rfcal = tda18271_read_thermometer ( fe ) ;
2008-05-04 02:28:00 +04:00
fail :
return ret ;
2008-01-02 04:52:09 +03:00
}
/* ------------------------------------------------------------------ */
2008-04-22 21:42:07 +04:00
static int tda18271c2_rf_cal_init ( struct dvb_frontend * fe )
2008-01-02 04:52:09 +03:00
{
struct tda18271_priv * priv = fe - > tuner_priv ;
2008-01-14 00:29:44 +03:00
unsigned char * regs = priv - > tda18271_regs ;
2008-05-04 02:28:00 +04:00
int ret ;
2008-01-14 00:29:44 +03:00
/* test RF_CAL_OK to see if we need init */
if ( ( regs [ R_EP1 ] & 0x10 ) = = 0 )
priv - > cal_initialized = false ;
2008-01-02 04:52:09 +03:00
if ( priv - > cal_initialized )
return 0 ;
2008-05-04 02:28:00 +04:00
ret = tda18271_calc_rf_filter_curve ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
2008-05-04 02:28:00 +04:00
ret = tda18271_por ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 02:28:00 +04:00
goto fail ;
2008-01-02 04:52:09 +03:00
2008-01-07 06:51:48 +03:00
tda_info ( " tda18271: RF tracking filter calibration complete \n " ) ;
2008-01-02 04:52:09 +03:00
priv - > cal_initialized = true ;
2008-05-05 00:54:23 +04:00
goto end ;
2008-05-04 02:28:00 +04:00
fail :
2008-05-05 00:54:23 +04:00
tda_info ( " tda18271: RF tracking filter calibration failed! \n " ) ;
end :
2008-05-04 02:28:00 +04:00
return ret ;
2008-01-02 04:52:09 +03:00
}
2008-04-22 21:42:07 +04:00
static int tda18271c1_rf_tracking_filter_calibration ( struct dvb_frontend * fe ,
u32 freq , u32 bw )
2007-10-22 16:56:38 +04:00
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
2008-05-05 03:26:47 +04:00
int ret ;
2007-12-24 11:05:05 +03:00
u32 N = 0 ;
2007-10-22 16:56:38 +04:00
2008-01-02 04:52:09 +03:00
/* calculate bp filter */
2007-12-26 00:54:22 +03:00
tda18271_calc_bp_filter ( fe , & freq ) ;
2007-10-22 16:56:38 +04:00
tda18271_write_regs ( fe , R_EP1 , 1 ) ;
regs [ R_EB4 ] & = 0x07 ;
regs [ R_EB4 ] | = 0x60 ;
tda18271_write_regs ( fe , R_EB4 , 1 ) ;
regs [ R_EB7 ] = 0x60 ;
tda18271_write_regs ( fe , R_EB7 , 1 ) ;
regs [ R_EB14 ] = 0x00 ;
tda18271_write_regs ( fe , R_EB14 , 1 ) ;
regs [ R_EB20 ] = 0xcc ;
tda18271_write_regs ( fe , R_EB20 , 1 ) ;
2008-01-02 04:52:09 +03:00
/* set cal mode to RF tracking filter calibration */
2007-12-21 20:28:46 +03:00
regs [ R_EP4 ] | = 0x03 ;
2007-10-22 16:56:38 +04:00
2008-01-02 04:52:09 +03:00
/* calculate cal pll */
2007-10-22 16:56:38 +04:00
switch ( priv - > mode ) {
case TDA18271_ANALOG :
N = freq - 1250000 ;
break ;
case TDA18271_DIGITAL :
N = freq + bw / 2 ;
break ;
}
2007-12-24 11:05:05 +03:00
tda18271_calc_cal_pll ( fe , N ) ;
2007-10-22 16:56:38 +04:00
2008-01-02 04:52:09 +03:00
/* calculate main pll */
2007-10-22 16:56:38 +04:00
switch ( priv - > mode ) {
case TDA18271_ANALOG :
N = freq - 250000 ;
break ;
case TDA18271_DIGITAL :
N = freq + bw / 2 + 1000000 ;
break ;
}
2007-12-24 11:05:05 +03:00
tda18271_calc_main_pll ( fe , N ) ;
2007-10-22 16:56:38 +04:00
2008-05-05 03:26:47 +04:00
ret = tda18271_write_regs ( fe , R_EP3 , 11 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-05 03:26:47 +04:00
return ret ;
2007-10-22 16:56:38 +04:00
msleep ( 5 ) ; /* RF tracking filter calibration initialization */
2008-01-02 04:52:09 +03:00
/* search for K,M,CO for RF calibration */
2007-12-26 00:54:22 +03:00
tda18271_calc_km ( fe , & freq ) ;
2007-10-22 16:56:38 +04:00
tda18271_write_regs ( fe , R_EB13 , 1 ) ;
2008-01-02 04:52:09 +03:00
/* search for rf band */
2007-12-26 00:54:22 +03:00
tda18271_calc_rf_band ( fe , & freq ) ;
2007-10-22 16:56:38 +04:00
2008-01-02 04:52:09 +03:00
/* search for gain taper */
2007-12-26 00:54:22 +03:00
tda18271_calc_gain_taper ( fe , & freq ) ;
2007-10-22 16:56:38 +04:00
tda18271_write_regs ( fe , R_EP2 , 1 ) ;
tda18271_write_regs ( fe , R_EP1 , 1 ) ;
tda18271_write_regs ( fe , R_EP2 , 1 ) ;
tda18271_write_regs ( fe , R_EP1 , 1 ) ;
regs [ R_EB4 ] & = 0x07 ;
regs [ R_EB4 ] | = 0x40 ;
tda18271_write_regs ( fe , R_EB4 , 1 ) ;
regs [ R_EB7 ] = 0x40 ;
tda18271_write_regs ( fe , R_EB7 , 1 ) ;
2008-04-22 21:42:07 +04:00
msleep ( 10 ) ; /* pll locking */
2007-10-22 16:56:38 +04:00
regs [ R_EB20 ] = 0xec ;
tda18271_write_regs ( fe , R_EB20 , 1 ) ;
msleep ( 60 ) ; /* RF tracking filter calibration completion */
regs [ R_EP4 ] & = ~ 0x03 ; /* set cal mode to normal */
tda18271_write_regs ( fe , R_EP4 , 1 ) ;
tda18271_write_regs ( fe , R_EP1 , 1 ) ;
2007-12-26 00:54:22 +03:00
/* RF tracking filter correction for VHF_Low band */
if ( 0 = = tda18271_calc_rf_cal ( fe , & freq ) )
2007-10-22 16:56:38 +04:00
tda18271_write_regs ( fe , R_EB14 , 1 ) ;
2008-04-22 21:42:07 +04:00
return 0 ;
}
2008-04-22 21:42:07 +04:00
/* ------------------------------------------------------------------ */
2008-04-22 21:42:07 +04:00
static int tda18271_ir_cal_init ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
2008-05-04 01:20:21 +04:00
int ret ;
2008-04-22 21:42:07 +04:00
2008-05-04 01:20:21 +04:00
ret = tda18271_read_regs ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 01:20:21 +04:00
goto fail ;
2008-04-22 21:42:07 +04:00
/* test IR_CAL_OK to see if we need init */
if ( ( regs [ R_EP1 ] & 0x08 ) = = 0 )
2008-05-04 01:20:21 +04:00
ret = tda18271_init_regs ( fe ) ;
fail :
return ret ;
2008-04-22 21:42:07 +04:00
}
static int tda18271_init ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
2008-05-04 01:20:21 +04:00
int ret ;
2008-04-22 21:42:07 +04:00
mutex_lock ( & priv - > lock ) ;
2009-08-29 23:25:37 +04:00
/* full power up */
2008-05-04 01:20:21 +04:00
ret = tda18271_set_standby_mode ( fe , 0 , 0 , 0 ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 01:20:21 +04:00
goto fail ;
2008-04-22 21:42:07 +04:00
/* initialization */
2008-05-04 01:20:21 +04:00
ret = tda18271_ir_cal_init ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 01:20:21 +04:00
goto fail ;
2008-04-22 21:42:07 +04:00
if ( priv - > id = = TDA18271HDC2 )
tda18271c2_rf_cal_init ( fe ) ;
2008-05-04 01:20:21 +04:00
fail :
2008-04-22 21:42:07 +04:00
mutex_unlock ( & priv - > lock ) ;
2008-05-04 01:20:21 +04:00
return ret ;
2008-04-22 21:42:07 +04:00
}
2009-08-29 23:27:21 +04:00
static int tda18271_sleep ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
int ret ;
mutex_lock ( & priv - > lock ) ;
/* enter standby mode, with required output features enabled */
ret = tda18271_toggle_output ( fe , 1 ) ;
mutex_unlock ( & priv - > lock ) ;
return ret ;
}
2009-03-05 01:42:06 +03:00
/* ------------------------------------------------------------------ */
static int tda18271_agc ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
int ret = 0 ;
switch ( priv - > config ) {
2013-04-06 21:29:29 +04:00
case TDA8290_LNA_OFF :
2009-09-06 21:38:48 +04:00
/* no external agc configuration required */
if ( tda18271_debug & DBG_ADV )
tda_dbg ( " no agc configuration provided \n " ) ;
2009-03-05 01:42:06 +03:00
break ;
2013-04-06 21:29:29 +04:00
case TDA8290_LNA_ON_BRIDGE :
2009-03-05 01:42:06 +03:00
/* switch with GPIO of saa713x */
tda_dbg ( " invoking callback \n " ) ;
if ( fe - > callback )
ret = fe - > callback ( priv - > i2c_props . adap - > algo_data ,
DVB_FRONTEND_COMPONENT_TUNER ,
TDA18271_CALLBACK_CMD_AGC_ENABLE ,
priv - > mode ) ;
break ;
2013-04-06 21:29:29 +04:00
case TDA8290_LNA_GP0_HIGH_ON :
case TDA8290_LNA_GP0_HIGH_OFF :
2009-03-05 01:42:06 +03:00
default :
/* n/a - currently not supported */
tda_err ( " unsupported configuration: %d \n " , priv - > config ) ;
ret = - EINVAL ;
break ;
}
return ret ;
}
2008-04-22 21:42:07 +04:00
static int tda18271_tune ( struct dvb_frontend * fe ,
2008-04-22 21:46:06 +04:00
struct tda18271_std_map_item * map , u32 freq , u32 bw )
2008-04-22 21:42:07 +04:00
{
struct tda18271_priv * priv = fe - > tuner_priv ;
2008-05-04 01:20:21 +04:00
int ret ;
2008-04-22 21:42:07 +04:00
2008-04-22 21:46:06 +04:00
tda_dbg ( " freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d \n " ,
freq , map - > if_freq , bw , map - > agc_mode , map - > std ) ;
2008-04-22 21:42:07 +04:00
2009-03-05 01:42:06 +03:00
ret = tda18271_agc ( fe ) ;
if ( tda_fail ( ret ) )
tda_warn ( " failed to configure agc \n " ) ;
2008-05-04 01:20:21 +04:00
ret = tda18271_init ( fe ) ;
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-05-04 01:20:21 +04:00
goto fail ;
2008-04-22 21:42:07 +04:00
mutex_lock ( & priv - > lock ) ;
2008-01-06 06:55:21 +03:00
switch ( priv - > id ) {
case TDA18271HDC1 :
2008-04-22 21:42:07 +04:00
tda18271c1_rf_tracking_filter_calibration ( fe , freq , bw ) ;
2008-01-06 06:55:21 +03:00
break ;
case TDA18271HDC2 :
2008-04-22 21:42:07 +04:00
tda18271c2_rf_tracking_filters_correction ( fe , freq ) ;
2008-01-06 06:55:21 +03:00
break ;
}
2008-05-05 02:37:27 +04:00
ret = tda18271_channel_configuration ( fe , map , freq , bw ) ;
2008-04-22 21:42:07 +04:00
mutex_unlock ( & priv - > lock ) ;
2008-05-04 01:20:21 +04:00
fail :
return ret ;
2008-01-06 06:55:21 +03:00
}
2007-10-22 16:56:38 +04:00
/* ------------------------------------------------------------------ */
2011-12-24 19:24:33 +04:00
static int tda18271_set_params ( struct dvb_frontend * fe )
2007-10-22 16:56:38 +04:00
{
2011-12-21 15:15:29 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
u32 delsys = c - > delivery_system ;
u32 bw = c - > bandwidth_hz ;
u32 freq = c - > frequency ;
2007-10-22 16:56:38 +04:00
struct tda18271_priv * priv = fe - > tuner_priv ;
2008-01-02 09:01:54 +03:00
struct tda18271_std_map * std_map = & priv - > std ;
2008-04-22 21:46:06 +04:00
struct tda18271_std_map_item * map ;
2008-01-06 06:55:21 +03:00
int ret ;
2007-10-22 16:56:38 +04:00
priv - > mode = TDA18271_DIGITAL ;
2011-12-21 15:15:29 +04:00
switch ( delsys ) {
case SYS_ATSC :
map = & std_map - > atsc_6 ;
2007-10-22 16:56:38 +04:00
bw = 6000000 ;
2011-12-21 15:15:29 +04:00
break ;
2012-01-10 00:26:32 +04:00
case SYS_ISDBT :
2011-12-21 15:15:29 +04:00
case SYS_DVBT :
case SYS_DVBT2 :
if ( bw < = 6000000 ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > dvbt_6 ;
2011-12-21 15:15:29 +04:00
} else if ( bw < = 7000000 ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > dvbt_7 ;
2011-12-21 15:15:29 +04:00
} else {
2008-04-22 21:46:06 +04:00
map = & std_map - > dvbt_8 ;
2007-10-22 16:56:38 +04:00
}
2011-12-21 15:15:29 +04:00
break ;
case SYS_DVBC_ANNEX_B :
bw = 6000000 ;
/* falltrough */
case SYS_DVBC_ANNEX_A :
case SYS_DVBC_ANNEX_C :
if ( bw < = 6000000 ) {
map = & std_map - > qam_6 ;
} else if ( bw < = 7000000 ) {
map = & std_map - > qam_7 ;
} else {
map = & std_map - > qam_8 ;
}
break ;
default :
2007-12-25 21:10:11 +03:00
tda_warn ( " modulation type not supported! \n " ) ;
2007-10-22 16:56:38 +04:00
return - EINVAL ;
}
2008-01-19 23:41:04 +03:00
/* When tuning digital, the analog demod must be tri-stated */
if ( fe - > ops . analog_ops . standby )
fe - > ops . analog_ops . standby ( fe ) ;
2008-04-22 21:46:06 +04:00
ret = tda18271_tune ( fe , map , freq , bw ) ;
2008-01-06 06:55:21 +03:00
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-01-06 06:55:21 +03:00
goto fail ;
2011-11-03 16:59:42 +04:00
priv - > if_freq = map - > if_freq ;
2008-01-06 06:55:21 +03:00
priv - > frequency = freq ;
2011-12-27 03:02:28 +04:00
priv - > bandwidth = bw ;
2008-01-06 06:55:21 +03:00
fail :
return ret ;
2007-10-22 16:56:38 +04:00
}
static int tda18271_set_analog_params ( struct dvb_frontend * fe ,
struct analog_parameters * params )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
2008-01-02 09:01:54 +03:00
struct tda18271_std_map * std_map = & priv - > std ;
2008-04-22 21:46:06 +04:00
struct tda18271_std_map_item * map ;
2007-10-22 16:56:38 +04:00
char * mode ;
2008-04-22 21:46:06 +04:00
int ret ;
2009-09-27 21:05:12 +04:00
u32 freq = params - > frequency * 125 *
( ( params - > mode = = V4L2_TUNER_RADIO ) ? 1 : 1000 ) / 2 ;
2007-10-22 16:56:38 +04:00
priv - > mode = TDA18271_ANALOG ;
2008-01-08 16:38:10 +03:00
if ( params - > mode = = V4L2_TUNER_RADIO ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > fm_radio ;
2008-01-08 16:38:10 +03:00
mode = " fm " ;
} else if ( params - > std & V4L2_STD_MN ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_mn ;
2007-10-22 16:56:38 +04:00
mode = " MN " ;
} else if ( params - > std & V4L2_STD_B ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_b ;
2007-10-22 16:56:38 +04:00
mode = " B " ;
} else if ( params - > std & V4L2_STD_GH ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_gh ;
2007-10-22 16:56:38 +04:00
mode = " GH " ;
} else if ( params - > std & V4L2_STD_PAL_I ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_i ;
2007-10-22 16:56:38 +04:00
mode = " I " ;
} else if ( params - > std & V4L2_STD_DK ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_dk ;
2007-10-22 16:56:38 +04:00
mode = " DK " ;
} else if ( params - > std & V4L2_STD_SECAM_L ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_l ;
2007-10-22 16:56:38 +04:00
mode = " L " ;
} else if ( params - > std & V4L2_STD_SECAM_LC ) {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_lc ;
2008-01-02 00:31:34 +03:00
mode = " L' " ;
2007-10-22 16:56:38 +04:00
} else {
2008-04-22 21:46:06 +04:00
map = & std_map - > atv_i ;
2007-10-22 16:56:38 +04:00
mode = " xx " ;
}
2007-12-25 21:10:11 +03:00
tda_dbg ( " setting tda18271 to system %s \n " , mode ) ;
2007-10-22 16:56:38 +04:00
2008-04-22 21:46:06 +04:00
ret = tda18271_tune ( fe , map , freq , 0 ) ;
2008-01-06 06:55:21 +03:00
2008-05-05 04:32:21 +04:00
if ( tda_fail ( ret ) )
2008-01-06 06:55:21 +03:00
goto fail ;
2011-11-03 16:59:42 +04:00
priv - > if_freq = map - > if_freq ;
2008-01-06 06:55:21 +03:00
priv - > frequency = freq ;
priv - > bandwidth = 0 ;
fail :
return ret ;
2007-10-22 16:56:38 +04:00
}
static int tda18271_release ( struct dvb_frontend * fe )
{
2008-01-06 21:52:56 +03:00
struct tda18271_priv * priv = fe - > tuner_priv ;
mutex_lock ( & tda18271_list_mutex ) ;
2008-04-22 21:41:54 +04:00
if ( priv )
hybrid_tuner_release_state ( priv ) ;
2008-01-06 21:52:56 +03:00
mutex_unlock ( & tda18271_list_mutex ) ;
2007-10-22 16:56:38 +04:00
fe - > tuner_priv = NULL ;
2008-01-06 21:52:56 +03:00
2007-10-22 16:56:38 +04:00
return 0 ;
}
static int tda18271_get_frequency ( struct dvb_frontend * fe , u32 * frequency )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
* frequency = priv - > frequency ;
return 0 ;
}
static int tda18271_get_bandwidth ( struct dvb_frontend * fe , u32 * bandwidth )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
* bandwidth = priv - > bandwidth ;
return 0 ;
}
2011-11-03 16:59:42 +04:00
static int tda18271_get_if_frequency ( struct dvb_frontend * fe , u32 * frequency )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
* frequency = ( u32 ) priv - > if_freq * 1000 ;
return 0 ;
}
2008-01-02 09:01:54 +03:00
/* ------------------------------------------------------------------ */
# define tda18271_update_std(std_cfg, name) do { \
2008-04-22 21:46:06 +04:00
if ( map - > std_cfg . if_freq + \
2008-03-31 02:40:20 +04:00
map - > std_cfg . agc_mode + map - > std_cfg . std + \
map - > std_cfg . if_lvl + map - > std_cfg . rfagc_top > 0 ) { \
2008-01-02 09:01:54 +03:00
tda_dbg ( " Using custom std config for %s \n " , name ) ; \
memcpy ( & std - > std_cfg , & map - > std_cfg , \
sizeof ( struct tda18271_std_map_item ) ) ; \
} } while ( 0 )
# define tda18271_dump_std_item(std_cfg, name) do { \
2008-03-31 02:40:20 +04:00
tda_dbg ( " (%s) if_freq = %d, agc_mode = %d, std = %d, " \
" if_lvl = %d, rfagc_top = 0x%02x \n " , \
2008-04-22 21:46:06 +04:00
name , std - > std_cfg . if_freq , \
2008-03-31 02:40:20 +04:00
std - > std_cfg . agc_mode , std - > std_cfg . std , \
std - > std_cfg . if_lvl , std - > std_cfg . rfagc_top ) ; \
2008-01-02 09:01:54 +03:00
} while ( 0 )
static int tda18271_dump_std_map ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
struct tda18271_std_map * std = & priv - > std ;
tda_dbg ( " ========== STANDARD MAP SETTINGS ========== \n " ) ;
2008-03-31 02:40:20 +04:00
tda18271_dump_std_item ( fm_radio , " fm " ) ;
tda18271_dump_std_item ( atv_b , " atv b " ) ;
tda18271_dump_std_item ( atv_dk , " atv dk " ) ;
tda18271_dump_std_item ( atv_gh , " atv gh " ) ;
tda18271_dump_std_item ( atv_i , " atv i " ) ;
tda18271_dump_std_item ( atv_l , " atv l " ) ;
tda18271_dump_std_item ( atv_lc , " atv l' " ) ;
2008-01-02 09:01:54 +03:00
tda18271_dump_std_item ( atv_mn , " atv mn " ) ;
tda18271_dump_std_item ( atsc_6 , " atsc 6 " ) ;
tda18271_dump_std_item ( dvbt_6 , " dvbt 6 " ) ;
tda18271_dump_std_item ( dvbt_7 , " dvbt 7 " ) ;
tda18271_dump_std_item ( dvbt_8 , " dvbt 8 " ) ;
2008-03-31 02:40:20 +04:00
tda18271_dump_std_item ( qam_6 , " qam 6 " ) ;
2012-12-04 23:13:33 +04:00
tda18271_dump_std_item ( qam_7 , " qam 7 " ) ;
2008-03-31 02:40:20 +04:00
tda18271_dump_std_item ( qam_8 , " qam 8 " ) ;
2008-01-02 09:01:54 +03:00
return 0 ;
}
static int tda18271_update_std_map ( struct dvb_frontend * fe ,
struct tda18271_std_map * map )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
struct tda18271_std_map * std = & priv - > std ;
if ( ! map )
return - EINVAL ;
2008-01-08 16:38:10 +03:00
tda18271_update_std ( fm_radio , " fm " ) ;
2008-01-02 09:01:54 +03:00
tda18271_update_std ( atv_b , " atv b " ) ;
tda18271_update_std ( atv_dk , " atv dk " ) ;
tda18271_update_std ( atv_gh , " atv gh " ) ;
tda18271_update_std ( atv_i , " atv i " ) ;
tda18271_update_std ( atv_l , " atv l " ) ;
tda18271_update_std ( atv_lc , " atv l' " ) ;
tda18271_update_std ( atv_mn , " atv mn " ) ;
tda18271_update_std ( atsc_6 , " atsc 6 " ) ;
tda18271_update_std ( dvbt_6 , " dvbt 6 " ) ;
tda18271_update_std ( dvbt_7 , " dvbt 7 " ) ;
tda18271_update_std ( dvbt_8 , " dvbt 8 " ) ;
tda18271_update_std ( qam_6 , " qam 6 " ) ;
2012-12-04 23:13:33 +04:00
tda18271_update_std ( qam_7 , " qam 7 " ) ;
2008-01-02 09:01:54 +03:00
tda18271_update_std ( qam_8 , " qam 8 " ) ;
return 0 ;
}
2007-12-24 10:15:20 +03:00
static int tda18271_get_id ( struct dvb_frontend * fe )
{
struct tda18271_priv * priv = fe - > tuner_priv ;
unsigned char * regs = priv - > tda18271_regs ;
char * name ;
2012-10-02 18:04:36 +04:00
int ret ;
2007-12-24 10:15:20 +03:00
2008-01-06 21:31:35 +03:00
mutex_lock ( & priv - > lock ) ;
2012-10-02 18:04:36 +04:00
ret = tda18271_read_regs ( fe ) ;
2008-01-06 21:31:35 +03:00
mutex_unlock ( & priv - > lock ) ;
2007-12-24 10:15:20 +03:00
2012-10-02 18:04:36 +04:00
if ( ret ) {
tda_info ( " Error reading device ID @ %d-%04x, bailing out. \n " ,
i2c_adapter_id ( priv - > i2c_props . adap ) ,
priv - > i2c_props . addr ) ;
return - EIO ;
}
2007-12-24 10:15:20 +03:00
switch ( regs [ R_ID ] & 0x7f ) {
case 3 :
name = " TDA18271HD/C1 " ;
2008-01-02 04:52:09 +03:00
priv - > id = TDA18271HDC1 ;
2007-12-24 10:15:20 +03:00
break ;
case 4 :
name = " TDA18271HD/C2 " ;
2008-01-02 04:52:09 +03:00
priv - > id = TDA18271HDC2 ;
2007-12-24 10:15:20 +03:00
break ;
default :
2010-09-26 07:39:26 +04:00
tda_info ( " Unknown device (%i) detected @ %d-%04x, device not supported. \n " ,
regs [ R_ID ] , i2c_adapter_id ( priv - > i2c_props . adap ) ,
priv - > i2c_props . addr ) ;
return - EINVAL ;
2007-12-24 10:15:20 +03:00
}
2010-09-26 07:39:26 +04:00
tda_info ( " %s detected @ %d-%04x \n " , name ,
i2c_adapter_id ( priv - > i2c_props . adap ) , priv - > i2c_props . addr ) ;
2007-12-24 10:15:20 +03:00
2010-09-26 07:39:26 +04:00
return 0 ;
2007-12-24 10:15:20 +03:00
}
2009-10-25 00:47:49 +04:00
static int tda18271_setup_configuration ( struct dvb_frontend * fe ,
struct tda18271_config * cfg )
2009-10-23 10:20:45 +04:00
{
struct tda18271_priv * priv = fe - > tuner_priv ;
priv - > gate = ( cfg ) ? cfg - > gate : TDA18271_GATE_AUTO ;
priv - > role = ( cfg ) ? cfg - > role : TDA18271_MASTER ;
priv - > config = ( cfg ) ? cfg - > config : 0 ;
priv - > small_i2c = ( cfg ) ?
cfg - > small_i2c : TDA18271_39_BYTE_CHUNK_INIT ;
priv - > output_opt = ( cfg ) ?
cfg - > output_opt : TDA18271_OUTPUT_LT_XT_ON ;
return 0 ;
}
2009-10-25 01:37:22 +04:00
static inline int tda18271_need_cal_on_startup ( struct tda18271_config * cfg )
{
/* tda18271_cal_on_startup == -1 when cal module option is unset */
return ( ( tda18271_cal_on_startup = = - 1 ) ?
/* honor configuration setting */
( ( cfg ) & & ( cfg - > rf_cal_on_startup ) ) :
/* module option overrides configuration setting */
( tda18271_cal_on_startup ) ) ? 1 : 0 ;
}
2009-10-25 00:47:49 +04:00
static int tda18271_set_config ( struct dvb_frontend * fe , void * priv_cfg )
{
struct tda18271_config * cfg = ( struct tda18271_config * ) priv_cfg ;
tda18271_setup_configuration ( fe , cfg ) ;
2009-10-25 01:37:22 +04:00
if ( tda18271_need_cal_on_startup ( cfg ) )
2009-10-25 00:47:49 +04:00
tda18271_init ( fe ) ;
2009-11-01 08:52:01 +03:00
/* override default std map with values in config struct */
if ( ( cfg ) & & ( cfg - > std_map ) )
tda18271_update_std_map ( fe , cfg - > std_map ) ;
2009-10-25 00:47:49 +04:00
return 0 ;
}
2011-08-20 23:01:26 +04:00
static const struct dvb_tuner_ops tda18271_tuner_ops = {
2007-10-22 16:56:38 +04:00
. info = {
. name = " NXP TDA18271HD " ,
. frequency_min = 45000000 ,
. frequency_max = 864000000 ,
. frequency_step = 62500
} ,
2007-12-01 23:40:16 +03:00
. init = tda18271_init ,
2008-01-13 23:01:01 +03:00
. sleep = tda18271_sleep ,
2007-10-22 16:56:38 +04:00
. set_params = tda18271_set_params ,
. set_analog_params = tda18271_set_analog_params ,
. release = tda18271_release ,
2009-10-23 10:20:45 +04:00
. set_config = tda18271_set_config ,
2007-10-22 16:56:38 +04:00
. get_frequency = tda18271_get_frequency ,
. get_bandwidth = tda18271_get_bandwidth ,
2011-11-03 16:59:42 +04:00
. get_if_frequency = tda18271_get_if_frequency ,
2007-10-22 16:56:38 +04:00
} ;
struct dvb_frontend * tda18271_attach ( struct dvb_frontend * fe , u8 addr ,
2007-12-10 04:23:30 +03:00
struct i2c_adapter * i2c ,
2008-01-02 09:01:54 +03:00
struct tda18271_config * cfg )
2007-10-22 16:56:38 +04:00
{
struct tda18271_priv * priv = NULL ;
2010-05-03 09:10:15 +04:00
int instance , ret ;
2008-01-06 21:52:56 +03:00
mutex_lock ( & tda18271_list_mutex ) ;
2008-04-22 21:41:54 +04:00
instance = hybrid_tuner_request_state ( struct tda18271_priv , priv ,
hybrid_tuner_instance_list ,
i2c , addr , " tda18271 " ) ;
switch ( instance ) {
case 0 :
goto fail ;
case 1 :
/* new tuner instance */
2009-10-23 10:20:45 +04:00
fe - > tuner_priv = priv ;
2009-10-25 00:47:49 +04:00
tda18271_setup_configuration ( fe , cfg ) ;
2009-08-27 23:58:06 +04:00
2008-01-06 21:52:56 +03:00
priv - > cal_initialized = false ;
mutex_init ( & priv - > lock ) ;
2007-10-22 16:56:38 +04:00
2010-05-03 09:10:15 +04:00
ret = tda18271_get_id ( fe ) ;
if ( tda_fail ( ret ) )
2008-01-06 21:52:56 +03:00
goto fail ;
2007-12-24 10:15:20 +03:00
2010-05-03 09:10:15 +04:00
ret = tda18271_assign_map_layout ( fe ) ;
if ( tda_fail ( ret ) )
2008-01-06 21:52:56 +03:00
goto fail ;
2008-01-02 04:52:09 +03:00
2012-10-02 06:50:37 +04:00
/* if delay_cal is set, delay IR & RF calibration until init()
* module option ' cal ' overrides this delay */
if ( ( cfg - > delay_cal ) & & ( ! tda18271_need_cal_on_startup ( cfg ) ) )
break ;
2008-01-06 21:52:56 +03:00
mutex_lock ( & priv - > lock ) ;
tda18271_init_regs ( fe ) ;
2008-01-14 04:01:07 +03:00
2009-10-25 01:37:22 +04:00
if ( ( tda18271_need_cal_on_startup ( cfg ) ) & &
( priv - > id = = TDA18271HDC2 ) )
2008-04-22 21:42:07 +04:00
tda18271c2_rf_cal_init ( fe ) ;
2008-01-14 04:01:07 +03:00
2012-09-29 23:06:23 +04:00
/* enter standby mode, with required output features enabled */
ret = tda18271_toggle_output ( fe , 1 ) ;
tda_fail ( ret ) ;
2008-01-06 21:52:56 +03:00
mutex_unlock ( & priv - > lock ) ;
2008-04-22 21:41:54 +04:00
break ;
default :
/* existing tuner instance */
fe - > tuner_priv = priv ;
2009-08-30 10:07:10 +04:00
/* allow dvb driver to override configuration settings */
if ( cfg ) {
if ( cfg - > gate ! = TDA18271_GATE_ANALOG )
priv - > gate = cfg - > gate ;
if ( cfg - > role )
priv - > role = cfg - > role ;
if ( cfg - > config )
priv - > config = cfg - > config ;
if ( cfg - > small_i2c )
priv - > small_i2c = cfg - > small_i2c ;
if ( cfg - > output_opt )
priv - > output_opt = cfg - > output_opt ;
2009-10-23 10:20:45 +04:00
if ( cfg - > std_map )
tda18271_update_std_map ( fe , cfg - > std_map ) ;
2009-08-30 10:07:10 +04:00
}
2009-10-25 01:37:22 +04:00
if ( tda18271_need_cal_on_startup ( cfg ) )
2009-10-25 01:18:03 +04:00
tda18271_init ( fe ) ;
2008-04-22 21:41:54 +04:00
break ;
2008-01-06 21:52:56 +03:00
}
2007-10-22 16:56:38 +04:00
2009-11-01 08:52:01 +03:00
/* override default std map with values in config struct */
if ( ( cfg ) & & ( cfg - > std_map ) )
tda18271_update_std_map ( fe , cfg - > std_map ) ;
2008-01-06 21:52:56 +03:00
mutex_unlock ( & tda18271_list_mutex ) ;
2008-01-06 21:31:35 +03:00
2008-01-06 21:52:56 +03:00
memcpy ( & fe - > ops . tuner_ops , & tda18271_tuner_ops ,
sizeof ( struct dvb_tuner_ops ) ) ;
2007-12-01 23:40:16 +03:00
2008-03-31 02:40:20 +04:00
if ( tda18271_debug & ( DBG_MAP | DBG_ADV ) )
2008-01-06 21:52:56 +03:00
tda18271_dump_std_map ( fe ) ;
2008-01-06 21:31:35 +03:00
2007-10-22 16:56:38 +04:00
return fe ;
2007-12-24 10:15:20 +03:00
fail :
2008-01-06 21:52:56 +03:00
mutex_unlock ( & tda18271_list_mutex ) ;
2007-12-24 10:15:20 +03:00
tda18271_release ( fe ) ;
return NULL ;
2007-10-22 16:56:38 +04:00
}
EXPORT_SYMBOL_GPL ( tda18271_attach ) ;
MODULE_DESCRIPTION ( " NXP TDA18271HD analog / digital tuner driver " ) ;
MODULE_AUTHOR ( " Michael Krufky <mkrufky@linuxtv.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-10-25 16:43:30 +03:00
MODULE_VERSION ( " 0.4 " ) ;
2007-10-22 16:56:38 +04:00
/*
* Overrides for Emacs so that we follow Linus ' s tabbing style .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Local variables :
* c - basic - offset : 8
* End :
*/