Commit 15396236 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

V4L/DVB (4205): Merge tda9887 module into tuner.

Most uses a tda988[5/6/7] IF demodulator as part of the device.
Having this as a separate stuff makes harder to configure it, since there
are some tda9887 options that are tuner-dependent and should be bound into
tuner-types structures.
This patch merges tda9887 module into tuner. More work is required to make
tuner-types to properly use it.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 0ccac4af
...@@ -6,7 +6,7 @@ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o ...@@ -6,7 +6,7 @@ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \ zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \ tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
mt20xx.o tda8290.o tea5767.o mt20xx.o tda8290.o tea5767.o tda9887.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o
...@@ -60,7 +60,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o ...@@ -60,7 +60,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_BUF) += video-buf.o obj-$(CONFIG_VIDEO_BUF) += video-buf.o
obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
......
...@@ -425,9 +425,19 @@ static int attach_inform(struct i2c_client *client) ...@@ -425,9 +425,19 @@ static int attach_inform(struct i2c_client *client)
struct em28xx *dev = client->adapter->algo_data; struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) { switch (client->addr << 1) {
case 0x86: case 0x43:
case 0x4b:
{
struct tuner_setup tun_setup;
tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
tun_setup.type = TUNER_TDA9887;
tun_setup.addr = client->addr;
em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf); em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
break; break;
}
case 0x42: case 0x42:
dprintk1(1,"attach_inform: saa7114 detected.\n"); dprintk1(1,"attach_inform: saa7114 detected.\n");
break; break;
...@@ -453,6 +463,7 @@ static int attach_inform(struct i2c_client *client) ...@@ -453,6 +463,7 @@ static int attach_inform(struct i2c_client *client)
case 0xba: case 0xba:
dprintk1(1,"attach_inform: tvp5150 detected.\n"); dprintk1(1,"attach_inform: tvp5150 detected.\n");
break; break;
default: default:
dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1); dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
dev->tuner_addr = client->addr; dev->tuner_addr = client->addr;
......
...@@ -18,49 +18,21 @@ ...@@ -18,49 +18,21 @@
TDA9886 (PAL, SECAM, NTSC) TDA9886 (PAL, SECAM, NTSC)
TDA9887 (PAL, SECAM, NTSC, FM Radio) TDA9887 (PAL, SECAM, NTSC, FM Radio)
found on: Used as part of several tuners
- Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
TDA9887 (world), TDA9885 (USA)
Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
- KNC One TV-Station RDS (saa7134)
- Hauppauge PVR-150/500 (possibly more)
*/ */
#define tda9887_info(fmt, arg...) do {\
printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
#define tda9887_dbg(fmt, arg...) do {\
if (tuner_debug) \
printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
/* Addresses to scan */
static unsigned short normal_i2c[] = {
0x84 >>1,
0x86 >>1,
0x96 >>1,
I2C_CLIENT_END,
};
I2C_CLIENT_INSMOD;
/* insmod options */
static unsigned int debug = 0;
module_param(debug, int, 0644);
MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
#define UNSET (-1U) #define UNSET (-1U)
#define tda9887_info(fmt, arg...) do {\
printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
#define tda9887_dbg(fmt, arg...) do {\
if (debug) \
printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
struct tda9887 {
struct i2c_client client;
v4l2_std_id std;
enum tuner_mode mode;
unsigned int config;
unsigned int using_v4l2;
unsigned int radio_mode;
unsigned char data[4];
};
struct tvnorm { struct tvnorm {
v4l2_std_id std; v4l2_std_id std;
...@@ -70,9 +42,6 @@ struct tvnorm { ...@@ -70,9 +42,6 @@ struct tvnorm {
unsigned char e; unsigned char e;
}; };
static struct i2c_driver driver;
static struct i2c_client client_template;
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
// //
...@@ -281,7 +250,7 @@ static struct tvnorm radio_mono = { ...@@ -281,7 +250,7 @@ static struct tvnorm radio_mono = {
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static void dump_read_message(struct tda9887 *t, unsigned char *buf) static void dump_read_message(struct tuner *t, unsigned char *buf)
{ {
static char *afc[16] = { static char *afc[16] = {
"- 12.5 kHz", "- 12.5 kHz",
...@@ -309,7 +278,7 @@ static void dump_read_message(struct tda9887 *t, unsigned char *buf) ...@@ -309,7 +278,7 @@ static void dump_read_message(struct tda9887 *t, unsigned char *buf)
tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
} }
static void dump_write_message(struct tda9887 *t, unsigned char *buf) static void dump_write_message(struct tuner *t, unsigned char *buf)
{ {
static char *sound[4] = { static char *sound[4] = {
"AM/TV", "AM/TV",
...@@ -405,13 +374,13 @@ static void dump_write_message(struct tda9887 *t, unsigned char *buf) ...@@ -405,13 +374,13 @@ static void dump_write_message(struct tda9887 *t, unsigned char *buf)
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) static int tda9887_set_tvnorm(struct tuner *t, char *buf)
{ {
struct tvnorm *norm = NULL; struct tvnorm *norm = NULL;
int i; int i;
if (t->mode == T_RADIO) { if (t->mode == V4L2_TUNER_RADIO) {
if (t->radio_mode == V4L2_TUNER_MODE_MONO) if (t->audmode == V4L2_TUNER_MODE_MONO)
norm = &radio_mono; norm = &radio_mono;
else else
norm = &radio_stereo; norm = &radio_stereo;
...@@ -445,7 +414,7 @@ module_param(port2, int, 0644); ...@@ -445,7 +414,7 @@ module_param(port2, int, 0644);
module_param(qss, int, 0644); module_param(qss, int, 0644);
module_param(adjust, int, 0644); module_param(adjust, int, 0644);
static int tda9887_set_insmod(struct tda9887 *t, char *buf) static int tda9887_set_insmod(struct tuner *t, char *buf)
{ {
if (UNSET != port1) { if (UNSET != port1) {
if (port1) if (port1)
...@@ -474,27 +443,27 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf) ...@@ -474,27 +443,27 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
return 0; return 0;
} }
static int tda9887_set_config(struct tda9887 *t, char *buf) static int tda9887_set_config(struct tuner *t, char *buf)
{ {
if (t->config & TDA9887_PORT1_ACTIVE) if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
buf[1] &= ~cOutputPort1Inactive; buf[1] &= ~cOutputPort1Inactive;
if (t->config & TDA9887_PORT1_INACTIVE) if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
buf[1] |= cOutputPort1Inactive; buf[1] |= cOutputPort1Inactive;
if (t->config & TDA9887_PORT2_ACTIVE) if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
buf[1] &= ~cOutputPort2Inactive; buf[1] &= ~cOutputPort2Inactive;
if (t->config & TDA9887_PORT2_INACTIVE) if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
buf[1] |= cOutputPort2Inactive; buf[1] |= cOutputPort2Inactive;
if (t->config & TDA9887_QSS) if (t->tda9887_config & TDA9887_QSS)
buf[1] |= cQSS; buf[1] |= cQSS;
if (t->config & TDA9887_INTERCARRIER) if (t->tda9887_config & TDA9887_INTERCARRIER)
buf[1] &= ~cQSS; buf[1] &= ~cQSS;
if (t->config & TDA9887_AUTOMUTE) if (t->tda9887_config & TDA9887_AUTOMUTE)
buf[1] |= cAutoMuteFmActive; buf[1] |= cAutoMuteFmActive;
if (t->config & TDA9887_DEEMPHASIS_MASK) { if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
buf[2] &= ~0x60; buf[2] &= ~0x60;
switch (t->config & TDA9887_DEEMPHASIS_MASK) { switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
case TDA9887_DEEMPHASIS_NONE: case TDA9887_DEEMPHASIS_NONE:
buf[2] |= cDeemphasisOFF; buf[2] |= cDeemphasisOFF;
break; break;
...@@ -506,153 +475,36 @@ static int tda9887_set_config(struct tda9887 *t, char *buf) ...@@ -506,153 +475,36 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
break; break;
} }
} }
if (t->config & TDA9887_TOP_SET) { if (t->tda9887_config & TDA9887_TOP_SET) {
buf[2] &= ~cTopMask; buf[2] &= ~cTopMask;
buf[2] |= (t->config >> 8) & cTopMask; buf[2] |= (t->tda9887_config >> 8) & cTopMask;
} }
if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
buf[1] &= ~cQSS; buf[1] &= ~cQSS;
return 0; return 0;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static char pal[] = "--"; static int tda9887_status(struct tuner *t)
static char secam[] = "--";
static char ntsc[] = "-";
module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
static int tda9887_fixup_std(struct tda9887 *t)
{
/* get more precise norm info from insmod option */
if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
switch (pal[0]) {
case 'b':
case 'B':
case 'g':
case 'G':
case 'h':
case 'H':
case 'n':
case 'N':
if (pal[1] == 'c' || pal[1] == 'C') {
tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
t->std = V4L2_STD_PAL_Nc;
} else {
tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
}
break;
case 'i':
case 'I':
tda9887_dbg("insmod fixup: PAL => PAL-I\n");
t->std = V4L2_STD_PAL_I;
break;
case 'd':
case 'D':
case 'k':
case 'K':
tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
t->std = V4L2_STD_PAL_DK;
break;
case 'm':
case 'M':
tda9887_dbg("insmod fixup: PAL => PAL-M\n");
t->std = V4L2_STD_PAL_M;
break;
case '-':
/* default parameter, do nothing */
break;
default:
tda9887_info("pal= argument not recognised\n");
break;
}
}
if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
switch (secam[0]) {
case 'b':
case 'B':
case 'g':
case 'G':
case 'h':
case 'H':
tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
break;
case 'd':
case 'D':
case 'k':
case 'K':
tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
t->std = V4L2_STD_SECAM_DK;
break;
case 'l':
case 'L':
if (secam[1] == 'c' || secam[1] == 'C') {
tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
t->std = V4L2_STD_SECAM_LC;
} else {
tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
t->std = V4L2_STD_SECAM_L;
}
break;
case '-':
/* default parameter, do nothing */
break;
default:
tda9887_info("secam= argument not recognised\n");
break;
}
}
if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
switch (ntsc[0]) {
case 'm':
case 'M':
tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
t->std = V4L2_STD_NTSC_M;
break;
case 'j':
case 'J':
tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
t->std = V4L2_STD_NTSC_M_JP;
break;
case 'k':
case 'K':
tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
t->std = V4L2_STD_NTSC_M_KR;
break;
case '-':
/* default parameter, do nothing */
break;
default:
tda9887_info("ntsc= argument not recognised\n");
break;
}
}
return 0;
}
static int tda9887_status(struct tda9887 *t)
{ {
unsigned char buf[1]; unsigned char buf[1];
int rc; int rc;
memset(buf,0,sizeof(buf)); memset(buf,0,sizeof(buf));
if (1 != (rc = i2c_master_recv(&t->client,buf,1))) if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
dump_read_message(t, buf); dump_read_message(t, buf);
return 0; return 0;
} }
static int tda9887_configure(struct tda9887 *t) static void tda9887_configure(struct i2c_client *client)
{ {
struct tuner *t = i2c_get_clientdata(client);
int rc; int rc;
memset(t->data,0,sizeof(t->data)); memset(t->tda9887_data,0,sizeof(t->tda9887_data));
tda9887_set_tvnorm(t,t->data); tda9887_set_tvnorm(t,t->tda9887_data);
/* A note on the port settings: /* A note on the port settings:
These settings tend to depend on the specifics of the board. These settings tend to depend on the specifics of the board.
...@@ -667,249 +519,84 @@ static int tda9887_configure(struct tda9887 *t) ...@@ -667,249 +519,84 @@ static int tda9887_configure(struct tda9887 *t)
the ports should be set to active (0), but, again, that may the ports should be set to active (0), but, again, that may
differ depending on the precise hardware configuration. differ depending on the precise hardware configuration.
*/ */
t->data[1] |= cOutputPort1Inactive; t->tda9887_data[1] |= cOutputPort1Inactive;
t->data[1] |= cOutputPort2Inactive; t->tda9887_data[1] |= cOutputPort2Inactive;
tda9887_set_config(t,t->data); tda9887_set_config(t,t->tda9887_data);
tda9887_set_insmod(t,t->data); tda9887_set_insmod(t,t->tda9887_data);
if (t->mode == T_STANDBY) { if (t->mode == T_STANDBY) {
t->data[1] |= cForcedMuteAudioON; t->tda9887_data[1] |= cForcedMuteAudioON;
} }
tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
t->data[1],t->data[2],t->data[3]); t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
if (debug > 1) if (tuner_debug > 1)
dump_write_message(t, t->data); dump_write_message(t, t->tda9887_data);
if (4 != (rc = i2c_master_send(&t->client,t->data,4))) if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
if (debug > 2) { if (tuner_debug > 2) {
msleep_interruptible(1000); msleep_interruptible(1000);
tda9887_status(t); tda9887_status(t);
} }
return 0;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) static void tda9887_tuner_status(struct i2c_client *client)
{ {
struct tda9887 *t; struct tuner *t = i2c_get_clientdata(client);
tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
client_template.adapter = adap;
client_template.addr = addr;
if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
return -ENOMEM;
t->client = client_template;
t->std = 0;
t->radio_mode = V4L2_TUNER_MODE_STEREO;
tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
i2c_set_clientdata(&t->client, t);
i2c_attach_client(&t->client);
return 0;
} }
static int tda9887_probe(struct i2c_adapter *adap) static int tda9887_get_afc(struct i2c_client *client)
{ {
if (adap->class & I2C_CLASS_TV_ANALOG) struct tuner *t = i2c_get_clientdata(client);
return i2c_probe(adap, &addr_data, tda9887_attach); static int AFC_BITS_2_kHz[] = {
return 0; -12500, -37500, -62500, -97500,
} -112500, -137500, -162500, -187500,
187500, 162500, 137500, 112500,
97500 , 62500, 37500 , 12500
};
int afc=0;
__u8 reg = 0;
static int tda9887_detach(struct i2c_client *client) if (1 == i2c_master_recv(&t->i2c,&reg,1))
{ afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
struct tda9887 *t = i2c_get_clientdata(client);
i2c_detach_client(client); return afc;
kfree(t);
return 0;
} }
#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \ static void tda9887_standby(struct i2c_client *client)
tda9887_info("switching to v4l2\n"); \
t->using_v4l2 = 1;
#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \
tda9887_info("ignore v4l1 call\n"); \
return 0; }
static int
tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
{ {
struct tda9887 *t = i2c_get_clientdata(client); tda9887_configure(client);
switch (cmd) {
/* --- configuration --- */
case AUDC_SET_RADIO:
{
t->mode = T_RADIO;
tda9887_configure(t);
break;
}
case TUNER_SET_STANDBY:
{
t->mode = T_STANDBY;
tda9887_configure(t);
break;
}
case TDA9887_SET_CONFIG:
{
int *i = arg;
t->config = *i;
tda9887_configure(t);
break;
}
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
case VIDIOCSCHAN:
{
static const v4l2_std_id map[] = {
[ VIDEO_MODE_PAL ] = V4L2_STD_PAL,
[ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M,
[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
[ 4 /* bttv */ ] = V4L2_STD_PAL_M,
[ 5 /* bttv */ ] = V4L2_STD_PAL_N,
[ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
};
struct video_channel *vc = arg;
CHECK_V4L2;
t->mode = T_ANALOG_TV;
if (vc->norm < ARRAY_SIZE(map))
t->std = map[vc->norm];
tda9887_fixup_std(t);
tda9887_configure(t);
break;
}
case VIDIOC_S_STD:
{
v4l2_std_id *id = arg;
SWITCH_V4L2;
t->mode = T_ANALOG_TV;
t->std = *id;
tda9887_fixup_std(t);
tda9887_configure(t);
break;
}
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *f = arg;
SWITCH_V4L2;
if (V4L2_TUNER_ANALOG_TV == f->type) {
if (t->mode == T_ANALOG_TV)
return 0;
t->mode = T_ANALOG_TV;
}
if (V4L2_TUNER_RADIO == f->type) {
if (t->mode == T_RADIO)
return 0;
t->mode = T_RADIO;
}
tda9887_configure(t);
break;
}
case VIDIOC_G_TUNER:
{
static int AFC_BITS_2_kHz[] = {
-12500, -37500, -62500, -97500,
-112500, -137500, -162500, -187500,
187500, 162500, 137500, 112500,
97500 , 62500, 37500 , 12500
};
struct v4l2_tuner* tuner = arg;
if (t->mode == T_RADIO) {
__u8 reg = 0;
tuner->afc=0;
if (1 == i2c_master_recv(&t->client,&reg,1))
tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
}
break;
}
case VIDIOC_S_TUNER:
{
struct v4l2_tuner* tuner = arg;
if (t->mode == T_RADIO) {
t->radio_mode = tuner->audmode;
tda9887_configure (t);
}
break;
}
case VIDIOC_LOG_STATUS:
{
tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
break;
}
default:
/* nothing */
break;
}
return 0;
} }
static int tda9887_suspend(struct device * dev, pm_message_t state) static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
{ {
struct i2c_client *c = container_of(dev, struct i2c_client, dev); tda9887_configure(client);
struct tda9887 *t = i2c_get_clientdata(c);
tda9887_dbg("suspend\n");
return 0;
} }
static int tda9887_resume(struct device * dev) int tda9887_tuner_init(struct i2c_client *c)
{ {
struct i2c_client *c = container_of(dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata(c);
struct tda9887 *t = i2c_get_clientdata(c);
tda9887_dbg("resume\n"); strlcpy(c->name, "tda9887", sizeof(c->name));
tda9887_configure(t);
return 0;
}
/* ----------------------------------------------------------------------- */ tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
t->i2c.driver->driver.name);
static struct i2c_driver driver = {
.id = I2C_DRIVERID_TDA9887,
.attach_adapter = tda9887_probe,
.detach_client = tda9887_detach,
.command = tda9887_command,
.driver = {
.name = "tda9887",
.suspend = tda9887_suspend,
.resume = tda9887_resume,
},
};
static struct i2c_client client_template =
{
.name = "tda9887",
.driver = &driver,
};
static int __init tda9887_init_module(void) t->set_tv_freq = tda9887_set_freq;
{ t->set_radio_freq = tda9887_set_freq;
return i2c_add_driver(&driver); t->standby = tda9887_standby;
} t->tuner_status=tda9887_tuner_status;
t->get_afc=tda9887_get_afc;
static void __exit tda9887_cleanup_module(void) return 0;
{
i2c_del_driver(&driver);
} }
module_init(tda9887_init_module);
module_exit(tda9887_cleanup_module);
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
* --------------------------------------------------------------------------- * ---------------------------------------------------------------------------
......
...@@ -215,6 +215,9 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -215,6 +215,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c,buffer,4); i2c_master_send(c,buffer,4);
default_tuner_init(c); default_tuner_init(c);
break; break;
case TUNER_TDA9887:
tda9887_tuner_init(c);
break;
default: default:
default_tuner_init(c); default_tuner_init(c);
break; break;
...@@ -241,6 +244,8 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) ...@@ -241,6 +244,8 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = i2c_get_clientdata(c);
tuner_dbg("set addr for type %i\n", t->type);
if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET && if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
(t->mode_mask & tun_setup->mode_mask)) || (t->mode_mask & tun_setup->mode_mask)) ||
tun_setup->addr == c->addr)) { tun_setup->addr == c->addr)) {
...@@ -436,6 +441,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) ...@@ -436,6 +441,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
t->audmode = V4L2_TUNER_MODE_STEREO; t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED; t->mode_mask = T_UNINITIALIZED;
t->tuner_status = tuner_status;
if (tuner_debug_old) { if (tuner_debug_old) {
tuner_debug = tuner_debug_old; tuner_debug = tuner_debug_old;
printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n"); printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
...@@ -462,10 +468,14 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) ...@@ -462,10 +468,14 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
case 0x4b: case 0x4b:
/* If chip is not tda8290, don't register. /* If chip is not tda8290, don't register.
since it can be tda9887*/ since it can be tda9887*/
if (tda8290_probe(&t->i2c) != 0) { if (tda8290_probe(&t->i2c) == 0) {
tuner_dbg("chip at addr %x is not a tda8290\n", addr); tuner_dbg("chip at addr %x is a tda8290\n", addr);
kfree(t); } else {
return 0; /* Default is being tda9887 */
t->type = TUNER_TDA9887;
t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
t->mode = T_STANDBY;
goto register_client;
} }
break; break;
case 0x60: case 0x60:
...@@ -592,6 +602,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -592,6 +602,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
case TUNER_SET_STANDBY: case TUNER_SET_STANDBY:
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0; return 0;
t->mode = T_STANDBY;
if (t->standby) if (t->standby)
t->standby (client); t->standby (client);
break; break;
...@@ -604,6 +615,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -604,6 +615,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* Should be implemented, since bttv calls it */ /* Should be implemented, since bttv calls it */
tuner_dbg("VIDIOCSAUDIO not implemented.\n"); tuner_dbg("VIDIOCSAUDIO not implemented.\n");
break; break;
case TDA9887_SET_CONFIG:
{
int *i = arg;
t->tda9887_config = *i;
set_freq(client, t->tv_freq);
break;
}
/* --- v4l ioctls --- */ /* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a /* take care: bttv does userspace copying, we'll get a
kernel pointer here... */ kernel pointer here... */
...@@ -744,6 +763,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -744,6 +763,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2(); switch_v4l2();
tuner->type = t->mode; tuner->type = t->mode;
if (t->get_afc)
tuner->afc=t->get_afc(client);
if (t->mode == V4L2_TUNER_ANALOG_TV) if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM; tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) { if (t->mode != V4L2_TUNER_RADIO) {
...@@ -787,7 +808,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -787,7 +808,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break; break;
} }
case VIDIOC_LOG_STATUS: case VIDIOC_LOG_STATUS:
tuner_status(client); if (t->tuner_status)
t->tuner_status(client);
break; break;
} }
......
...@@ -1421,6 +1421,11 @@ struct tunertype tuners[] = { ...@@ -1421,6 +1421,11 @@ struct tunertype tuners[] = {
.params = tuner_samsung_tcpg_6121p30a_params, .params = tuner_samsung_tcpg_6121p30a_params,
.count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params), .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
}, },
[TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
This chip is part of some modern tuners */
.name = "Philips TDA988[5,6,7] IF PLL Demodulator",
/* see tda9887.c for details */
},
}; };
unsigned const int tuner_count = ARRAY_SIZE(tuners); unsigned const int tuner_count = ARRAY_SIZE(tuners);
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/tuner-types.h> #include <media/tuner-types.h>
extern int tuner_debug;
#define ADDR_UNSET (255) #define ADDR_UNSET (255)
#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ #define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */
...@@ -120,6 +122,7 @@ ...@@ -120,6 +122,7 @@
#define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */ #define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */
#define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */
#define TUNER_TDA9887 74 /* This tuner should be used only internally */
/* tv card specific */ /* tv card specific */
#define TDA9887_PRESENT (1<<0) #define TDA9887_PRESENT (1<<0)
...@@ -191,6 +194,10 @@ struct tuner { ...@@ -191,6 +194,10 @@ struct tuner {
int using_v4l2; int using_v4l2;
/* used by tda9887 */
unsigned int tda9887_config;
unsigned char tda9887_data[4];
/* used by MT2032 */ /* used by MT2032 */
unsigned int xogc; unsigned int xogc;
unsigned int radio_if2; unsigned int radio_if2;
...@@ -207,6 +214,8 @@ struct tuner { ...@@ -207,6 +214,8 @@ struct tuner {
void (*set_radio_freq)(struct i2c_client *c, unsigned int freq); void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
int (*has_signal)(struct i2c_client *c); int (*has_signal)(struct i2c_client *c);
int (*is_stereo)(struct i2c_client *c); int (*is_stereo)(struct i2c_client *c);
int (*get_afc)(struct i2c_client *c);
void (*tuner_status)(struct i2c_client *c);
void (*standby)(struct i2c_client *c); void (*standby)(struct i2c_client *c);
}; };
...@@ -219,6 +228,7 @@ extern int tda8290_probe(struct i2c_client *c); ...@@ -219,6 +228,7 @@ extern int tda8290_probe(struct i2c_client *c);
extern int tea5767_tuner_init(struct i2c_client *c); extern int tea5767_tuner_init(struct i2c_client *c);
extern int default_tuner_init(struct i2c_client *c); extern int default_tuner_init(struct i2c_client *c);
extern int tea5767_autodetection(struct i2c_client *c); extern int tea5767_autodetection(struct i2c_client *c);
extern int tda9887_tuner_init(struct i2c_client *c);
#define tuner_warn(fmt, arg...) do {\ #define tuner_warn(fmt, arg...) do {\
printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment