Skip to content

Commit

Permalink
[PATCH] tuner-core.c improvments and Ymec Tvision TVF8533MF support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mauro Carvalho Chehab authored and Linus Torvalds committed Jun 24, 2005
1 parent 55f51ef commit 391cd72
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 4 deletions.
13 changes: 13 additions & 0 deletions drivers/media/video/Kconfig
Expand Up @@ -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
Expand Down
79 changes: 76 additions & 3 deletions drivers/media/video/tuner-core.c
@@ -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
Expand All @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -249,25 +298,41 @@ 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)
{
struct tuner *t = i2c_get_clientdata(client);
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");
Expand Down Expand Up @@ -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))
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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);
Expand Down
28 changes: 27 additions & 1 deletion drivers/media/video/tuner-simple.c
@@ -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.
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions include/media/tuner.h
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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;
Expand Down

0 comments on commit 391cd72

Please sign in to comment.