2005-04-16 15:20:36 -07:00
/*
2005-11-08 21:37:48 -08:00
i2c tv tuner chip device driver
controls the philips tda8290 + 75 tuner chip combo .
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 .
*/
2005-04-16 15:20:36 -07:00
# include <linux/i2c.h>
# include <linux/videodev.h>
# include <linux/delay.h>
# include <media/tuner.h>
/* ---------------------------------------------------------------------- */
2005-11-08 21:37:48 -08:00
struct tda827x_data {
u32 lomax ;
u8 spd ;
u8 bs ;
u8 bp ;
u8 cp ;
u8 gc3 ;
u8 div1p5 ;
2005-04-16 15:20:36 -07:00
} ;
2005-11-08 21:37:48 -08:00
/* Note lomax entry is lo / 62500 */
static struct tda827x_data tda827x_analog [ ] = {
{ . lomax = 992 , . spd = 3 , . bs = 2 , . bp = 0 , . cp = 0 , . gc3 = 3 , . div1p5 = 1 } , /* 62 MHz */
{ . lomax = 1056 , . spd = 3 , . bs = 3 , . bp = 0 , . cp = 0 , . gc3 = 3 , . div1p5 = 1 } , /* 66 MHz */
{ . lomax = 1216 , . spd = 3 , . bs = 1 , . bp = 0 , . cp = 0 , . gc3 = 3 , . div1p5 = 0 } , /* 76 MHz */
{ . lomax = 1344 , . spd = 3 , . bs = 2 , . bp = 0 , . cp = 0 , . gc3 = 3 , . div1p5 = 0 } , /* 84 MHz */
{ . lomax = 1488 , . spd = 3 , . bs = 2 , . bp = 0 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 93 MHz */
{ . lomax = 1568 , . spd = 3 , . bs = 3 , . bp = 0 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 98 MHz */
{ . lomax = 1744 , . spd = 3 , . bs = 3 , . bp = 1 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 109 MHz */
{ . lomax = 1968 , . spd = 2 , . bs = 2 , . bp = 1 , . cp = 0 , . gc3 = 1 , . div1p5 = 1 } , /* 123 MHz */
{ . lomax = 2128 , . spd = 2 , . bs = 3 , . bp = 1 , . cp = 0 , . gc3 = 1 , . div1p5 = 1 } , /* 133 MHz */
{ . lomax = 2416 , . spd = 2 , . bs = 1 , . bp = 1 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 151 MHz */
{ . lomax = 2464 , . spd = 2 , . bs = 2 , . bp = 1 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 154 MHz */
{ . lomax = 2896 , . spd = 2 , . bs = 2 , . bp = 1 , . cp = 0 , . gc3 = 0 , . div1p5 = 0 } , /* 181 MHz */
{ . lomax = 2960 , . spd = 2 , . bs = 2 , . bp = 2 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 185 MHz */
{ . lomax = 3472 , . spd = 2 , . bs = 3 , . bp = 2 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 217 MHz */
{ . lomax = 3904 , . spd = 1 , . bs = 2 , . bp = 2 , . cp = 0 , . gc3 = 1 , . div1p5 = 1 } , /* 244 MHz */
{ . lomax = 4240 , . spd = 1 , . bs = 3 , . bp = 2 , . cp = 0 , . gc3 = 1 , . div1p5 = 1 } , /* 265 MHz */
{ . lomax = 4832 , . spd = 1 , . bs = 1 , . bp = 2 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 302 MHz */
{ . lomax = 5184 , . spd = 1 , . bs = 2 , . bp = 2 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 324 MHz */
{ . lomax = 5920 , . spd = 1 , . bs = 2 , . bp = 3 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 370 MHz */
{ . lomax = 7264 , . spd = 1 , . bs = 3 , . bp = 3 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 454 MHz */
{ . lomax = 7888 , . spd = 0 , . bs = 2 , . bp = 3 , . cp = 0 , . gc3 = 1 , . div1p5 = 1 } , /* 493 MHz */
{ . lomax = 8480 , . spd = 0 , . bs = 3 , . bp = 3 , . cp = 0 , . gc3 = 1 , . div1p5 = 1 } , /* 530 MHz */
{ . lomax = 8864 , . spd = 0 , . bs = 1 , . bp = 3 , . cp = 0 , . gc3 = 1 , . div1p5 = 0 } , /* 554 MHz */
{ . lomax = 9664 , . spd = 0 , . bs = 1 , . bp = 4 , . cp = 0 , . gc3 = 0 , . div1p5 = 0 } , /* 604 MHz */
{ . lomax = 11088 , . spd = 0 , . bs = 2 , . bp = 4 , . cp = 0 , . gc3 = 0 , . div1p5 = 0 } , /* 696 MHz */
{ . lomax = 11840 , . spd = 0 , . bs = 2 , . bp = 4 , . cp = 1 , . gc3 = 0 , . div1p5 = 0 } , /* 740 MHz */
{ . lomax = 13120 , . spd = 0 , . bs = 3 , . bp = 4 , . cp = 0 , . gc3 = 0 , . div1p5 = 0 } , /* 820 MHz */
{ . lomax = 13840 , . spd = 0 , . bs = 3 , . bp = 4 , . cp = 1 , . gc3 = 0 , . div1p5 = 0 } , /* 865 MHz */
{ . lomax = 0 , . spd = 0 , . bs = 0 , . bp = 0 , . cp = 0 , . gc3 = 0 , . div1p5 = 0 } /* End */
2005-04-16 15:20:36 -07:00
} ;
2005-11-08 21:37:48 -08:00
static void tda827x_tune ( struct i2c_client * c , u16 ifc , unsigned int freq )
{
unsigned char tuner_reg [ 8 ] ;
unsigned char reg2 [ 2 ] ;
u32 N ;
int i ;
struct tuner * t = i2c_get_clientdata ( c ) ;
struct i2c_msg msg = { . addr = t - > tda827x_addr , . flags = 0 } ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
if ( t - > mode = = V4L2_TUNER_RADIO )
freq = freq / 1000 ;
N = freq + ifc ;
i = 0 ;
while ( tda827x_analog [ i ] . lomax < N ) {
if ( tda827x_analog [ i + 1 ] . lomax = = 0 )
break ;
i + + ;
}
N = N < < tda827x_analog [ i ] . spd ;
tuner_reg [ 0 ] = 0 ;
tuner_reg [ 1 ] = ( unsigned char ) ( N > > 8 ) ;
tuner_reg [ 2 ] = ( unsigned char ) N ;
tuner_reg [ 3 ] = 0x40 ;
tuner_reg [ 4 ] = 0x52 + ( t - > tda827x_lpsel < < 5 ) ;
tuner_reg [ 5 ] = ( tda827x_analog [ i ] . spd < < 6 ) + ( tda827x_analog [ i ] . div1p5 < < 5 ) +
2005-11-08 21:37:50 -08:00
( tda827x_analog [ i ] . bs < < 3 ) + tda827x_analog [ i ] . bp ;
2005-11-08 21:37:48 -08:00
tuner_reg [ 6 ] = 0x8f + ( tda827x_analog [ i ] . gc3 < < 4 ) ;
tuner_reg [ 7 ] = 0x8f ;
msg . buf = tuner_reg ;
msg . len = 8 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
msg . buf = reg2 ;
msg . len = 2 ;
reg2 [ 0 ] = 0x80 ;
reg2 [ 1 ] = 0 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
reg2 [ 0 ] = 0x60 ;
reg2 [ 1 ] = 0xbf ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
reg2 [ 0 ] = 0x30 ;
reg2 [ 1 ] = tuner_reg [ 4 ] + 0x80 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
msleep ( 1 ) ;
reg2 [ 0 ] = 0x30 ;
reg2 [ 1 ] = tuner_reg [ 4 ] + 4 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
msleep ( 1 ) ;
reg2 [ 0 ] = 0x30 ;
reg2 [ 1 ] = tuner_reg [ 4 ] ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
msleep ( 550 ) ;
reg2 [ 0 ] = 0x30 ;
reg2 [ 1 ] = ( tuner_reg [ 4 ] & 0xfc ) + tda827x_analog [ i ] . cp ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
reg2 [ 0 ] = 0x60 ;
2005-11-08 21:38:00 -08:00
reg2 [ 1 ] = 0x3f ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
reg2 [ 0 ] = 0x80 ;
reg2 [ 1 ] = 0x08 ; // Vsync en
i2c_transfer ( c - > adapter , & msg , 1 ) ;
}
static void tda827x_agcf ( struct i2c_client * c )
2005-04-16 15:20:36 -07:00
{
2005-11-08 21:37:48 -08:00
struct tuner * t = i2c_get_clientdata ( c ) ;
unsigned char data [ ] = { 0x80 , 0x0c } ;
struct i2c_msg msg = { . addr = t - > tda827x_addr , . buf = data ,
. flags = 0 , . len = 2 } ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2005-04-16 15:20:36 -07:00
}
/* ---------------------------------------------------------------------- */
2005-11-08 21:37:48 -08:00
struct tda827xa_data {
u32 lomax ;
u8 svco ;
u8 spd ;
u8 scr ;
u8 sbs ;
u8 gc3 ;
2005-04-16 15:20:36 -07:00
} ;
2005-11-08 21:37:48 -08:00
static struct tda827xa_data tda827xa_analog [ ] = {
{ . lomax = 910 , . svco = 3 , . spd = 4 , . scr = 0 , . sbs = 0 , . gc3 = 3 } , /* 56.875 MHz */
{ . lomax = 1076 , . svco = 0 , . spd = 3 , . scr = 0 , . sbs = 0 , . gc3 = 3 } , /* 67.25 MHz */
{ . lomax = 1300 , . svco = 1 , . spd = 3 , . scr = 0 , . sbs = 0 , . gc3 = 3 } , /* 81.25 MHz */
{ . lomax = 1560 , . svco = 2 , . spd = 3 , . scr = 0 , . sbs = 0 , . gc3 = 3 } , /* 97.5 MHz */
{ . lomax = 1820 , . svco = 3 , . spd = 3 , . scr = 0 , . sbs = 1 , . gc3 = 1 } , /* 113.75 MHz */
{ . lomax = 2152 , . svco = 0 , . spd = 2 , . scr = 0 , . sbs = 1 , . gc3 = 1 } , /* 134.5 MHz */
{ . lomax = 2464 , . svco = 1 , . spd = 2 , . scr = 0 , . sbs = 1 , . gc3 = 1 } , /* 154 MHz */
{ . lomax = 2600 , . svco = 1 , . spd = 2 , . scr = 0 , . sbs = 1 , . gc3 = 1 } , /* 162.5 MHz */
{ . lomax = 2928 , . svco = 2 , . spd = 2 , . scr = 0 , . sbs = 1 , . gc3 = 1 } , /* 183 MHz */
{ . lomax = 3120 , . svco = 2 , . spd = 2 , . scr = 0 , . sbs = 2 , . gc3 = 1 } , /* 195 MHz */
{ . lomax = 3640 , . svco = 3 , . spd = 2 , . scr = 0 , . sbs = 2 , . gc3 = 3 } , /* 227.5 MHz */
{ . lomax = 4304 , . svco = 0 , . spd = 1 , . scr = 0 , . sbs = 2 , . gc3 = 3 } , /* 269 MHz */
{ . lomax = 5200 , . svco = 1 , . spd = 1 , . scr = 0 , . sbs = 2 , . gc3 = 1 } , /* 325 MHz */
{ . lomax = 6240 , . svco = 2 , . spd = 1 , . scr = 0 , . sbs = 3 , . gc3 = 3 } , /* 390 MHz */
{ . lomax = 7280 , . svco = 3 , . spd = 1 , . scr = 0 , . sbs = 3 , . gc3 = 3 } , /* 455 MHz */
{ . lomax = 8320 , . svco = 0 , . spd = 0 , . scr = 0 , . sbs = 3 , . gc3 = 1 } , /* 520 MHz */
{ . lomax = 8608 , . svco = 0 , . spd = 0 , . scr = 1 , . sbs = 3 , . gc3 = 1 } , /* 538 MHz */
{ . lomax = 8864 , . svco = 1 , . spd = 0 , . scr = 0 , . sbs = 3 , . gc3 = 1 } , /* 554 MHz */
{ . lomax = 9920 , . svco = 1 , . spd = 0 , . scr = 0 , . sbs = 4 , . gc3 = 0 } , /* 620 MHz */
{ . lomax = 10400 , . svco = 1 , . spd = 0 , . scr = 1 , . sbs = 4 , . gc3 = 0 } , /* 650 MHz */
{ . lomax = 11200 , . svco = 2 , . spd = 0 , . scr = 0 , . sbs = 4 , . gc3 = 0 } , /* 700 MHz */
{ . lomax = 12480 , . svco = 2 , . spd = 0 , . scr = 1 , . sbs = 4 , . gc3 = 0 } , /* 780 MHz */
{ . lomax = 13120 , . svco = 3 , . spd = 0 , . scr = 0 , . sbs = 4 , . gc3 = 0 } , /* 820 MHz */
{ . lomax = 13920 , . svco = 3 , . spd = 0 , . scr = 1 , . sbs = 4 , . gc3 = 0 } , /* 870 MHz */
{ . lomax = 14576 , . svco = 3 , . spd = 0 , . scr = 2 , . sbs = 4 , . gc3 = 0 } , /* 911 MHz */
{ . lomax = 0 , . svco = 0 , . spd = 0 , . scr = 0 , . sbs = 0 , . gc3 = 0 } /* End */
2005-04-16 15:20:36 -07:00
} ;
2007-04-27 12:31:12 -03:00
static void tda827xa_lna_gain ( struct i2c_client * c , int high )
{
struct tuner * t = i2c_get_clientdata ( c ) ;
unsigned char buf [ ] = { 0x22 , 0x01 } ;
int arg ;
struct i2c_msg msg = { . addr = c - > addr , . flags = 0 , . buf = buf , . len = sizeof ( buf ) } ;
if ( t - > config ) {
if ( high )
tuner_dbg ( " setting LNA to high gain \n " ) ;
else
tuner_dbg ( " setting LNA to low gain \n " ) ;
}
switch ( t - > config ) {
case 0 : /* no LNA */
break ;
case 1 : /* switch is GPIO 0 of tda8290 */
case 2 :
/* turn Vsync on */
if ( t - > std & V4L2_STD_MN )
2007-04-27 12:31:17 -03:00
arg = 1 ;
2007-04-27 12:31:12 -03:00
else
2007-04-27 12:31:17 -03:00
arg = 0 ;
if ( t - > tuner_callback )
t - > tuner_callback ( c - > adapter - > algo_data , 1 , arg ) ;
2007-04-27 12:31:12 -03:00
buf [ 1 ] = high ? 0 : 1 ;
if ( t - > config = = 2 )
buf [ 1 ] = high ? 1 : 0 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
break ;
case 3 : /* switch with GPIO of saa713x */
2007-04-27 12:31:17 -03:00
if ( t - > tuner_callback )
t - > tuner_callback ( c - > adapter - > algo_data , 0 , high ) ;
2007-04-27 12:31:12 -03:00
break ;
}
}
2005-11-08 21:37:48 -08:00
static void tda827xa_tune ( struct i2c_client * c , u16 ifc , unsigned int freq )
{
2007-04-27 12:31:12 -03:00
unsigned char tuner_reg [ 11 ] ;
2005-11-08 21:37:48 -08:00
u32 N ;
int i ;
struct tuner * t = i2c_get_clientdata ( c ) ;
2007-04-27 12:31:12 -03:00
struct i2c_msg msg = { . addr = t - > tda827x_addr , . flags = 0 , . buf = tuner_reg } ;
tda827xa_lna_gain ( c , 1 ) ;
msleep ( 10 ) ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
if ( t - > mode = = V4L2_TUNER_RADIO )
freq = freq / 1000 ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
N = freq + ifc ;
i = 0 ;
while ( tda827xa_analog [ i ] . lomax < N ) {
if ( tda827xa_analog [ i + 1 ] . lomax = = 0 )
break ;
i + + ;
}
N = N < < tda827xa_analog [ i ] . spd ;
tuner_reg [ 0 ] = 0 ;
tuner_reg [ 1 ] = ( unsigned char ) ( N > > 8 ) ;
tuner_reg [ 2 ] = ( unsigned char ) N ;
tuner_reg [ 3 ] = 0 ;
tuner_reg [ 4 ] = 0x16 ;
tuner_reg [ 5 ] = ( tda827xa_analog [ i ] . spd < < 5 ) + ( tda827xa_analog [ i ] . svco < < 3 ) +
2005-11-08 21:37:50 -08:00
tda827xa_analog [ i ] . sbs ;
2005-11-08 21:37:48 -08:00
tuner_reg [ 6 ] = 0x8b + ( tda827xa_analog [ i ] . gc3 < < 4 ) ;
2007-04-27 12:31:12 -03:00
tuner_reg [ 7 ] = 0x1c ;
2005-11-08 21:37:48 -08:00
tuner_reg [ 8 ] = 4 ;
tuner_reg [ 9 ] = 0x20 ;
2007-04-27 12:31:12 -03:00
tuner_reg [ 10 ] = 0x00 ;
msg . len = 11 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2005-11-08 21:37:48 -08:00
2007-04-27 12:31:12 -03:00
tuner_reg [ 0 ] = 0x90 ;
tuner_reg [ 1 ] = 0xff ;
tuner_reg [ 2 ] = 0xe0 ;
tuner_reg [ 3 ] = 0 ;
tuner_reg [ 4 ] = 0x99 + ( t - > tda827x_lpsel < < 1 ) ;
msg . len = 5 ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2007-04-27 12:31:12 -03:00
tuner_reg [ 0 ] = 0xa0 ;
tuner_reg [ 1 ] = 0xc0 ;
2005-11-08 21:37:48 -08:00
msg . len = 2 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2007-04-27 12:31:12 -03:00
tuner_reg [ 0 ] = 0x30 ;
tuner_reg [ 1 ] = 0x10 + tda827xa_analog [ i ] . scr ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2007-04-27 12:31:12 -03:00
msg . flags = I2C_M_RD ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
msg . flags = 0 ;
tuner_reg [ 1 ] > > = 4 ;
tuner_dbg ( " AGC2 gain is: %d \n " , tuner_reg [ 1 ] ) ;
if ( tuner_reg [ 1 ] < 1 )
tda827xa_lna_gain ( c , 0 ) ;
msleep ( 100 ) ;
tuner_reg [ 0 ] = 0x60 ;
tuner_reg [ 1 ] = 0x3c ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2007-04-27 12:31:12 -03:00
msleep ( 163 ) ;
tuner_reg [ 0 ] = 0x50 ;
tuner_reg [ 1 ] = 0x8f + ( tda827xa_analog [ i ] . gc3 < < 4 ) ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2007-04-27 12:31:12 -03:00
tuner_reg [ 0 ] = 0x80 ;
tuner_reg [ 1 ] = 0x28 ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2007-04-27 12:31:12 -03:00
tuner_reg [ 0 ] = 0xb0 ;
tuner_reg [ 1 ] = 0x01 ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
2005-09-09 13:03:37 -07:00
2007-04-27 12:31:12 -03:00
tuner_reg [ 0 ] = 0xc0 ;
tuner_reg [ 1 ] = 0x19 + ( t - > tda827x_lpsel < < 1 ) ;
2005-11-08 21:37:48 -08:00
i2c_transfer ( c - > adapter , & msg , 1 ) ;
}
static void tda827xa_agcf ( struct i2c_client * c )
2005-04-16 15:20:36 -07:00
{
struct tuner * t = i2c_get_clientdata ( c ) ;
2005-11-08 21:37:48 -08:00
unsigned char data [ ] = { 0x80 , 0x2c } ;
struct i2c_msg msg = { . addr = t - > tda827x_addr , . buf = data ,
. flags = 0 , . len = 2 } ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
}
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
/*---------------------------------------------------------------------*/
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
static void tda8290_i2c_bridge ( struct i2c_client * c , int close )
{
unsigned char enable [ 2 ] = { 0x21 , 0xC0 } ;
2006-02-07 06:49:09 -02:00
unsigned char disable [ 2 ] = { 0x21 , 0x00 } ;
2005-11-08 21:37:48 -08:00
unsigned char * msg ;
if ( close ) {
msg = enable ;
i2c_master_send ( c , msg , 2 ) ;
/* let the bridge stabilize */
msleep ( 20 ) ;
} else {
msg = disable ;
i2c_master_send ( c , msg , 2 ) ;
}
2005-04-16 15:20:36 -07:00
}
2005-11-08 21:37:48 -08:00
/*---------------------------------------------------------------------*/
static int tda8290_tune ( struct i2c_client * c , u16 ifc , unsigned int freq )
2005-04-16 15:20:36 -07:00
{
2005-11-08 21:37:48 -08:00
struct tuner * t = i2c_get_clientdata ( c ) ;
unsigned char soft_reset [ ] = { 0x00 , 0x00 } ;
unsigned char easy_mode [ ] = { 0x01 , t - > tda8290_easy_mode } ;
unsigned char expert_mode [ ] = { 0x01 , 0x80 } ;
2006-02-07 06:49:09 -02:00
unsigned char agc_out_on [ ] = { 0x02 , 0x00 } ;
2005-11-08 21:37:48 -08:00
unsigned char gainset_off [ ] = { 0x28 , 0x14 } ;
unsigned char if_agc_spd [ ] = { 0x0f , 0x88 } ;
unsigned char adc_head_6 [ ] = { 0x05 , 0x04 } ;
unsigned char adc_head_9 [ ] = { 0x05 , 0x02 } ;
unsigned char adc_head_12 [ ] = { 0x05 , 0x01 } ;
unsigned char pll_bw_nom [ ] = { 0x0d , 0x47 } ;
unsigned char pll_bw_low [ ] = { 0x0d , 0x27 } ;
unsigned char gainset_2 [ ] = { 0x28 , 0x64 } ;
unsigned char agc_rst_on [ ] = { 0x0e , 0x0b } ;
unsigned char agc_rst_off [ ] = { 0x0e , 0x09 } ;
unsigned char if_agc_set [ ] = { 0x0f , 0x81 } ;
unsigned char addr_adc_sat = 0x1a ;
unsigned char addr_agc_stat = 0x1d ;
unsigned char addr_pll_stat = 0x1b ;
unsigned char adc_sat , agc_stat ,
2005-11-08 21:37:50 -08:00
pll_stat ;
2007-04-27 12:31:12 -03:00
int i ;
2005-11-08 21:37:48 -08:00
2007-04-27 12:31:12 -03:00
tuner_dbg ( " tda827xa config is 0x%02x \n " , t - > config ) ;
2005-11-08 21:37:48 -08:00
i2c_master_send ( c , easy_mode , 2 ) ;
2006-02-07 06:49:09 -02:00
i2c_master_send ( c , agc_out_on , 2 ) ;
2005-11-08 21:37:48 -08:00
i2c_master_send ( c , soft_reset , 2 ) ;
msleep ( 1 ) ;
2005-11-08 21:38:38 -08:00
expert_mode [ 1 ] = t - > tda8290_easy_mode + 0x80 ;
2005-11-08 21:37:48 -08:00
i2c_master_send ( c , expert_mode , 2 ) ;
i2c_master_send ( c , gainset_off , 2 ) ;
i2c_master_send ( c , if_agc_spd , 2 ) ;
if ( t - > tda8290_easy_mode & 0x60 )
i2c_master_send ( c , adc_head_9 , 2 ) ;
else
i2c_master_send ( c , adc_head_6 , 2 ) ;
i2c_master_send ( c , pll_bw_nom , 2 ) ;
tda8290_i2c_bridge ( c , 1 ) ;
if ( t - > tda827x_ver ! = 0 )
tda827xa_tune ( c , ifc , freq ) ;
else
tda827x_tune ( c , ifc , freq ) ;
2007-04-27 12:31:12 -03:00
for ( i = 0 ; i < 3 ; i + + ) {
i2c_master_send ( c , & addr_pll_stat , 1 ) ;
i2c_master_recv ( c , & pll_stat , 1 ) ;
if ( pll_stat & 0x80 ) {
i2c_master_send ( c , & addr_adc_sat , 1 ) ;
i2c_master_recv ( c , & adc_sat , 1 ) ;
i2c_master_send ( c , & addr_agc_stat , 1 ) ;
i2c_master_recv ( c , & agc_stat , 1 ) ;
tuner_dbg ( " tda8290 is locked, AGC: %d \n " , agc_stat ) ;
break ;
} else {
tuner_dbg ( " tda8290 not locked, no signal? \n " ) ;
msleep ( 100 ) ;
}
}
2005-11-08 21:37:48 -08:00
/* adjust headroom resp. gain */
2005-11-08 21:38:38 -08:00
if ( ( agc_stat > 115 ) | | ( ! ( pll_stat & 0x80 ) & & ( adc_sat < 20 ) ) ) {
tuner_dbg ( " adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d \n " ,
agc_stat , adc_sat , pll_stat & 0x80 ) ;
2005-11-08 21:37:48 -08:00
i2c_master_send ( c , gainset_2 , 2 ) ;
msleep ( 100 ) ;
i2c_master_send ( c , & addr_agc_stat , 1 ) ;
i2c_master_recv ( c , & agc_stat , 1 ) ;
i2c_master_send ( c , & addr_pll_stat , 1 ) ;
i2c_master_recv ( c , & pll_stat , 1 ) ;
if ( ( agc_stat > 115 ) | | ! ( pll_stat & 0x80 ) ) {
2005-11-08 21:38:38 -08:00
tuner_dbg ( " adjust gain, step 2. Agc: %d, lock: %d \n " ,
agc_stat , pll_stat & 0x80 ) ;
2005-11-08 21:37:48 -08:00
if ( t - > tda827x_ver ! = 0 )
tda827xa_agcf ( c ) ;
else
tda827x_agcf ( c ) ;
msleep ( 100 ) ;
i2c_master_send ( c , & addr_agc_stat , 1 ) ;
i2c_master_recv ( c , & agc_stat , 1 ) ;
i2c_master_send ( c , & addr_pll_stat , 1 ) ;
i2c_master_recv ( c , & pll_stat , 1 ) ;
if ( ( agc_stat > 115 ) | | ! ( pll_stat & 0x80 ) ) {
tuner_dbg ( " adjust gain, step 3. Agc: %d \n " , agc_stat ) ;
i2c_master_send ( c , adc_head_12 , 2 ) ;
i2c_master_send ( c , pll_bw_low , 2 ) ;
msleep ( 100 ) ;
}
}
}
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
/* l/ l' deadlock? */
if ( t - > tda8290_easy_mode & 0x60 ) {
i2c_master_send ( c , & addr_adc_sat , 1 ) ;
i2c_master_recv ( c , & adc_sat , 1 ) ;
i2c_master_send ( c , & addr_pll_stat , 1 ) ;
i2c_master_recv ( c , & pll_stat , 1 ) ;
if ( ( adc_sat > 20 ) | | ! ( pll_stat & 0x80 ) ) {
2005-11-08 21:38:38 -08:00
tuner_dbg ( " trying to resolve SECAM L deadlock \n " ) ;
2005-11-08 21:37:48 -08:00
i2c_master_send ( c , agc_rst_on , 2 ) ;
msleep ( 40 ) ;
i2c_master_send ( c , agc_rst_off , 2 ) ;
}
}
2005-06-28 20:45:21 -07:00
2005-11-08 21:37:48 -08:00
tda8290_i2c_bridge ( c , 0 ) ;
i2c_master_send ( c , if_agc_set , 2 ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2005-11-08 21:37:48 -08:00
/*---------------------------------------------------------------------*/
2005-04-16 15:20:36 -07:00
static void set_audio ( struct tuner * t )
{
2005-11-08 21:38:38 -08:00
char * mode ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:38:38 -08:00
t - > tda827x_lpsel = 0 ;
2005-11-08 21:36:50 -08:00
if ( t - > std & V4L2_STD_MN ) {
2005-11-08 21:37:48 -08:00
t - > sgIF = 92 ;
t - > tda8290_easy_mode = 0x01 ;
t - > tda827x_lpsel = 1 ;
2005-11-08 21:38:38 -08:00
mode = " MN " ;
2005-11-08 21:36:50 -08:00
} else if ( t - > std & V4L2_STD_B ) {
2005-11-08 21:37:48 -08:00
t - > sgIF = 108 ;
t - > tda8290_easy_mode = 0x02 ;
2005-11-08 21:38:38 -08:00
mode = " B " ;
2005-11-08 21:36:50 -08:00
} else if ( t - > std & V4L2_STD_GH ) {
2005-11-08 21:37:48 -08:00
t - > sgIF = 124 ;
t - > tda8290_easy_mode = 0x04 ;
2005-11-08 21:38:38 -08:00
mode = " GH " ;
2005-11-08 21:36:50 -08:00
} else if ( t - > std & V4L2_STD_PAL_I ) {
2005-11-08 21:37:48 -08:00
t - > sgIF = 124 ;
t - > tda8290_easy_mode = 0x08 ;
2005-11-08 21:38:38 -08:00
mode = " I " ;
2005-11-08 21:36:50 -08:00
} else if ( t - > std & V4L2_STD_DK ) {
2005-11-08 21:37:48 -08:00
t - > sgIF = 124 ;
t - > tda8290_easy_mode = 0x10 ;
2005-11-08 21:38:38 -08:00
mode = " DK " ;
2005-11-08 21:36:50 -08:00
} else if ( t - > std & V4L2_STD_SECAM_L ) {
2005-11-08 21:37:48 -08:00
t - > sgIF = 124 ;
t - > tda8290_easy_mode = 0x20 ;
2005-11-08 21:38:38 -08:00
mode = " L " ;
2005-11-13 16:07:58 -08:00
} else if ( t - > std & V4L2_STD_SECAM_LC ) {
t - > sgIF = 20 ;
t - > tda8290_easy_mode = 0x40 ;
mode = " LC " ;
2007-03-22 20:58:43 -03:00
} else {
t - > sgIF = 124 ;
t - > tda8290_easy_mode = 0x10 ;
mode = " xx " ;
2005-11-08 21:36:50 -08:00
}
2007-03-22 20:58:43 -03:00
tuner_dbg ( " setting tda8290 to system %s \n " , mode ) ;
2005-04-16 15:20:36 -07:00
}
static void set_tv_freq ( struct i2c_client * c , unsigned int freq )
{
struct tuner * t = i2c_get_clientdata ( c ) ;
set_audio ( t ) ;
2005-11-08 21:37:48 -08:00
tda8290_tune ( c , t - > sgIF , freq ) ;
2005-04-16 15:20:36 -07:00
}
static void set_radio_freq ( struct i2c_client * c , unsigned int freq )
{
2005-11-08 21:37:48 -08:00
/* if frequency is 5.5 MHz */
tda8290_tune ( c , 88 , freq ) ;
2005-04-16 15:20:36 -07:00
}
static int has_signal ( struct i2c_client * c )
{
unsigned char i2c_get_afc [ 1 ] = { 0x1B } ;
unsigned char afc = 0 ;
i2c_master_send ( c , i2c_get_afc , ARRAY_SIZE ( i2c_get_afc ) ) ;
i2c_master_recv ( c , & afc , 1 ) ;
return ( afc & 0x80 ) ? 65535 : 0 ;
}
2005-11-08 21:37:48 -08:00
/*---------------------------------------------------------------------*/
2005-09-09 13:03:37 -07:00
static void standby ( struct i2c_client * c )
{
2005-11-08 21:37:48 -08:00
struct tuner * t = i2c_get_clientdata ( c ) ;
unsigned char cb1 [ ] = { 0x30 , 0xD0 } ;
unsigned char tda8290_standby [ ] = { 0x00 , 0x02 } ;
2006-02-07 06:49:09 -02:00
unsigned char tda8290_agc_tri [ ] = { 0x02 , 0x20 } ;
2005-11-08 21:37:48 -08:00
struct i2c_msg msg = { . addr = t - > tda827x_addr , . flags = 0 , . buf = cb1 , . len = 2 } ;
tda8290_i2c_bridge ( c , 1 ) ;
if ( t - > tda827x_ver ! = 0 )
cb1 [ 1 ] = 0x90 ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
tda8290_i2c_bridge ( c , 0 ) ;
2006-02-07 06:49:09 -02:00
i2c_master_send ( c , tda8290_agc_tri , 2 ) ;
2005-11-08 21:37:48 -08:00
i2c_master_send ( c , tda8290_standby , 2 ) ;
2005-09-09 13:03:37 -07:00
}
2005-11-08 21:37:48 -08:00
static void tda8290_init_if ( struct i2c_client * c )
{
2007-04-27 12:31:12 -03:00
struct tuner * t = i2c_get_clientdata ( c ) ;
2005-11-08 21:37:48 -08:00
unsigned char set_VS [ ] = { 0x30 , 0x6F } ;
2007-04-27 12:31:12 -03:00
unsigned char set_GP00_CF [ ] = { 0x20 , 0x01 } ;
2005-11-08 21:37:48 -08:00
unsigned char set_GP01_CF [ ] = { 0x20 , 0x0B } ;
2007-04-27 12:31:12 -03:00
if ( ( t - > config = = 1 ) | | ( t - > config = = 2 ) )
i2c_master_send ( c , set_GP00_CF , 2 ) ;
else
i2c_master_send ( c , set_GP01_CF , 2 ) ;
2005-11-08 21:37:48 -08:00
i2c_master_send ( c , set_VS , 2 ) ;
}
static void tda8290_init_tuner ( struct i2c_client * c )
2005-04-16 15:20:36 -07:00
{
struct tuner * t = i2c_get_clientdata ( c ) ;
2005-11-08 21:37:48 -08:00
unsigned char tda8275_init [ ] = { 0x00 , 0x00 , 0x00 , 0x40 , 0xdC , 0x04 , 0xAf ,
2005-11-08 21:37:50 -08:00
0x3F , 0x2A , 0x04 , 0xFF , 0x00 , 0x00 , 0x40 } ;
2005-11-08 21:37:48 -08:00
unsigned char tda8275a_init [ ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0xdC , 0x05 , 0x8b ,
2005-11-08 21:37:50 -08:00
0x0c , 0x04 , 0x20 , 0xFF , 0x00 , 0x00 , 0x4b } ;
2005-11-08 21:37:48 -08:00
struct i2c_msg msg = { . addr = t - > tda827x_addr , . flags = 0 ,
2005-11-08 21:37:51 -08:00
. buf = tda8275_init , . len = 14 } ;
2005-11-08 21:37:48 -08:00
if ( t - > tda827x_ver ! = 0 )
msg . buf = tda8275a_init ;
tda8290_i2c_bridge ( c , 1 ) ;
i2c_transfer ( c - > adapter , & msg , 1 ) ;
tda8290_i2c_bridge ( c , 0 ) ;
}
/*---------------------------------------------------------------------*/
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
int tda8290_init ( struct i2c_client * c )
{
struct tuner * t = i2c_get_clientdata ( c ) ;
u8 data ;
int i , ret , tuners_found ;
u32 tuner_addrs ;
struct i2c_msg msg = { . flags = I2C_M_RD , . buf = & data , . len = 1 } ;
tda8290_i2c_bridge ( c , 1 ) ;
/* probe for tuner chip */
tuners_found = 0 ;
tuner_addrs = 0 ;
for ( i = 0x60 ; i < = 0x63 ; i + + ) {
msg . addr = i ;
ret = i2c_transfer ( c - > adapter , & msg , 1 ) ;
if ( ret = = 1 ) {
tuners_found + + ;
tuner_addrs = ( tuner_addrs < < 8 ) + i ;
}
}
/* if there is more than one tuner, we expect the right one is
behind the bridge and we choose the highest address that doesn ' t
give a response now
*/
tda8290_i2c_bridge ( c , 0 ) ;
if ( tuners_found > 1 )
for ( i = 0 ; i < tuners_found ; i + + ) {
msg . addr = tuner_addrs & 0xff ;
ret = i2c_transfer ( c - > adapter , & msg , 1 ) ;
if ( ret = = 1 )
tuner_addrs = tuner_addrs > > 8 ;
else
break ;
}
if ( tuner_addrs = = 0 ) {
tuner_addrs = 0x61 ;
2005-11-08 21:38:00 -08:00
tuner_info ( " could not clearly identify tuner address, defaulting to %x \n " ,
2005-11-08 21:38:00 -08:00
tuner_addrs ) ;
2005-11-08 21:37:48 -08:00
} else {
tuner_addrs = tuner_addrs & 0xff ;
tuner_info ( " setting tuner address to %x \n " , tuner_addrs ) ;
}
t - > tda827x_addr = tuner_addrs ;
msg . addr = tuner_addrs ;
tda8290_i2c_bridge ( c , 1 ) ;
ret = i2c_transfer ( c - > adapter , & msg , 1 ) ;
if ( ret ! = 1 )
tuner_warn ( " TDA827x access failed! \n " ) ;
if ( ( data & 0x3c ) = = 0 ) {
strlcpy ( c - > name , " tda8290+75 " , sizeof ( c - > name ) ) ;
t - > tda827x_ver = 0 ;
} else {
strlcpy ( c - > name , " tda8290+75a " , sizeof ( c - > name ) ) ;
t - > tda827x_ver = 2 ;
}
2006-02-07 06:49:09 -02:00
tuner_info ( " type set to %s \n " , c - > name ) ;
2005-11-08 21:37:48 -08:00
2006-01-15 15:04:52 -02:00
t - > set_tv_freq = set_tv_freq ;
t - > set_radio_freq = set_radio_freq ;
2005-04-16 15:20:36 -07:00
t - > has_signal = has_signal ;
2005-09-09 13:03:37 -07:00
t - > standby = standby ;
2005-11-08 21:37:48 -08:00
t - > tda827x_lpsel = 0 ;
2007-03-22 20:58:43 -03:00
t - > mode = V4L2_TUNER_ANALOG_TV ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:48 -08:00
tda8290_init_tuner ( c ) ;
tda8290_init_if ( c ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-08 21:38:00 -08:00
int tda8290_probe ( struct i2c_client * c )
{
2006-02-27 00:09:11 -03:00
unsigned char soft_reset [ ] = { 0x00 , 0x00 } ;
unsigned char easy_mode_b [ ] = { 0x01 , 0x02 } ;
unsigned char easy_mode_g [ ] = { 0x01 , 0x04 } ;
unsigned char restore_9886 [ ] = { 0x00 , 0xd6 , 0x30 } ;
2005-11-08 21:38:00 -08:00
unsigned char addr_dto_lsb = 0x07 ;
unsigned char data ;
i2c_master_send ( c , easy_mode_b , 2 ) ;
i2c_master_send ( c , soft_reset , 2 ) ;
i2c_master_send ( c , & addr_dto_lsb , 1 ) ;
i2c_master_recv ( c , & data , 1 ) ;
if ( data = = 0 ) {
i2c_master_send ( c , easy_mode_g , 2 ) ;
i2c_master_send ( c , soft_reset , 2 ) ;
i2c_master_send ( c , & addr_dto_lsb , 1 ) ;
i2c_master_recv ( c , & data , 1 ) ;
if ( data = = 0x7b ) {
return 0 ;
}
}
2006-02-27 00:09:11 -03:00
i2c_master_send ( c , restore_9886 , 3 ) ;
2005-11-08 21:38:00 -08:00
return - 1 ;
}
2005-04-16 15:20:36 -07:00
/*
* Overrides for Emacs so that we follow Linus ' s tabbing style .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Local variables :
* c - basic - offset : 8
* End :
*/