mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +00:00
V4L/DVB (8941): mxb/tda9840: cleanups, use module saa7115 instead of saa7111.
Cleanup tda9840 and use a v4l2 API to get the tuner subchannels. Do some cleanups in mxb and switch to saa7115 instead of the saa7111 module. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
6bd6dff631
commit
707ecf4603
@ -691,7 +691,7 @@ config VIDEO_MXB
|
||||
depends on PCI && VIDEO_V4L1 && I2C
|
||||
select VIDEO_SAA7146_VV
|
||||
select VIDEO_TUNER
|
||||
select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_SAA7115 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <media/tuner.h>
|
||||
#include <linux/video_decoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/saa7115.h>
|
||||
|
||||
#include "mxb.h"
|
||||
#include "tea6415c.h"
|
||||
@ -122,6 +123,8 @@ static struct saa7146_extension_ioctls ioctls[] = {
|
||||
{ VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
|
||||
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
|
||||
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
|
||||
{ VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE },
|
||||
{ VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE },
|
||||
{ MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
|
||||
{ MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
|
||||
{ 0, 0 }
|
||||
@ -154,20 +157,20 @@ static int mxb_check_clients(struct device *dev, void *data)
|
||||
struct mxb* mxb = data;
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
|
||||
if( !client )
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
if( I2C_ADDR_TEA6420_1 == client->addr )
|
||||
if (I2C_ADDR_TEA6420_1 == client->addr)
|
||||
mxb->tea6420_1 = client;
|
||||
if( I2C_ADDR_TEA6420_2 == client->addr )
|
||||
if (I2C_ADDR_TEA6420_2 == client->addr)
|
||||
mxb->tea6420_2 = client;
|
||||
if( I2C_TEA6415C_2 == client->addr )
|
||||
if (I2C_TEA6415C_2 == client->addr)
|
||||
mxb->tea6415c = client;
|
||||
if( I2C_ADDR_TDA9840 == client->addr )
|
||||
if (I2C_ADDR_TDA9840 == client->addr)
|
||||
mxb->tda9840 = client;
|
||||
if( I2C_SAA7111 == client->addr )
|
||||
if (I2C_SAA7111 == client->addr)
|
||||
mxb->saa7111a = client;
|
||||
if( 0x60 == client->addr )
|
||||
if (0x60 == client->addr)
|
||||
mxb->tuner = client;
|
||||
|
||||
return 0;
|
||||
@ -178,23 +181,28 @@ static int mxb_probe(struct saa7146_dev* dev)
|
||||
struct mxb* mxb = NULL;
|
||||
int result;
|
||||
|
||||
if ((result = request_module("saa7111")) < 0) {
|
||||
result = request_module("saa7115");
|
||||
if (result < 0) {
|
||||
printk("mxb: saa7111 i2c module not available.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((result = request_module("tea6420")) < 0) {
|
||||
result = request_module("tea6420");
|
||||
if (result < 0) {
|
||||
printk("mxb: tea6420 i2c module not available.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((result = request_module("tea6415c")) < 0) {
|
||||
result = request_module("tea6415c");
|
||||
if (result < 0) {
|
||||
printk("mxb: tea6415c i2c module not available.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((result = request_module("tda9840")) < 0) {
|
||||
result = request_module("tda9840");
|
||||
if (result < 0) {
|
||||
printk("mxb: tda9840 i2c module not available.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((result = request_module("tuner")) < 0) {
|
||||
result = request_module("tuner");
|
||||
if (result < 0) {
|
||||
printk("mxb: tuner i2c module not available.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -293,37 +301,6 @@ static struct {
|
||||
{-1, { 0} }
|
||||
};
|
||||
|
||||
static const unsigned char mxb_saa7111_init[] = {
|
||||
0x00, 0x00, /* 00 - ID byte */
|
||||
0x01, 0x00, /* 01 - reserved */
|
||||
|
||||
/*front end */
|
||||
0x02, 0xd8, /* 02 - FUSE=x, GUDL=x, MODE=x */
|
||||
0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
|
||||
0x04, 0x00, /* 04 - GAI1=256 */
|
||||
0x05, 0x00, /* 05 - GAI2=256 */
|
||||
|
||||
/* decoder */
|
||||
0x06, 0xf0, /* 06 - HSB at xx(50Hz) / xx(60Hz) pixels after end of last line */
|
||||
0x07, 0x30, /* 07 - HSS at xx(50Hz) / xx(60Hz) pixels after end of last line */
|
||||
0x08, 0xa8, /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
|
||||
0x09, 0x02, /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
|
||||
0x0a, 0x80, /* 0a - BRIG=128 */
|
||||
0x0b, 0x47, /* 0b - CONT=1.109 */
|
||||
0x0c, 0x40, /* 0c - SATN=1.0 */
|
||||
0x0d, 0x00, /* 0d - HUE=0 */
|
||||
0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
|
||||
0x0f, 0x00, /* 0f - reserved */
|
||||
0x10, 0xd0, /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
|
||||
0x11, 0x8c, /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
|
||||
0x12, 0x80, /* 12 - xx output control 2 */
|
||||
0x13, 0x30, /* 13 - xx output control 3 */
|
||||
0x14, 0x00, /* 14 - reserved */
|
||||
0x15, 0x15, /* 15 - VBI */
|
||||
0x16, 0x04, /* 16 - VBI */
|
||||
0x17, 0x00, /* 17 - VBI */
|
||||
};
|
||||
|
||||
/* bring hardware to a sane state. this has to be done, just in case someone
|
||||
wants to capture from this device before it has been properly initialized.
|
||||
the capture engine would badly fail, because no valid signal arrives on the
|
||||
@ -331,37 +308,29 @@ static const unsigned char mxb_saa7111_init[] = {
|
||||
static int mxb_init_done(struct saa7146_dev* dev)
|
||||
{
|
||||
struct mxb* mxb = (struct mxb*)dev->ext_priv;
|
||||
struct video_decoder_init init;
|
||||
struct i2c_msg msg;
|
||||
struct tuner_setup tun_setup;
|
||||
v4l2_std_id std = V4L2_STD_PAL_BG;
|
||||
struct v4l2_routing route;
|
||||
|
||||
int i = 0, err = 0;
|
||||
struct tea6415c_multiplex vm;
|
||||
|
||||
/* select video mode in saa7111a */
|
||||
i = VIDEO_MODE_PAL;
|
||||
/* fixme: currently pointless: gets overwritten by configuration below */
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
|
||||
|
||||
/* write configuration to saa7111a */
|
||||
init.data = mxb_saa7111_init;
|
||||
init.len = sizeof(mxb_saa7111_init);
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
|
||||
|
||||
/* select tuner-output on saa7111a */
|
||||
i = 0;
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
|
||||
|
||||
/* enable vbi bypass */
|
||||
i = 1;
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
|
||||
route.input = SAA7115_COMPOSITE0;
|
||||
route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
|
||||
|
||||
/* select a tuner type */
|
||||
tun_setup.mode_mask = T_ANALOG_TV;
|
||||
tun_setup.addr = ADDR_UNSET;
|
||||
tun_setup.type = TUNER_PHILIPS_PAL;
|
||||
mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
|
||||
mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
|
||||
/* tune in some frequency on tuner */
|
||||
mxb->cur_freq.tuner = 0;
|
||||
mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
|
||||
@ -393,7 +362,6 @@ static int mxb_init_done(struct saa7146_dev* dev)
|
||||
mxb->cur_mute = 1;
|
||||
|
||||
mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
|
||||
mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
|
||||
|
||||
/* check if the saa7740 (aka 'sound arena module') is present
|
||||
on the mxb. if so, we must initialize it. due to lack of
|
||||
@ -626,7 +594,8 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
case VIDIOC_S_INPUT:
|
||||
{
|
||||
int input = *(int *)arg;
|
||||
struct tea6415c_multiplex vm;
|
||||
struct tea6415c_multiplex vm;
|
||||
struct v4l2_routing route;
|
||||
int i = 0;
|
||||
|
||||
DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
|
||||
@ -635,19 +604,6 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* fixme: locke das setzen des inputs mit hilfe des mutexes
|
||||
mutex_lock(&dev->lock);
|
||||
video_mux(dev,*i);
|
||||
mutex_unlock(&dev->lock);
|
||||
*/
|
||||
|
||||
/* fixme: check if streaming capture
|
||||
if ( 0 != dev->streaming ) {
|
||||
DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
|
||||
return -EPERM;
|
||||
}
|
||||
*/
|
||||
|
||||
mxb->cur_input = input;
|
||||
|
||||
saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
|
||||
@ -658,7 +614,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
|
||||
case TUNER:
|
||||
{
|
||||
i = 0;
|
||||
i = SAA7115_COMPOSITE0;
|
||||
vm.in = 3;
|
||||
vm.out = 17;
|
||||
|
||||
@ -675,19 +631,19 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
{
|
||||
/* nothing to be done here. aux3_yc is
|
||||
directly connected to the saa711a */
|
||||
i = 5;
|
||||
i = SAA7115_SVIDEO1;
|
||||
break;
|
||||
}
|
||||
case AUX3:
|
||||
{
|
||||
/* nothing to be done here. aux3 is
|
||||
directly connected to the saa711a */
|
||||
i = 1;
|
||||
i = SAA7115_COMPOSITE1;
|
||||
break;
|
||||
}
|
||||
case AUX1:
|
||||
{
|
||||
i = 0;
|
||||
i = SAA7115_COMPOSITE0;
|
||||
vm.in = 1;
|
||||
vm.out = 17;
|
||||
break;
|
||||
@ -712,9 +668,10 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
}
|
||||
|
||||
/* switch video in saa7111a */
|
||||
if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
|
||||
route.input = i;
|
||||
route.output = 0;
|
||||
if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
|
||||
printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
|
||||
}
|
||||
|
||||
/* switch the audio-source only if necessary */
|
||||
if( 0 == mxb->cur_mute ) {
|
||||
@ -727,105 +684,35 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *t = arg;
|
||||
int byte = 0;
|
||||
|
||||
if( 0 != t->index ) {
|
||||
if (t->index) {
|
||||
DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
|
||||
|
||||
memset(t,0,sizeof(*t));
|
||||
memset(t, 0, sizeof(*t));
|
||||
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
|
||||
|
||||
strlcpy(t->name, "Television", sizeof(t->name));
|
||||
strlcpy(t->name, "TV Tuner", sizeof(t->name));
|
||||
t->type = V4L2_TUNER_ANALOG_TV;
|
||||
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
|
||||
t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
|
||||
t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
|
||||
/* FIXME: add the real signal strength here */
|
||||
t->signal = 0xffff;
|
||||
t->afc = 0;
|
||||
mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
|
||||
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
|
||||
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
|
||||
t->audmode = mxb->cur_mode;
|
||||
|
||||
if( byte < 0 ) {
|
||||
t->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
} else {
|
||||
switch(byte) {
|
||||
case TDA9840_MONO_DETECT: {
|
||||
t->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
|
||||
break;
|
||||
}
|
||||
case TDA9840_DUAL_DETECT: {
|
||||
t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
|
||||
DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
|
||||
break;
|
||||
}
|
||||
case TDA9840_STEREO_DETECT: {
|
||||
t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
|
||||
DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
|
||||
break;
|
||||
}
|
||||
default: { /* TDA9840_INCORRECT_DETECT */
|
||||
t->rxsubchans = V4L2_TUNER_MODE_MONO;
|
||||
DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *t = arg;
|
||||
int result = 0;
|
||||
int byte = 0;
|
||||
|
||||
if( 0 != t->index ) {
|
||||
if (t->index) {
|
||||
DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch(t->audmode) {
|
||||
case V4L2_TUNER_MODE_STEREO: {
|
||||
mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
|
||||
byte = TDA9840_SET_STEREO;
|
||||
DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
|
||||
break;
|
||||
}
|
||||
case V4L2_TUNER_MODE_LANG1_LANG2: {
|
||||
mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
|
||||
byte = TDA9840_SET_BOTH;
|
||||
DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
|
||||
break;
|
||||
}
|
||||
case V4L2_TUNER_MODE_LANG1: {
|
||||
mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
|
||||
byte = TDA9840_SET_LANG1;
|
||||
DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
|
||||
break;
|
||||
}
|
||||
case V4L2_TUNER_MODE_LANG2: {
|
||||
mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
|
||||
byte = TDA9840_SET_LANG2;
|
||||
DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
|
||||
break;
|
||||
}
|
||||
default: { /* case V4L2_TUNER_MODE_MONO: {*/
|
||||
mxb->cur_mode = V4L2_TUNER_MODE_MONO;
|
||||
byte = TDA9840_SET_MONO;
|
||||
DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
|
||||
printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
|
||||
}
|
||||
|
||||
mxb->cur_mode = t->audmode;
|
||||
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
@ -852,8 +739,8 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
if (V4L2_TUNER_ANALOG_TV != f->type)
|
||||
return -EINVAL;
|
||||
|
||||
if(0 != mxb->cur_input) {
|
||||
DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
|
||||
if (mxb->cur_input) {
|
||||
DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -921,6 +808,10 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
||||
DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_DBG_S_REGISTER:
|
||||
case VIDIOC_DBG_G_REGISTER:
|
||||
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
DEB2(printk("does not handle this ioctl.\n"));
|
||||
@ -943,7 +834,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
|
||||
/* set the 7146 gpio register -- I don't know what this does exactly */
|
||||
saa7146_write(dev, GPIO_CTRL, 0x00404050);
|
||||
/* unset the 7111 gpio register -- I don't know what this does exactly */
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
|
||||
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
|
||||
} else {
|
||||
v4l2_std_id std = V4L2_STD_PAL_BG;
|
||||
@ -952,7 +843,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
|
||||
/* set the 7146 gpio register -- I don't know what this does exactly */
|
||||
saa7146_write(dev, GPIO_CTRL, 0x00404050);
|
||||
/* set the 7111 gpio register -- I don't know what this does exactly */
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
|
||||
mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
|
||||
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
|
||||
}
|
||||
return 0;
|
||||
|
@ -47,6 +47,15 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
#define STEREO_ADJUST 0x03
|
||||
#define TEST 0x04
|
||||
|
||||
#define TDA9840_SET_MUTE 0x00
|
||||
#define TDA9840_SET_MONO 0x10
|
||||
#define TDA9840_SET_STEREO 0x2a
|
||||
#define TDA9840_SET_LANG1 0x12
|
||||
#define TDA9840_SET_LANG2 0x1e
|
||||
#define TDA9840_SET_BOTH 0x1a
|
||||
#define TDA9840_SET_BOTH_R 0x16
|
||||
#define TDA9840_SET_EXTERNAL 0x7a
|
||||
|
||||
/* addresses to scan, found only at 0x42 (7-Bit) */
|
||||
static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
|
||||
|
||||
@ -62,26 +71,74 @@ static void tda9840_write(struct i2c_client *client, u8 reg, u8 val)
|
||||
|
||||
static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
int result;
|
||||
int result = 0;
|
||||
int byte = *(int *)arg;
|
||||
|
||||
switch (cmd) {
|
||||
case TDA9840_SWITCH:
|
||||
v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
|
||||
case VIDIOC_S_TUNER: {
|
||||
struct v4l2_tuner *t = arg;
|
||||
int byte;
|
||||
|
||||
if (byte != TDA9840_SET_MONO
|
||||
&& byte != TDA9840_SET_MUTE
|
||||
&& byte != TDA9840_SET_STEREO
|
||||
&& byte != TDA9840_SET_LANG1
|
||||
&& byte != TDA9840_SET_LANG2
|
||||
&& byte != TDA9840_SET_BOTH
|
||||
&& byte != TDA9840_SET_BOTH_R
|
||||
&& byte != TDA9840_SET_EXTERNAL) {
|
||||
if (t->index)
|
||||
return -EINVAL;
|
||||
|
||||
switch (t->audmode) {
|
||||
case V4L2_TUNER_MODE_STEREO:
|
||||
byte = TDA9840_SET_STEREO;
|
||||
break;
|
||||
case V4L2_TUNER_MODE_LANG1_LANG2:
|
||||
byte = TDA9840_SET_BOTH;
|
||||
break;
|
||||
case V4L2_TUNER_MODE_LANG1:
|
||||
byte = TDA9840_SET_LANG1;
|
||||
break;
|
||||
case V4L2_TUNER_MODE_LANG2:
|
||||
byte = TDA9840_SET_LANG2;
|
||||
break;
|
||||
default:
|
||||
byte = TDA9840_SET_MONO;
|
||||
break;
|
||||
}
|
||||
v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
|
||||
tda9840_write(client, SWITCH, byte);
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDIOC_G_TUNER: {
|
||||
struct v4l2_tuner *t = arg;
|
||||
u8 byte;
|
||||
|
||||
t->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
if (1 != i2c_master_recv(client, &byte, 1)) {
|
||||
v4l_dbg(1, debug, client,
|
||||
"i2c_master_recv() failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (byte & 0x80) {
|
||||
v4l_dbg(1, debug, client,
|
||||
"TDA9840_DETECT: register contents invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tda9840_write(client, SWITCH, byte);
|
||||
v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
|
||||
|
||||
switch (byte & 0x60) {
|
||||
case 0x00:
|
||||
t->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
break;
|
||||
case 0x20:
|
||||
t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
|
||||
break;
|
||||
case 0x40:
|
||||
t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
|
||||
break;
|
||||
default: /* Incorrect detect */
|
||||
t->rxsubchans = V4L2_TUNER_MODE_MONO;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TDA9840_LEVEL_ADJUST:
|
||||
v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte);
|
||||
@ -115,36 +172,6 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
|
||||
tda9840_write(client, STEREO_ADJUST, byte);
|
||||
break;
|
||||
|
||||
case TDA9840_DETECT: {
|
||||
int *ret = (int *)arg;
|
||||
|
||||
byte = i2c_smbus_read_byte_data(client, STEREO_ADJUST);
|
||||
if (byte == -1) {
|
||||
v4l_dbg(1, debug, client,
|
||||
"i2c_smbus_read_byte_data() failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (byte & 0x80) {
|
||||
v4l_dbg(1, debug, client,
|
||||
"TDA9840_DETECT: register contents invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
|
||||
*ret = (byte & 0x60) >> 5;
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
case TDA9840_TEST:
|
||||
v4l_dbg(1, debug, client, "TDA9840_TEST: 0x%02x\n", byte);
|
||||
|
||||
/* mask out irrelevant bits */
|
||||
byte &= 0x3;
|
||||
|
||||
tda9840_write(client, TEST, byte);
|
||||
break;
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
@ -174,8 +201,7 @@ static int tda9840_probe(struct i2c_client *client,
|
||||
byte = 0;
|
||||
result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte);
|
||||
result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte);
|
||||
byte = TDA9840_SET_MONO;
|
||||
result = tda9840_command(client, TDA9840_SWITCH, &byte);
|
||||
tda9840_write(client, SWITCH, TDA9840_SET_STEREO);
|
||||
if (result) {
|
||||
v4l_dbg(1, debug, client, "could not initialize tda9840\n");
|
||||
return -ENODEV;
|
||||
|
@ -3,24 +3,6 @@
|
||||
|
||||
#define I2C_ADDR_TDA9840 0x42
|
||||
|
||||
#define TDA9840_DETECT _IOR('v',1,int)
|
||||
/* return values for TDA9840_DETCT */
|
||||
#define TDA9840_MONO_DETECT 0x0
|
||||
#define TDA9840_DUAL_DETECT 0x1
|
||||
#define TDA9840_STEREO_DETECT 0x2
|
||||
#define TDA9840_INCORRECT_DETECT 0x3
|
||||
|
||||
#define TDA9840_SWITCH _IOW('v',2,int)
|
||||
/* modes than can be set with TDA9840_SWITCH */
|
||||
#define TDA9840_SET_MUTE 0x00
|
||||
#define TDA9840_SET_MONO 0x10
|
||||
#define TDA9840_SET_STEREO 0x2a
|
||||
#define TDA9840_SET_LANG1 0x12
|
||||
#define TDA9840_SET_LANG2 0x1e
|
||||
#define TDA9840_SET_BOTH 0x1a
|
||||
#define TDA9840_SET_BOTH_R 0x16
|
||||
#define TDA9840_SET_EXTERNAL 0x7a
|
||||
|
||||
/* values may range between +2.5 and -2.0;
|
||||
the value has to be multiplied with 10 */
|
||||
#define TDA9840_LEVEL_ADJUST _IOW('v',3,int)
|
||||
@ -29,7 +11,4 @@
|
||||
the value has to be multiplied with 10 */
|
||||
#define TDA9840_STEREO_ADJUST _IOW('v',4,int)
|
||||
|
||||
/* currently not implemented */
|
||||
#define TDA9840_TEST _IOW('v',5,int)
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user