aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@brturbo.com.br>2005-06-24 01:02:43 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:05:31 -0400
commit391cd727eac2e10be7685efd739a3ea9de87393c (patch)
tree564ac5faefc87d6a8806d56a82d22a0404da0fdc /drivers/media
parent55f51efdb696ff6e9d2056377d05268a97f3d4e4 (diff)
[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>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/Kconfig13
-rw-r--r--drivers/media/video/tuner-core.c79
-rw-r--r--drivers/media/video/tuner-simple.c28
3 files changed, 116 insertions, 4 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6c05fddb69ab..8c349706f850 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -7,6 +7,19 @@ menu "Video For Linux"
7 7
8comment "Video Adapters" 8comment "Video Adapters"
9 9
10config CONFIG_TUNER_MULTI_I2C
11 bool "Enable support for multiple I2C devices on Video Adapters (EXPERIMENTAL)"
12 depends on VIDEO_DEV && EXPERIMENTAL
13 ---help---
14 Some video adapters have more than one tuner inside. This patch
15 enables support for using more than one tuner. This is required
16 for some cards to allow tunning both video and radio.
17 It also improves I2C autodetection for these cards.
18
19 Only few tuners currently is supporting this. More to come.
20
21 It is safe to say 'Y' here even if your card has only one I2C tuner.
22
10config VIDEO_BT848 23config VIDEO_BT848
11 tristate "BT848 Video For Linux" 24 tristate "BT848 Video For Linux"
12 depends on VIDEO_DEV && PCI && I2C 25 depends on VIDEO_DEV && PCI && I2C
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 81882ddab859..71423ae3b4dd 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * $Id: tuner-core.c,v 1.5 2005/02/15 15:59:35 kraxel Exp $ 2 * $Id: tuner-core.c,v 1.7 2005/05/30 02:02:47 mchehab Exp $
3 * 3 *
4 * i2c tv tuner chip device driver 4 * i2c tv tuner chip device driver
5 * core core, i.e. kernel interfaces, registering and so on 5 * core core, i.e. kernel interfaces, registering and so on
@@ -23,6 +23,11 @@
23#include <media/tuner.h> 23#include <media/tuner.h>
24#include <media/audiochip.h> 24#include <media/audiochip.h>
25 25
26/*
27 * comment line bellow to return to old behavor, where only one I2C device is supported
28 */
29/* #define CONFIG_TUNER_MULTI_I2C */
30
26#define UNSET (-1U) 31#define UNSET (-1U)
27 32
28/* standard i2c insmod options */ 33/* standard i2c insmod options */
@@ -53,6 +58,9 @@ MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
53MODULE_LICENSE("GPL"); 58MODULE_LICENSE("GPL");
54 59
55static int this_adap; 60static int this_adap;
61#ifdef CONFIG_TUNER_MULTI_I2C
62static unsigned short tv_tuner, radio_tuner;
63#endif
56 64
57static struct i2c_driver driver; 65static struct i2c_driver driver;
58static struct i2c_client client_template; 66static struct i2c_client client_template;
@@ -125,6 +133,28 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
125 t->freq = freq; 133 t->freq = freq;
126} 134}
127 135
136#ifdef CONFIG_TUNER_MULTI_I2C
137static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr)
138{
139 struct tuner *t = i2c_get_clientdata(c);
140
141 switch (tun_addr->type) {
142 case V4L2_TUNER_RADIO:
143 radio_tuner=tun_addr->addr;
144 tuner_dbg("radio tuner set to I2C address 0x%02x\n",radio_tuner<<1);
145
146 break;
147 default:
148 tv_tuner=tun_addr->addr;
149 tuner_dbg("TV tuner set to I2C address 0x%02x\n",tv_tuner<<1);
150 break;
151 }
152}
153#else
154#define set_addr(c,tun_addr) \
155 tuner_warn("It is recommended to enable CONFIG_TUNER_MULTI_I2C for this card.\n");
156#endif
157
128static void set_type(struct i2c_client *c, unsigned int type) 158static void set_type(struct i2c_client *c, unsigned int type)
129{ 159{
130 struct tuner *t = i2c_get_clientdata(c); 160 struct tuner *t = i2c_get_clientdata(c);
@@ -197,8 +227,16 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
197{ 227{
198 struct tuner *t; 228 struct tuner *t;
199 229
230#ifndef CONFIG_TUNER_MULTI_I2C
200 if (this_adap > 0) 231 if (this_adap > 0)
201 return -1; 232 return -1;
233#else
234 /* by default, first I2C card is both tv and radio tuner */
235 if (this_adap == 0) {
236 tv_tuner = addr;
237 radio_tuner = addr;
238 }
239#endif
202 this_adap++; 240 this_adap++;
203 241
204 client_template.adapter = adap; 242 client_template.adapter = adap;
@@ -228,6 +266,11 @@ static int tuner_probe(struct i2c_adapter *adap)
228 } 266 }
229 this_adap = 0; 267 this_adap = 0;
230 268
269#ifdef CONFIG_TUNER_MULTI_I2C
270 tv_tuner = 0;
271 radio_tuner = 0;
272#endif
273
231 if (adap->class & I2C_CLASS_TV_ANALOG) 274 if (adap->class & I2C_CLASS_TV_ANALOG)
232 return i2c_probe(adap, &addr_data, tuner_attach); 275 return i2c_probe(adap, &addr_data, tuner_attach);
233 return 0; 276 return 0;
@@ -236,8 +279,14 @@ static int tuner_probe(struct i2c_adapter *adap)
236static int tuner_detach(struct i2c_client *client) 279static int tuner_detach(struct i2c_client *client)
237{ 280{
238 struct tuner *t = i2c_get_clientdata(client); 281 struct tuner *t = i2c_get_clientdata(client);
282 int err;
283
284 err=i2c_detach_client(&t->i2c);
285 if (err) {
286 tuner_warn ("Client deregistration failed, client not detached.\n");
287 return err;
288 }
239 289
240 i2c_detach_client(&t->i2c);
241 kfree(t); 290 kfree(t);
242 return 0; 291 return 0;
243} 292}
@@ -249,6 +298,17 @@ static int tuner_detach(struct i2c_client *client)
249 tuner_info("ignore v4l1 call\n"); \ 298 tuner_info("ignore v4l1 call\n"); \
250 return 0; } 299 return 0; }
251 300
301#ifdef CONFIG_TUNER_MULTI_I2C
302#define CHECK_ADDR(tp,cmd) if (client->addr!=tp) { \
303 tuner_info ("Cmd %s to addr 0x%02x rejected.\n",cmd,client->addr<<1); \
304 return 0; }
305#define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \
306 CHECK_ADDR(radio_tuner,cmd) } else { CHECK_ADDR(tv_tuner,cmd); }
307#else
308#define CHECK_ADDR(tp,cmd)
309#define CHECK_MODE(cmd)
310#endif
311
252static int 312static int
253tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) 313tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
254{ 314{
@@ -256,18 +316,23 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
256 unsigned int *iarg = (int*)arg; 316 unsigned int *iarg = (int*)arg;
257 317
258 switch (cmd) { 318 switch (cmd) {
259
260 /* --- configuration --- */ 319 /* --- configuration --- */
261 case TUNER_SET_TYPE: 320 case TUNER_SET_TYPE:
262 set_type(client,*iarg); 321 set_type(client,*iarg);
263 break; 322 break;
323 case TUNER_SET_ADDR:
324 set_addr(client,(struct tuner_addr *)arg);
325 break;
264 case AUDC_SET_RADIO: 326 case AUDC_SET_RADIO:
327 CHECK_ADDR(radio_tuner,"AUDC_SET_RADIO");
328
265 if (V4L2_TUNER_RADIO != t->mode) { 329 if (V4L2_TUNER_RADIO != t->mode) {
266 set_tv_freq(client,400 * 16); 330 set_tv_freq(client,400 * 16);
267 t->mode = V4L2_TUNER_RADIO; 331 t->mode = V4L2_TUNER_RADIO;
268 } 332 }
269 break; 333 break;
270 case AUDC_CONFIG_PINNACLE: 334 case AUDC_CONFIG_PINNACLE:
335 CHECK_ADDR(tv_tuner,"AUDC_CONFIG_PINNACLE");
271 switch (*iarg) { 336 switch (*iarg) {
272 case 2: 337 case 2:
273 tuner_dbg("pinnacle pal\n"); 338 tuner_dbg("pinnacle pal\n");
@@ -295,6 +360,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
295 }; 360 };
296 struct video_channel *vc = arg; 361 struct video_channel *vc = arg;
297 362
363 CHECK_ADDR(tv_tuner,"VIDIOCSCHAN");
298 CHECK_V4L2; 364 CHECK_V4L2;
299 t->mode = V4L2_TUNER_ANALOG_TV; 365 t->mode = V4L2_TUNER_ANALOG_TV;
300 if (vc->norm < ARRAY_SIZE(map)) 366 if (vc->norm < ARRAY_SIZE(map))
@@ -308,6 +374,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
308 { 374 {
309 unsigned long *v = arg; 375 unsigned long *v = arg;
310 376
377 CHECK_MODE("VIDIOCSFREQ");
311 CHECK_V4L2; 378 CHECK_V4L2;
312 set_freq(client,*v); 379 set_freq(client,*v);
313 return 0; 380 return 0;
@@ -316,6 +383,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
316 { 383 {
317 struct video_tuner *vt = arg; 384 struct video_tuner *vt = arg;
318 385
386 CHECK_ADDR(radio_tuner,"VIDIOCGTUNER:");
319 CHECK_V4L2; 387 CHECK_V4L2;
320 if (V4L2_TUNER_RADIO == t->mode && t->has_signal) 388 if (V4L2_TUNER_RADIO == t->mode && t->has_signal)
321 vt->signal = t->has_signal(client); 389 vt->signal = t->has_signal(client);
@@ -325,6 +393,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
325 { 393 {
326 struct video_audio *va = arg; 394 struct video_audio *va = arg;
327 395
396 CHECK_ADDR(radio_tuner,"VIDIOCGAUDIO");
328 CHECK_V4L2; 397 CHECK_V4L2;
329 if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) 398 if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
330 va->mode = t->is_stereo(client) 399 va->mode = t->is_stereo(client)
@@ -337,6 +406,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
337 { 406 {
338 v4l2_std_id *id = arg; 407 v4l2_std_id *id = arg;
339 408
409 CHECK_ADDR(tv_tuner,"VIDIOC_S_STD");
340 SWITCH_V4L2; 410 SWITCH_V4L2;
341 t->mode = V4L2_TUNER_ANALOG_TV; 411 t->mode = V4L2_TUNER_ANALOG_TV;
342 t->std = *id; 412 t->std = *id;
@@ -349,6 +419,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
349 { 419 {
350 struct v4l2_frequency *f = arg; 420 struct v4l2_frequency *f = arg;
351 421
422 CHECK_MODE("VIDIOC_S_FREQUENCY");
352 SWITCH_V4L2; 423 SWITCH_V4L2;
353 if (V4L2_TUNER_RADIO == f->type && 424 if (V4L2_TUNER_RADIO == f->type &&
354 V4L2_TUNER_RADIO != t->mode) 425 V4L2_TUNER_RADIO != t->mode)
@@ -361,6 +432,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
361 { 432 {
362 struct v4l2_frequency *f = arg; 433 struct v4l2_frequency *f = arg;
363 434
435 CHECK_MODE("VIDIOC_G_FREQUENCY");
364 SWITCH_V4L2; 436 SWITCH_V4L2;
365 f->type = t->mode; 437 f->type = t->mode;
366 f->frequency = t->freq; 438 f->frequency = t->freq;
@@ -370,6 +442,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
370 { 442 {
371 struct v4l2_tuner *tuner = arg; 443 struct v4l2_tuner *tuner = arg;
372 444
445 CHECK_MODE("VIDIOC_G_TUNER");
373 SWITCH_V4L2; 446 SWITCH_V4L2;
374 if (V4L2_TUNER_RADIO == t->mode && t->has_signal) 447 if (V4L2_TUNER_RADIO == t->mode && t->has_signal)
375 tuner->signal = t->has_signal(client); 448 tuner->signal = t->has_signal(client);
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 48c6ceff1dc2..f7305c8d53de 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * $Id: tuner-simple.c,v 1.10 2005/03/08 08:38:00 kraxel Exp $ 2 * $Id: tuner-simple.c,v 1.14 2005/05/30 02:02:47 mchehab Exp $
3 * 3 *
4 * i2c tv tuner chip device driver 4 * i2c tv tuner chip device driver
5 * controls all those simple 4-control-bytes style tuners. 5 * controls all those simple 4-control-bytes style tuners.
@@ -212,6 +212,11 @@ static struct tunertype tuners[] = {
212 { "Philips FQ1236A MK4", Philips, NTSC, 212 { "Philips FQ1236A MK4", Philips, NTSC,
213 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, 213 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
214 214
215 /* Should work for TVF8531MF, TVF8831MF, TVF8731MF */
216 { "Ymec TVision TVF-8531MF", Philips, NTSC,
217 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
218 { "Ymec TVision TVF-5533MF", Philips, NTSC,
219 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
215}; 220};
216unsigned const int tuner_count = ARRAY_SIZE(tuners); 221unsigned const int tuner_count = ARRAY_SIZE(tuners);
217 222
@@ -424,6 +429,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
424 buffer[2] = tun->config; 429 buffer[2] = tun->config;
425 430
426 switch (t->type) { 431 switch (t->type) {
432 case TUNER_YMEC_TVF_5533MF:
433
434 /*These values are empirically determinated */
435 div = (freq*122)/16 - 20;
436 buffer[2] = 0x88; /* could be also 0x80 */
437 buffer[3] = 0x19; /* could be also 0x10, 0x18, 0x99 */
438 break;
427 case TUNER_PHILIPS_FM1216ME_MK3: 439 case TUNER_PHILIPS_FM1216ME_MK3:
428 case TUNER_PHILIPS_FM1236_MK3: 440 case TUNER_PHILIPS_FM1236_MK3:
429 buffer[3] = 0x19; 441 buffer[3] = 0x19;
@@ -458,6 +470,20 @@ int default_tuner_init(struct i2c_client *c)
458 t->type, tuners[t->type].name); 470 t->type, tuners[t->type].name);
459 strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); 471 strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
460 472
473 switch (t->type) {
474 case TUNER_YMEC_TVF_5533MF:
475 {
476 struct tuner_addr tun_addr = { V4L2_TUNER_ANALOG_TV, 0xc2>>1 };
477
478 if (c->driver->command) {
479 c->driver->command(c, TUNER_SET_ADDR, &tun_addr);
480 } else {
481 tuner_warn("Couldn't set TV tuner I2C address to 0x%02x\n",tun_addr.addr<<1);
482 }
483 break;
484 }
485 }
486
461 t->tv_freq = default_set_tv_freq; 487 t->tv_freq = default_set_tv_freq;
462 t->radio_freq = default_set_radio_freq; 488 t->radio_freq = default_set_radio_freq;
463 t->has_signal = tuner_signal; 489 t->has_signal = tuner_signal;