aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tuner-core.c
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/video/tuner-core.c
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/video/tuner-core.c')
-rw-r--r--drivers/media/video/tuner-core.c79
1 files changed, 76 insertions, 3 deletions
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);