[PATCH] tuner-core.c improvments and Ymec Tvision TVF8533MF support

tuner-core.c, tuner.h:

- tuner-core changed to support multiple I2C devices used on some
  adapters;

- Kconfig now has an option (CONFIG_TUNER_MULTI_I2C) to enable this new
  behavor;

- By default, even enabling CONFIG_TUNER_MULTI_I2C, tuner-core emulates
  the old behavor, using first I2C device for both FM and TV;

- There is a new i2c command (TUNER_SET_ADDR) to allow tuner clients to
  select I2C address for FM or TV tuner;

- Tuner I2C dettach now generates a warning on syslog if failed.

tuner-simple.c:

- TVision TVF-8531MF and TVF-5533 MF tuner included.  It uses, by
  default, I2C on 0xC2 address for TV and on 0xC0 for Radio.  Both TV and
  FM Radio mode are working.

Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Mauro Carvalho Chehab 2005-06-23 22:02:43 -07:00 committed by Linus Torvalds
parent 55f51efdb6
commit 391cd727ea
4 changed files with 126 additions and 4 deletions

View file

@ -7,6 +7,19 @@ menu "Video For Linux"
comment "Video Adapters"
config CONFIG_TUNER_MULTI_I2C
bool "Enable support for multiple I2C devices on Video Adapters (EXPERIMENTAL)"
depends on VIDEO_DEV && EXPERIMENTAL
---help---
Some video adapters have more than one tuner inside. This patch
enables support for using more than one tuner. This is required
for some cards to allow tunning both video and radio.
It also improves I2C autodetection for these cards.
Only few tuners currently is supporting this. More to come.
It is safe to say 'Y' here even if your card has only one I2C tuner.
config VIDEO_BT848
tristate "BT848 Video For Linux"
depends on VIDEO_DEV && PCI && I2C

View file

@ -1,5 +1,5 @@
/*
* $Id: tuner-core.c,v 1.5 2005/02/15 15:59:35 kraxel Exp $
* $Id: tuner-core.c,v 1.7 2005/05/30 02:02:47 mchehab Exp $
*
* i2c tv tuner chip device driver
* core core, i.e. kernel interfaces, registering and so on
@ -23,6 +23,11 @@
#include <media/tuner.h>
#include <media/audiochip.h>
/*
* comment line bellow to return to old behavor, where only one I2C device is supported
*/
/* #define CONFIG_TUNER_MULTI_I2C */
#define UNSET (-1U)
/* standard i2c insmod options */
@ -53,6 +58,9 @@ MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");
static int this_adap;
#ifdef CONFIG_TUNER_MULTI_I2C
static unsigned short tv_tuner, radio_tuner;
#endif
static struct i2c_driver driver;
static struct i2c_client client_template;
@ -125,6 +133,28 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
t->freq = freq;
}
#ifdef CONFIG_TUNER_MULTI_I2C
static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr)
{
struct tuner *t = i2c_get_clientdata(c);
switch (tun_addr->type) {
case V4L2_TUNER_RADIO:
radio_tuner=tun_addr->addr;
tuner_dbg("radio tuner set to I2C address 0x%02x\n",radio_tuner<<1);
break;
default:
tv_tuner=tun_addr->addr;
tuner_dbg("TV tuner set to I2C address 0x%02x\n",tv_tuner<<1);
break;
}
}
#else
#define set_addr(c,tun_addr) \
tuner_warn("It is recommended to enable CONFIG_TUNER_MULTI_I2C for this card.\n");
#endif
static void set_type(struct i2c_client *c, unsigned int type)
{
struct tuner *t = i2c_get_clientdata(c);
@ -197,8 +227,16 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct tuner *t;
#ifndef CONFIG_TUNER_MULTI_I2C
if (this_adap > 0)
return -1;
#else
/* by default, first I2C card is both tv and radio tuner */
if (this_adap == 0) {
tv_tuner = addr;
radio_tuner = addr;
}
#endif
this_adap++;
client_template.adapter = adap;
@ -228,6 +266,11 @@ static int tuner_probe(struct i2c_adapter *adap)
}
this_adap = 0;
#ifdef CONFIG_TUNER_MULTI_I2C
tv_tuner = 0;
radio_tuner = 0;
#endif
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tuner_attach);
return 0;
@ -236,8 +279,14 @@ static int tuner_probe(struct i2c_adapter *adap)
static int tuner_detach(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
int err;
err=i2c_detach_client(&t->i2c);
if (err) {
tuner_warn ("Client deregistration failed, client not detached.\n");
return err;
}
i2c_detach_client(&t->i2c);
kfree(t);
return 0;
}
@ -249,6 +298,17 @@ static int tuner_detach(struct i2c_client *client)
tuner_info("ignore v4l1 call\n"); \
return 0; }
#ifdef CONFIG_TUNER_MULTI_I2C
#define CHECK_ADDR(tp,cmd) if (client->addr!=tp) { \
tuner_info ("Cmd %s to addr 0x%02x rejected.\n",cmd,client->addr<<1); \
return 0; }
#define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \
CHECK_ADDR(radio_tuner,cmd) } else { CHECK_ADDR(tv_tuner,cmd); }
#else
#define CHECK_ADDR(tp,cmd)
#define CHECK_MODE(cmd)
#endif
static int
tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
@ -256,18 +316,23 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
unsigned int *iarg = (int*)arg;
switch (cmd) {
/* --- configuration --- */
case TUNER_SET_TYPE:
set_type(client,*iarg);
break;
case TUNER_SET_ADDR:
set_addr(client,(struct tuner_addr *)arg);
break;
case AUDC_SET_RADIO:
CHECK_ADDR(radio_tuner,"AUDC_SET_RADIO");
if (V4L2_TUNER_RADIO != t->mode) {
set_tv_freq(client,400 * 16);
t->mode = V4L2_TUNER_RADIO;
}
break;
case AUDC_CONFIG_PINNACLE:
CHECK_ADDR(tv_tuner,"AUDC_CONFIG_PINNACLE");
switch (*iarg) {
case 2:
tuner_dbg("pinnacle pal\n");
@ -295,6 +360,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
};
struct video_channel *vc = arg;
CHECK_ADDR(tv_tuner,"VIDIOCSCHAN");
CHECK_V4L2;
t->mode = V4L2_TUNER_ANALOG_TV;
if (vc->norm < ARRAY_SIZE(map))
@ -308,6 +374,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
unsigned long *v = arg;
CHECK_MODE("VIDIOCSFREQ");
CHECK_V4L2;
set_freq(client,*v);
return 0;
@ -316,6 +383,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_tuner *vt = arg;
CHECK_ADDR(radio_tuner,"VIDIOCGTUNER:");
CHECK_V4L2;
if (V4L2_TUNER_RADIO == t->mode && t->has_signal)
vt->signal = t->has_signal(client);
@ -325,6 +393,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_audio *va = arg;
CHECK_ADDR(radio_tuner,"VIDIOCGAUDIO");
CHECK_V4L2;
if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
va->mode = t->is_stereo(client)
@ -337,6 +406,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
v4l2_std_id *id = arg;
CHECK_ADDR(tv_tuner,"VIDIOC_S_STD");
SWITCH_V4L2;
t->mode = V4L2_TUNER_ANALOG_TV;
t->std = *id;
@ -349,6 +419,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_frequency *f = arg;
CHECK_MODE("VIDIOC_S_FREQUENCY");
SWITCH_V4L2;
if (V4L2_TUNER_RADIO == f->type &&
V4L2_TUNER_RADIO != t->mode)
@ -361,6 +432,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_frequency *f = arg;
CHECK_MODE("VIDIOC_G_FREQUENCY");
SWITCH_V4L2;
f->type = t->mode;
f->frequency = t->freq;
@ -370,6 +442,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tuner = arg;
CHECK_MODE("VIDIOC_G_TUNER");
SWITCH_V4L2;
if (V4L2_TUNER_RADIO == t->mode && t->has_signal)
tuner->signal = t->has_signal(client);

View file

@ -1,5 +1,5 @@
/*
* $Id: tuner-simple.c,v 1.10 2005/03/08 08:38:00 kraxel Exp $
* $Id: tuner-simple.c,v 1.14 2005/05/30 02:02:47 mchehab Exp $
*
* i2c tv tuner chip device driver
* controls all those simple 4-control-bytes style tuners.
@ -212,6 +212,11 @@ static struct tunertype tuners[] = {
{ "Philips FQ1236A MK4", Philips, NTSC,
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
/* Should work for TVF8531MF, TVF8831MF, TVF8731MF */
{ "Ymec TVision TVF-8531MF", Philips, NTSC,
16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
{ "Ymec TVision TVF-5533MF", Philips, NTSC,
16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
@ -424,6 +429,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = tun->config;
switch (t->type) {
case TUNER_YMEC_TVF_5533MF:
/*These values are empirically determinated */
div = (freq*122)/16 - 20;
buffer[2] = 0x88; /* could be also 0x80 */
buffer[3] = 0x19; /* could be also 0x10, 0x18, 0x99 */
break;
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
buffer[3] = 0x19;
@ -458,6 +470,20 @@ int default_tuner_init(struct i2c_client *c)
t->type, tuners[t->type].name);
strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
switch (t->type) {
case TUNER_YMEC_TVF_5533MF:
{
struct tuner_addr tun_addr = { V4L2_TUNER_ANALOG_TV, 0xc2>>1 };
if (c->driver->command) {
c->driver->command(c, TUNER_SET_ADDR, &tun_addr);
} else {
tuner_warn("Couldn't set TV tuner I2C address to 0x%02x\n",tun_addr.addr<<1);
}
break;
}
}
t->tv_freq = default_set_tv_freq;
t->radio_freq = default_set_radio_freq;
t->has_signal = tuner_signal;

View file

@ -98,6 +98,9 @@
#define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */
#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */
#define TUNER_YMEC_TVF_8531MF 58
#define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */
#define NOTUNER 0
#define PAL 1 /* PAL_BG */
#define PAL_I 2
@ -121,8 +124,10 @@
#define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */
#define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */
#define TUNER_SET_ADDR _IOW('T',3,int) /* Chooses tuner I2C address */
#define TDA9887_SET_CONFIG _IOW('t',5,int)
/* tv card specific */
# define TDA9887_PRESENT (1<<0)
# define TDA9887_PORT1_INACTIVE (1<<1)
@ -143,6 +148,11 @@
#define I2C_ADDR_TDA8290 0x4b
#define I2C_ADDR_TDA8275 0x61
struct tuner_addr {
enum v4l2_tuner_type type;
unsigned short addr;
};
struct tuner {
/* device */
struct i2c_client i2c;