summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux/drivers/media/video/tuner-core.c80
-rw-r--r--linux/drivers/media/video/tuner-simple.c28
-rw-r--r--linux/include/media/tuner.h7
-rw-r--r--v4l/ChangeLog15
4 files changed, 115 insertions, 15 deletions
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 4633c0d6a..b330eba5a 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -1,5 +1,5 @@
/*
- * $Id: tuner-core.c,v 1.6 2005/05/22 19:23:39 nsh 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
@@ -24,6 +24,11 @@
#include <media/audiochip.h>
#include "compat.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 */
@@ -62,6 +67,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;
@@ -134,6 +142,27 @@ 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)
+#endif
+
static void set_type(struct i2c_client *c, unsigned int type)
{
struct tuner *t = i2c_get_clientdata(c);
@@ -206,8 +235,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;
@@ -238,6 +275,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;
@@ -246,8 +288,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;
- i2c_detach_client(&t->i2c);
+ err=i2c_detach_client(&t->i2c);
+ if (err) {
+ tuner_warn ("Client deregistration failed, client not detached.\n");
+ return err;
+ }
+
kfree(t);
return 0;
}
@@ -258,7 +306,18 @@ static int tuner_detach(struct i2c_client *client)
#define CHECK_V4L2 if (t->using_v4l2) { if (tuner_debug) \
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)
{
@@ -266,18 +325,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");
@@ -305,6 +369,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))
@@ -318,6 +383,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;
@@ -326,6 +392,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);
@@ -335,6 +402,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)
@@ -347,6 +415,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;
@@ -359,6 +428,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)
@@ -371,6 +441,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;
@@ -380,6 +451,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);
diff --git a/linux/drivers/media/video/tuner-simple.c b/linux/drivers/media/video/tuner-simple.c
index d100901e0..4998fcc6f 100644
--- a/linux/drivers/media/video/tuner-simple.c
+++ b/linux/drivers/media/video/tuner-simple.c
@@ -1,5 +1,5 @@
/*
- * $Id: tuner-simple.c,v 1.13 2005/05/29 10:22:08 nsh 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.
@@ -426,7 +426,6 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
unsigned char buffer[4];
unsigned div;
int rc;
- int old_addr=c->addr;
tun=&tuners[t->type];
div = freq + (int)(16*10.7);
@@ -434,12 +433,11 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
switch (t->type) {
case TUNER_YMEC_TVF_5533MF:
- c->addr=0x60; /* Forces usage of I2C FM Tuner which is different from TV */
/*These values are empirically determinated */
- div = (int)(freq*7.625)- 20;
- buffer[2] = 0x80; /* could be also 0x88 */
- buffer[3] = 0x10; /* could be also 0x18 or 0x19 */
+ 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:
@@ -465,8 +463,6 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
-
- c->addr=old_addr;
}
int default_tuner_init(struct i2c_client *c)
@@ -476,7 +472,21 @@ int default_tuner_init(struct i2c_client *c)
tuner_info("type set to %d (%s)\n",
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;
diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h
index 9a7584e10..f9dd563ec 100644
--- a/linux/include/media/tuner.h
+++ b/linux/include/media/tuner.h
@@ -125,8 +125,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)
@@ -147,6 +149,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;
diff --git a/v4l/ChangeLog b/v4l/ChangeLog
index 229a13606..698eb093f 100644
--- a/v4l/ChangeLog
+++ b/v4l/ChangeLog
@@ -1,3 +1,14 @@
+2005-05-30 02:42 mchehab
+ * tuner-core.c, tuner-simple.c, tuner.h:
+
+ - tuner-core changed to support multiple I2C devices
+ - has to define CONFIG_TUNER_MULTI_I2C to allow new behavor
+ - By default, it uses first I2C device for FM and TV
+ - New client control TUNER_SET_ADDR changes I2C addr for FM or TV
+ - TVision 5533 MF now uses I2C on 0xC2 for TV and on 0xC0 for radio
+ - TVision 5533 MF div now uses only integer arithmetics
+ - tuner I2C dettach now generates warn log if failed
+
2005-05-29 13:38 nshmyrev
* cx88-cards.c, cx88.h:
@@ -11,7 +22,7 @@
- Added initial support for Radio tuner for Ymec TVF xxx3 MF
- Buffer values determinated empirically.
- - There's a hack for selecting I2C bus for Radio (0xC0>>2)
+ - There's a hack for selecting I2C bus for Radio (0xC0>>1)
2005-05-25 04:00 nshmyrev
@@ -1066,7 +1077,7 @@
saa7134-reg.h, saa7134-ts.c, saa7134-tvaudio.c, saa7134-vbi.c,
saa7134-video.c, saa7134.h, video-buf.c, video-buf.h:
- - added a bunch of $Id: ChangeLog,v 1.9 2005/05/29 17:34:51 mchehab Exp $ tags.
+ - added a bunch of $Id: ChangeLog,v 1.10 2005/05/30 02:02:47 mchehab Exp $ tags.
2004-09-15 17:35 kraxel