tuner-core.c 25.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 *
 * i2c tv tuner chip device driver
 * core core, i.e. kernel interfaces, registering and so on
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/init.h>
18
#include <linux/videodev.h>
L
Linus Torvalds 已提交
19
#include <media/tuner.h>
20
#include <media/v4l2-common.h>
21
#include "tuner-driver.h"
L
Linus Torvalds 已提交
22 23 24 25 26

#define UNSET (-1U)

/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
27
#ifdef CONFIG_TUNER_TEA5761
28 29
	0x10,
#endif
30
	0x42, 0x43, 0x4a, 0x4b,			/* tda8290 */
31 32
	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
L
Linus Torvalds 已提交
33 34
	I2C_CLIENT_END
};
M
Mauro Carvalho Chehab 已提交
35

L
Linus Torvalds 已提交
36 37 38
I2C_CLIENT_INSMOD;

/* insmod options used at init time => read/only */
M
Mauro Carvalho Chehab 已提交
39
static unsigned int addr = 0;
40
static unsigned int no_autodetect = 0;
41 42
static unsigned int show_i2c = 0;

L
Linus Torvalds 已提交
43
/* insmod options used at runtime => read/write */
44
int tuner_debug = 0;
L
Linus Torvalds 已提交
45

M
Mauro Carvalho Chehab 已提交
46
static unsigned int tv_range[2] = { 44, 958 };
L
Linus Torvalds 已提交
47 48
static unsigned int radio_range[2] = { 65, 108 };

49 50 51 52
static char pal[] = "--";
static char secam[] = "--";
static char ntsc[] = "-";

53

54 55 56
module_param(addr, int, 0444);
module_param(no_autodetect, int, 0444);
module_param(show_i2c, int, 0444);
57
module_param_named(debug,tuner_debug, int, 0644);
58 59 60
module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
M
Mauro Carvalho Chehab 已提交
61
module_param_array(tv_range, int, NULL, 0644);
L
Linus Torvalds 已提交
62 63 64 65 66 67 68 69 70 71 72
module_param_array(radio_range, int, NULL, 0644);

MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");

static struct i2c_driver driver;
static struct i2c_client client_template;

/* ---------------------------------------------------------------------- */

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
static void fe_set_freq(struct tuner *t, unsigned int freq)
{
	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;

	struct analog_parameters params = {
		.frequency = freq,
		.mode      = t->mode,
		.audmode   = t->audmode,
		.std       = t->std
	};

	if (NULL == fe_tuner_ops->set_analog_params) {
		tuner_warn("Tuner frontend module has no way to set freq\n");
		return;
	}
	fe_tuner_ops->set_analog_params(&t->fe, &params);
}

static void fe_release(struct tuner *t)
{
	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;

	if (fe_tuner_ops->release)
		fe_tuner_ops->release(&t->fe);
}

static void fe_standby(struct tuner *t)
{
	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;

	if (fe_tuner_ops->sleep)
		fe_tuner_ops->sleep(&t->fe);
}

107
/* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
L
Linus Torvalds 已提交
108 109 110 111 112
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
	struct tuner *t = i2c_get_clientdata(c);

	if (t->type == UNSET) {
M
Mauro Carvalho Chehab 已提交
113
		tuner_warn ("tuner type not set\n");
L
Linus Torvalds 已提交
114 115
		return;
	}
116
	if (NULL == t->ops.set_tv_freq) {
M
Mauro Carvalho Chehab 已提交
117
		tuner_warn ("Tuner has no way to set tv freq\n");
L
Linus Torvalds 已提交
118 119
		return;
	}
M
Mauro Carvalho Chehab 已提交
120 121 122 123
	if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
		tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
			   freq / 16, freq % 16 * 100 / 16, tv_range[0],
			   tv_range[1]);
124 125 126 127 128 129
		/* V4L2 spec: if the freq is not possible then the closest
		   possible value should be selected */
		if (freq < tv_range[0] * 16)
			freq = tv_range[0] * 16;
		else
			freq = tv_range[1] * 16;
L
Linus Torvalds 已提交
130
	}
131
	t->ops.set_tv_freq(t, freq);
L
Linus Torvalds 已提交
132 133 134 135 136 137 138
}

static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{
	struct tuner *t = i2c_get_clientdata(c);

	if (t->type == UNSET) {
M
Mauro Carvalho Chehab 已提交
139
		tuner_warn ("tuner type not set\n");
L
Linus Torvalds 已提交
140 141
		return;
	}
142
	if (NULL == t->ops.set_radio_freq) {
M
Mauro Carvalho Chehab 已提交
143
		tuner_warn ("tuner has no way to set radio frequency\n");
L
Linus Torvalds 已提交
144 145
		return;
	}
146
	if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
M
Mauro Carvalho Chehab 已提交
147 148 149
		tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
			   freq / 16000, freq % 16000 * 100 / 16000,
			   radio_range[0], radio_range[1]);
150 151 152 153 154 155
		/* V4L2 spec: if the freq is not possible then the closest
		   possible value should be selected */
		if (freq < radio_range[0] * 16000)
			freq = radio_range[0] * 16000;
		else
			freq = radio_range[1] * 16000;
L
Linus Torvalds 已提交
156
	}
157

158
	t->ops.set_radio_freq(t, freq);
L
Linus Torvalds 已提交
159 160 161 162 163 164 165 166 167
}

static void set_freq(struct i2c_client *c, unsigned long freq)
{
	struct tuner *t = i2c_get_clientdata(c);

	switch (t->mode) {
	case V4L2_TUNER_RADIO:
		tuner_dbg("radio freq set to %lu.%02lu\n",
M
Mauro Carvalho Chehab 已提交
168 169
			  freq / 16000, freq % 16000 * 100 / 16000);
		set_radio_freq(c, freq);
170
		t->radio_freq = freq;
L
Linus Torvalds 已提交
171 172 173 174
		break;
	case V4L2_TUNER_ANALOG_TV:
	case V4L2_TUNER_DIGITAL_TV:
		tuner_dbg("tv freq set to %lu.%02lu\n",
M
Mauro Carvalho Chehab 已提交
175
			  freq / 16, freq % 16 * 100 / 16);
L
Linus Torvalds 已提交
176
		set_tv_freq(c, freq);
177
		t->tv_freq = freq;
L
Linus Torvalds 已提交
178 179 180 181
		break;
	}
}

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
static void tuner_i2c_address_check(struct tuner *t)
{
	if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
	    ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
		return;

	tuner_warn("====================== WARNING! ======================\n");
	tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
	tuner_warn("will soon be dropped. This message indicates that your\n");
	tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
		   t->i2c.name, t->i2c.addr);
	tuner_warn("To ensure continued support for your device, please\n");
	tuner_warn("send a copy of this message, along with full dmesg\n");
	tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
	tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
	tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
		   t->i2c.adapter->name, t->i2c.addr, t->type,
		   tuners[t->type].name);
	tuner_warn("====================== WARNING! ======================\n");
}

M
Mauro Carvalho Chehab 已提交
203
static void set_type(struct i2c_client *c, unsigned int type,
204
		     unsigned int new_mode_mask, unsigned int new_config,
205
		     int (*tuner_callback) (void *dev, int command,int arg))
L
Linus Torvalds 已提交
206 207
{
	struct tuner *t = i2c_get_clientdata(c);
208
	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
209
	unsigned char buffer[4];
L
Linus Torvalds 已提交
210

M
Mauro Carvalho Chehab 已提交
211 212
	if (type == UNSET || type == TUNER_ABSENT) {
		tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
L
Linus Torvalds 已提交
213
		return;
M
Mauro Carvalho Chehab 已提交
214 215 216 217
	}

	if (type >= tuner_count) {
		tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
L
Linus Torvalds 已提交
218
		return;
M
Mauro Carvalho Chehab 已提交
219
	}
L
Linus Torvalds 已提交
220

221 222 223 224 225 226 227
	t->type = type;
	t->config = new_config;
	if (tuner_callback != NULL) {
		tuner_dbg("defining GPIO callback\n");
		t->tuner_callback = tuner_callback;
	}

M
Mauro Carvalho Chehab 已提交
228
	/* This code detects calls by card attach_inform */
L
Linus Torvalds 已提交
229
	if (NULL == t->i2c.dev.driver) {
M
Mauro Carvalho Chehab 已提交
230 231
		tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);

L
Linus Torvalds 已提交
232 233
		return;
	}
234

235
	/* discard private data, in case set_type() was previously called */
236
	if (t->ops.release)
237
		t->ops.release(t);
238 239 240 241
	else {
		kfree(t->priv);
		t->priv = NULL;
	}
242

L
Linus Torvalds 已提交
243 244
	switch (t->type) {
	case TUNER_MT2032:
245
		microtune_init(t);
L
Linus Torvalds 已提交
246 247
		break;
	case TUNER_PHILIPS_TDA8290:
248
		tda8290_init(t);
L
Linus Torvalds 已提交
249
		break;
250
	case TUNER_TEA5767:
251
		if (tea5767_tuner_init(t) == EINVAL) {
M
Mauro Carvalho Chehab 已提交
252 253 254 255 256
			t->type = TUNER_ABSENT;
			t->mode_mask = T_UNINITIALIZED;
			return;
		}
		t->mode_mask = T_RADIO;
257
		break;
258
#ifdef CONFIG_TUNER_TEA5761
259
	case TUNER_TEA5761:
260
		if (tea5761_tuner_init(t) == EINVAL) {
261 262
			t->type = TUNER_ABSENT;
			t->mode_mask = T_UNINITIALIZED;
263
			return;
264 265 266 267
		}
		t->mode_mask = T_RADIO;
		break;
#endif
268 269 270 271 272
	case TUNER_PHILIPS_FMD1216ME_MK3:
		buffer[0] = 0x0b;
		buffer[1] = 0xdc;
		buffer[2] = 0x9c;
		buffer[3] = 0x60;
M
Mauro Carvalho Chehab 已提交
273
		i2c_master_send(c, buffer, 4);
274 275 276
		mdelay(1);
		buffer[2] = 0x86;
		buffer[3] = 0x54;
M
Mauro Carvalho Chehab 已提交
277
		i2c_master_send(c, buffer, 4);
278
		default_tuner_init(t);
279
		break;
280 281 282 283 284 285
	case TUNER_PHILIPS_TD1316:
		buffer[0] = 0x0b;
		buffer[1] = 0xdc;
		buffer[2] = 0x86;
		buffer[3] = 0xa4;
		i2c_master_send(c,buffer,4);
286
		default_tuner_init(t);
287
		break;
288
	case TUNER_TDA9887:
289
		tda9887_tuner_init(t);
290
		break;
L
Linus Torvalds 已提交
291
	default:
292
		default_tuner_init(t);
L
Linus Torvalds 已提交
293 294
		break;
	}
M
Mauro Carvalho Chehab 已提交
295

296 297 298 299 300 301 302 303 304 305 306
	if (fe_tuner_ops->set_analog_params) {
		strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));

		t->ops.set_tv_freq    = fe_set_freq;
		t->ops.set_radio_freq = fe_set_freq;
		t->ops.standby        = fe_standby;
		t->ops.release        = fe_release;
	}

	tuner_info("type set to %s\n", t->i2c.name);

M
Mauro Carvalho Chehab 已提交
307 308 309
	if (t->mode_mask == T_UNINITIALIZED)
		t->mode_mask = new_mode_mask;

310
	set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
M
Mauro Carvalho Chehab 已提交
311
	tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
312
		  c->adapter->name, c->driver->driver.name, c->addr << 1, type,
M
Mauro Carvalho Chehab 已提交
313
		  t->mode_mask);
314
	tuner_i2c_address_check(t);
L
Linus Torvalds 已提交
315 316
}

M
Mauro Carvalho Chehab 已提交
317 318 319 320 321 322 323 324 325 326 327 328
/*
 * This function apply tuner config to tuner specified
 * by tun_setup structure. I addr is unset, then admin status
 * and tun addr status is more precise then current status,
 * it's applied. Otherwise status and type are applied only to
 * tuner with exactly the same addr.
*/

static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
	struct tuner *t = i2c_get_clientdata(c);

329 330
	tuner_dbg("set addr for type %i\n", t->type);

331 332 333 334
	if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
		(t->mode_mask & tun_setup->mode_mask))) ||
		(tun_setup->addr == c->addr)) {
			set_type(c, tun_setup->type, tun_setup->mode_mask,
335
				 tun_setup->config, tun_setup->tuner_callback);
M
Mauro Carvalho Chehab 已提交
336 337
	}
}
338

M
Mauro Carvalho Chehab 已提交
339
static inline int check_mode(struct tuner *t, char *cmd)
340
{
341 342 343 344 345 346 347 348 349 350 351 352 353 354
	if ((1 << t->mode & t->mode_mask) == 0) {
		return EINVAL;
	}

	switch (t->mode) {
	case V4L2_TUNER_RADIO:
		tuner_dbg("Cmd %s accepted for radio\n", cmd);
		break;
	case V4L2_TUNER_ANALOG_TV:
		tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
		break;
	case V4L2_TUNER_DIGITAL_TV:
		tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
		break;
355
	}
356
	return 0;
357 358
}

M
Mauro Carvalho Chehab 已提交
359
/* get more precise norm info from insmod option */
L
Linus Torvalds 已提交
360 361 362 363
static int tuner_fixup_std(struct tuner *t)
{
	if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
		switch (pal[0]) {
364 365 366 367
		case '6':
			tuner_dbg ("insmod fixup: PAL => PAL-60\n");
			t->std = V4L2_STD_PAL_60;
			break;
L
Linus Torvalds 已提交
368 369 370 371
		case 'b':
		case 'B':
		case 'g':
		case 'G':
M
Mauro Carvalho Chehab 已提交
372
			tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
L
Linus Torvalds 已提交
373 374 375 376
			t->std = V4L2_STD_PAL_BG;
			break;
		case 'i':
		case 'I':
M
Mauro Carvalho Chehab 已提交
377
			tuner_dbg ("insmod fixup: PAL => PAL-I\n");
L
Linus Torvalds 已提交
378 379 380 381 382 383
			t->std = V4L2_STD_PAL_I;
			break;
		case 'd':
		case 'D':
		case 'k':
		case 'K':
M
Mauro Carvalho Chehab 已提交
384
			tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
L
Linus Torvalds 已提交
385 386
			t->std = V4L2_STD_PAL_DK;
			break;
M
Mauro Carvalho Chehab 已提交
387 388 389 390 391 392 393
		case 'M':
		case 'm':
			tuner_dbg ("insmod fixup: PAL => PAL-M\n");
			t->std = V4L2_STD_PAL_M;
			break;
		case 'N':
		case 'n':
394 395 396 397 398 399 400
			if (pal[1] == 'c' || pal[1] == 'C') {
				tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
				t->std = V4L2_STD_PAL_Nc;
			} else {
				tuner_dbg ("insmod fixup: PAL => PAL-N\n");
				t->std = V4L2_STD_PAL_N;
			}
M
Mauro Carvalho Chehab 已提交
401
			break;
402 403 404 405 406 407
		case '-':
			/* default parameter, do nothing */
			break;
		default:
			tuner_warn ("pal= argument not recognised\n");
			break;
L
Linus Torvalds 已提交
408 409
		}
	}
M
Mauro Carvalho Chehab 已提交
410 411
	if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
		switch (secam[0]) {
412 413 414 415 416 417 418 419 420
		case 'b':
		case 'B':
		case 'g':
		case 'G':
		case 'h':
		case 'H':
			tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
			t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
			break;
M
Mauro Carvalho Chehab 已提交
421 422 423 424 425 426 427 428 429
		case 'd':
		case 'D':
		case 'k':
		case 'K':
			tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
			t->std = V4L2_STD_SECAM_DK;
			break;
		case 'l':
		case 'L':
430 431 432 433 434 435 436
			if ((secam[1]=='C')||(secam[1]=='c')) {
				tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
				t->std = V4L2_STD_SECAM_LC;
			} else {
				tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
				t->std = V4L2_STD_SECAM_L;
			}
M
Mauro Carvalho Chehab 已提交
437
			break;
438 439 440 441 442 443
		case '-':
			/* default parameter, do nothing */
			break;
		default:
			tuner_warn ("secam= argument not recognised\n");
			break;
M
Mauro Carvalho Chehab 已提交
444 445 446
		}
	}

447 448 449 450 451 452 453 454 455 456 457 458
	if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
		switch (ntsc[0]) {
		case 'm':
		case 'M':
			tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
			t->std = V4L2_STD_NTSC_M;
			break;
		case 'j':
		case 'J':
			tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
			t->std = V4L2_STD_NTSC_M_JP;
			break;
459 460 461 462 463
		case 'k':
		case 'K':
			tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
			t->std = V4L2_STD_NTSC_M_KR;
			break;
464 465 466 467 468 469 470 471
		case '-':
			/* default parameter, do nothing */
			break;
		default:
			tuner_info("ntsc= argument not recognised\n");
			break;
		}
	}
L
Linus Torvalds 已提交
472 473 474
	return 0;
}

475
static void tuner_status(struct tuner *t)
476 477
{
	unsigned long freq, freq_fraction;
478
	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
479 480 481 482 483 484 485 486 487
	const char *p;

	switch (t->mode) {
		case V4L2_TUNER_RADIO: 	    p = "radio"; break;
		case V4L2_TUNER_ANALOG_TV:  p = "analog TV"; break;
		case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
		default: p = "undefined"; break;
	}
	if (t->mode == V4L2_TUNER_RADIO) {
488 489
		freq = t->radio_freq / 16000;
		freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
490
	} else {
491 492
		freq = t->tv_freq / 16;
		freq_fraction = (t->tv_freq % 16) * 100 / 16;
493 494 495
	}
	tuner_info("Tuner mode:      %s\n", p);
	tuner_info("Frequency:       %lu.%02lu MHz\n", freq, freq_fraction);
496
	tuner_info("Standard:        0x%08lx\n", (unsigned long)t->std);
497 498
	if (t->mode != V4L2_TUNER_RADIO)
	       return;
499 500 501 502 503 504 505 506 507
	if (fe_tuner_ops->get_status) {
		u32 tuner_status;

		fe_tuner_ops->get_status(&t->fe, &tuner_status);
		if (tuner_status & TUNER_STATUS_LOCKED)
			tuner_info("Tuner is locked.\n");
		if (tuner_status & TUNER_STATUS_STEREO)
			tuner_info("Stereo:          yes\n");
	}
508
	if (t->ops.has_signal) {
509
		tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
510
	}
511
	if (t->ops.is_stereo) {
512
		tuner_info("Stereo:          %s\n", t->ops.is_stereo(t) ? "yes" : "no");
513 514
	}
}
515

L
Linus Torvalds 已提交
516 517
/* ---------------------------------------------------------------------- */

518
/* static vars: used only in tuner_attach and tuner_probe */
M
Mauro Carvalho Chehab 已提交
519 520 521 522 523
static unsigned default_mode_mask;

/* During client attach, set_type is called by adapter's attach_inform callback.
   set_type must then be completed by tuner_attach.
 */
L
Linus Torvalds 已提交
524 525 526 527
static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
{
	struct tuner *t;

M
Mauro Carvalho Chehab 已提交
528 529
	client_template.adapter = adap;
	client_template.addr = addr;
L
Linus Torvalds 已提交
530

P
 
Panagiotis Issaris 已提交
531
	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
M
Mauro Carvalho Chehab 已提交
532 533 534
	if (NULL == t)
		return -ENOMEM;
	memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
L
Linus Torvalds 已提交
535
	i2c_set_clientdata(&t->i2c, t);
M
Mauro Carvalho Chehab 已提交
536 537 538
	t->type = UNSET;
	t->audmode = V4L2_TUNER_MODE_STEREO;
	t->mode_mask = T_UNINITIALIZED;
539
	t->ops.tuner_status = tuner_status;
M
Mauro Carvalho Chehab 已提交
540

541 542 543 544 545 546
	if (show_i2c) {
		unsigned char buffer[16];
		int i,rc;

		memset(buffer, 0, sizeof(buffer));
		rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
547
		tuner_info("I2C RECV = ");
548 549 550 551
		for (i=0;i<rc;i++)
			printk("%02x ",buffer[i]);
		printk("\n");
	}
552 553 554 555
	/* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
	if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
		return -ENODEV;

556
	/* autodetection code based on the i2c addr */
557
	if (!no_autodetect) {
558
		switch (addr) {
559
#ifdef CONFIG_TUNER_TEA5761
560
		case 0x10:
561
			if (tea5761_autodetection(t) != EINVAL) {
562 563 564 565 566 567 568 569 570 571
				t->type = TUNER_TEA5761;
				t->mode_mask = T_RADIO;
				t->mode = T_STANDBY;
				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
				default_mode_mask &= ~T_RADIO;

				goto register_client;
			}
			break;
#endif
572 573 574
		case 0x42:
		case 0x43:
		case 0x4a:
575
		case 0x4b:
576 577
			/* If chip is not tda8290, don't register.
			   since it can be tda9887*/
578
			if (tda8290_probe(t) == 0) {
579 580 581 582 583 584 585
				tuner_dbg("chip at addr %x is a tda8290\n", addr);
			} else {
				/* Default is being tda9887 */
				t->type = TUNER_TDA9887;
				t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
				t->mode = T_STANDBY;
				goto register_client;
586
			}
587 588
			break;
		case 0x60:
589
			if (tea5767_autodetection(t) != EINVAL) {
590 591 592
				t->type = TUNER_TEA5767;
				t->mode_mask = T_RADIO;
				t->mode = T_STANDBY;
593
				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
594
				default_mode_mask &= ~T_RADIO;
595

596 597 598
				goto register_client;
			}
			break;
M
Mauro Carvalho Chehab 已提交
599 600
		}
	}
L
Linus Torvalds 已提交
601

M
Mauro Carvalho Chehab 已提交
602 603 604 605
	/* Initializes only the first adapter found */
	if (default_mode_mask != T_UNINITIALIZED) {
		tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
		t->mode_mask = default_mode_mask;
606 607
		t->tv_freq = 400 * 16; /* Sets freq to VHF High */
		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
M
Mauro Carvalho Chehab 已提交
608 609
		default_mode_mask = T_UNINITIALIZED;
	}
610

M
Mauro Carvalho Chehab 已提交
611
	/* Should be just before return */
612 613
register_client:
	tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
M
Mauro Carvalho Chehab 已提交
614
	i2c_attach_client (&t->i2c);
615
	set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback);
L
Linus Torvalds 已提交
616 617 618 619 620 621
	return 0;
}

static int tuner_probe(struct i2c_adapter *adap)
{
	if (0 != addr) {
622 623
		normal_i2c[0] = addr;
		normal_i2c[1] = I2C_CLIENT_END;
L
Linus Torvalds 已提交
624 625
	}

M
Mauro Carvalho Chehab 已提交
626
	default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
627

L
Linus Torvalds 已提交
628 629 630 631 632 633 634 635
	if (adap->class & I2C_CLASS_TV_ANALOG)
		return i2c_probe(adap, &addr_data, tuner_attach);
	return 0;
}

static int tuner_detach(struct i2c_client *client)
{
	struct tuner *t = i2c_get_clientdata(client);
636 637
	int err;

M
Mauro Carvalho Chehab 已提交
638
	err = i2c_detach_client(&t->i2c);
639
	if (err) {
M
Mauro Carvalho Chehab 已提交
640 641
		tuner_warn
		    ("Client deregistration failed, client not detached.\n");
642 643
		return err;
	}
L
Linus Torvalds 已提交
644

645
	if (t->ops.release)
646
		t->ops.release(t);
647 648 649
	else {
		kfree(t->priv);
	}
L
Linus Torvalds 已提交
650 651 652 653
	kfree(t);
	return 0;
}

M
Mauro Carvalho Chehab 已提交
654 655 656 657 658 659 660 661 662
/*
 * Switch tuner to other mode. If tuner support both tv and radio,
 * set another frequency to some value (This is needed for some pal
 * tuners to avoid locking). Otherwise, just put second tuner in
 * standby mode.
 */

static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
{
663 664 665 666 667 668 669
	if (mode == t->mode)
		return 0;

	t->mode = mode;

	if (check_mode(t, cmd) == EINVAL) {
		t->mode = T_STANDBY;
670
		if (t->ops.standby)
671
			t->ops.standby(t);
672 673 674
		return EINVAL;
	}
	return 0;
M
Mauro Carvalho Chehab 已提交
675 676 677
}

#define switch_v4l2()	if (!t->using_v4l2) \
678 679
			    tuner_dbg("switching to v4l2\n"); \
			t->using_v4l2 = 1;
M
Mauro Carvalho Chehab 已提交
680 681 682

static inline int check_v4l2(struct tuner *t)
{
683 684 685 686
	/* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
	   TV, v4l1 for radio), until that is fixed this code is disabled.
	   Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
	   first. */
M
Mauro Carvalho Chehab 已提交
687 688
	return 0;
}
L
Linus Torvalds 已提交
689

M
Mauro Carvalho Chehab 已提交
690
static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
L
Linus Torvalds 已提交
691 692
{
	struct tuner *t = i2c_get_clientdata(client);
693
	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
L
Linus Torvalds 已提交
694

695
	if (tuner_debug>1)
696 697
		v4l_i2c_print_ioctl(&(t->i2c),cmd);

M
Mauro Carvalho Chehab 已提交
698
	switch (cmd) {
L
Linus Torvalds 已提交
699
	/* --- configuration --- */
700
	case TUNER_SET_TYPE_ADDR:
701
		tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
M
Mauro Carvalho Chehab 已提交
702 703
				((struct tuner_setup *)arg)->type,
				((struct tuner_setup *)arg)->addr,
704 705
				((struct tuner_setup *)arg)->mode_mask,
				((struct tuner_setup *)arg)->config);
M
Mauro Carvalho Chehab 已提交
706 707

		set_addr(client, (struct tuner_setup *)arg);
708
		break;
L
Linus Torvalds 已提交
709
	case AUDC_SET_RADIO:
710 711 712 713 714
		if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
				== EINVAL)
			return 0;
		if (t->radio_freq)
			set_freq(client, t->radio_freq);
L
Linus Torvalds 已提交
715
		break;
716
	case TUNER_SET_STANDBY:
717 718
		if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
			return 0;
719
		t->mode = T_STANDBY;
720
		if (t->ops.standby)
721
			t->ops.standby(t);
722
		break;
723
#ifdef CONFIG_VIDEO_V4L1
724 725 726 727 728 729 730 731
	case VIDIOCSAUDIO:
		if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
			return 0;
		if (check_v4l2(t) == EINVAL)
			return 0;

		/* Should be implemented, since bttv calls it */
		tuner_dbg("VIDIOCSAUDIO not implemented.\n");
M
Mauro Carvalho Chehab 已提交
732
		break;
L
Linus Torvalds 已提交
733
	case VIDIOCSCHAN:
M
Mauro Carvalho Chehab 已提交
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
		{
			static const v4l2_std_id map[] = {
				[VIDEO_MODE_PAL] = V4L2_STD_PAL,
				[VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
				[VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
				[4 /* bttv */ ] = V4L2_STD_PAL_M,
				[5 /* bttv */ ] = V4L2_STD_PAL_N,
				[6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
			};
			struct video_channel *vc = arg;

			if (check_v4l2(t) == EINVAL)
				return 0;

			if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
				return 0;

			if (vc->norm < ARRAY_SIZE(map))
				t->std = map[vc->norm];
			tuner_fixup_std(t);
754 755
			if (t->tv_freq)
				set_tv_freq(client, t->tv_freq);
M
Mauro Carvalho Chehab 已提交
756 757
			return 0;
		}
L
Linus Torvalds 已提交
758
	case VIDIOCSFREQ:
M
Mauro Carvalho Chehab 已提交
759 760
		{
			unsigned long *v = arg;
L
Linus Torvalds 已提交
761

M
Mauro Carvalho Chehab 已提交
762 763 764 765 766 767 768 769
			if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
				return 0;
			if (check_v4l2(t) == EINVAL)
				return 0;

			set_freq(client, *v);
			return 0;
		}
L
Linus Torvalds 已提交
770
	case VIDIOCGTUNER:
M
Mauro Carvalho Chehab 已提交
771 772 773 774 775 776 777 778 779
		{
			struct video_tuner *vt = arg;

			if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
				return 0;
			if (check_v4l2(t) == EINVAL)
				return 0;

			if (V4L2_TUNER_RADIO == t->mode) {
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
				if (fe_tuner_ops->get_status) {
					u32 tuner_status;

					fe_tuner_ops->get_status(&t->fe, &tuner_status);
						if (tuner_status & TUNER_STATUS_STEREO)
							vt->flags |= VIDEO_TUNER_STEREO_ON;
						else
							vt->flags &= ~VIDEO_TUNER_STEREO_ON;
						vt->signal = tuner_status & TUNER_STATUS_LOCKED
							? 65535 : 0;
				} else {
					if (t->ops.is_stereo) {
						if (t->ops.is_stereo(t))
							vt->flags |=
								VIDEO_TUNER_STEREO_ON;
						else
							vt->flags &=
								~VIDEO_TUNER_STEREO_ON;
					}
					if (t->ops.has_signal)
						vt->signal = t->ops.has_signal(t);
M
Mauro Carvalho Chehab 已提交
801 802
				}
				vt->flags |= VIDEO_TUNER_LOW;	/* Allow freqs at 62.5 Hz */
803

M
Mauro Carvalho Chehab 已提交
804 805
				vt->rangelow = radio_range[0] * 16000;
				vt->rangehigh = radio_range[1] * 16000;
806

M
Mauro Carvalho Chehab 已提交
807 808 809 810
			} else {
				vt->rangelow = tv_range[0] * 16;
				vt->rangehigh = tv_range[1] * 16;
			}
811

M
Mauro Carvalho Chehab 已提交
812 813
			return 0;
		}
L
Linus Torvalds 已提交
814
	case VIDIOCGAUDIO:
M
Mauro Carvalho Chehab 已提交
815 816 817 818 819 820 821 822
		{
			struct video_audio *va = arg;

			if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
				return 0;
			if (check_v4l2(t) == EINVAL)
				return 0;

823 824 825 826 827 828 829 830 831 832 833
			if (V4L2_TUNER_RADIO == t->mode) {
				if (fe_tuner_ops->get_status) {
					u32 tuner_status;

					fe_tuner_ops->get_status(&t->fe, &tuner_status);
					va->mode = (tuner_status & TUNER_STATUS_STEREO)
					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
				} else if (t->ops.is_stereo)
					va->mode = t->ops.is_stereo(t)
					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
			}
M
Mauro Carvalho Chehab 已提交
834 835
			return 0;
		}
836 837 838 839
#endif
	case TDA9887_SET_CONFIG:
		if (t->type == TUNER_TDA9887) {
			int *i = arg;
L
Linus Torvalds 已提交
840

841 842 843 844 845 846 847
			t->tda9887_config = *i;
			set_freq(client, t->tv_freq);
		}
		break;
	/* --- v4l ioctls --- */
	/* take care: bttv does userspace copying, we'll get a
	   kernel pointer here... */
L
Linus Torvalds 已提交
848
	case VIDIOC_S_STD:
M
Mauro Carvalho Chehab 已提交
849 850
		{
			v4l2_std_id *id = arg;
L
Linus Torvalds 已提交
851

M
Mauro Carvalho Chehab 已提交
852 853 854
			if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
					== EINVAL)
				return 0;
855

M
Mauro Carvalho Chehab 已提交
856 857 858 859
			switch_v4l2();

			t->std = *id;
			tuner_fixup_std(t);
860 861
			if (t->tv_freq)
				set_freq(client, t->tv_freq);
M
Mauro Carvalho Chehab 已提交
862 863
			break;
		}
L
Linus Torvalds 已提交
864
	case VIDIOC_S_FREQUENCY:
M
Mauro Carvalho Chehab 已提交
865 866 867
		{
			struct v4l2_frequency *f = arg;

868 869 870
			if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
					== EINVAL)
				return 0;
M
Mauro Carvalho Chehab 已提交
871
			switch_v4l2();
872
			set_freq(client,f->frequency);
873

M
Mauro Carvalho Chehab 已提交
874 875 876 877 878 879 880 881 882 883
			break;
		}
	case VIDIOC_G_FREQUENCY:
		{
			struct v4l2_frequency *f = arg;

			if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
				return 0;
			switch_v4l2();
			f->type = t->mode;
884 885 886 887 888 889 890 891 892
			if (fe_tuner_ops->get_frequency) {
				u32 abs_freq;

				fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
				f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
					(abs_freq * 2 + 125/2) / 125 :
					(abs_freq + 62500/2) / 62500;
				break;
			}
893 894
			f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
				t->radio_freq : t->tv_freq;
M
Mauro Carvalho Chehab 已提交
895 896
			break;
		}
L
Linus Torvalds 已提交
897
	case VIDIOC_G_TUNER:
M
Mauro Carvalho Chehab 已提交
898 899 900 901 902 903 904
		{
			struct v4l2_tuner *tuner = arg;

			if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
				return 0;
			switch_v4l2();

905
			tuner->type = t->mode;
906
			if (t->ops.get_afc)
907
				tuner->afc=t->ops.get_afc(t);
908 909
			if (t->mode == V4L2_TUNER_ANALOG_TV)
				tuner->capability |= V4L2_TUNER_CAP_NORM;
910
			if (t->mode != V4L2_TUNER_RADIO) {
M
Mauro Carvalho Chehab 已提交
911 912
				tuner->rangelow = tv_range[0] * 16;
				tuner->rangehigh = tv_range[1] * 16;
913 914 915 916 917 918
				break;
			}

			/* radio mode */
			tuner->rxsubchans =
				V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
919 920 921 922 923
			if (fe_tuner_ops->get_status) {
				u32 tuner_status;

				fe_tuner_ops->get_status(&t->fe, &tuner_status);
				tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
924
					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
925 926 927 928 929 930 931 932
				tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0;
			} else {
				if (t->ops.is_stereo) {
					tuner->rxsubchans = t->ops.is_stereo(t) ?
						V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
				}
				if (t->ops.has_signal)
					tuner->signal = t->ops.has_signal(t);
933
			}
934 935 936 937 938
			tuner->capability |=
			    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
			tuner->audmode = t->audmode;
			tuner->rangelow = radio_range[0] * 16000;
			tuner->rangehigh = radio_range[1] * 16000;
M
Mauro Carvalho Chehab 已提交
939 940 941 942 943 944 945 946 947 948 949
			break;
		}
	case VIDIOC_S_TUNER:
		{
			struct v4l2_tuner *tuner = arg;

			if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
				return 0;

			switch_v4l2();

950 951 952 953 954
			/* do nothing unless we're a radio tuner */
			if (t->mode != V4L2_TUNER_RADIO)
				break;
			t->audmode = tuner->audmode;
			set_radio_freq(client, t->radio_freq);
M
Mauro Carvalho Chehab 已提交
955
			break;
956
		}
957
	case VIDIOC_LOG_STATUS:
958
		if (t->ops.tuner_status)
959
			t->ops.tuner_status(t);
960
		break;
L
Linus Torvalds 已提交
961 962 963 964 965
	}

	return 0;
}

966
static int tuner_suspend(struct i2c_client *c, pm_message_t state)
L
Linus Torvalds 已提交
967
{
M
Mauro Carvalho Chehab 已提交
968
	struct tuner *t = i2c_get_clientdata (c);
L
Linus Torvalds 已提交
969

M
Mauro Carvalho Chehab 已提交
970
	tuner_dbg ("suspend\n");
L
Linus Torvalds 已提交
971 972 973 974
	/* FIXME: power down ??? */
	return 0;
}

975
static int tuner_resume(struct i2c_client *c)
L
Linus Torvalds 已提交
976
{
M
Mauro Carvalho Chehab 已提交
977
	struct tuner *t = i2c_get_clientdata (c);
L
Linus Torvalds 已提交
978

M
Mauro Carvalho Chehab 已提交
979
	tuner_dbg ("resume\n");
980 981 982 983 984 985 986
	if (V4L2_TUNER_RADIO == t->mode) {
		if (t->radio_freq)
			set_freq(c, t->radio_freq);
	} else {
		if (t->tv_freq)
			set_freq(c, t->tv_freq);
	}
L
Linus Torvalds 已提交
987 988 989 990 991 992
	return 0;
}

/* ----------------------------------------------------------------------- */

static struct i2c_driver driver = {
M
Mauro Carvalho Chehab 已提交
993 994 995 996
	.id = I2C_DRIVERID_TUNER,
	.attach_adapter = tuner_probe,
	.detach_client = tuner_detach,
	.command = tuner_command,
997 998
	.suspend = tuner_suspend,
	.resume  = tuner_resume,
L
Linus Torvalds 已提交
999
	.driver = {
1000 1001
		.name    = "tuner",
	},
L
Linus Torvalds 已提交
1002
};
M
Mauro Carvalho Chehab 已提交
1003
static struct i2c_client client_template = {
1004
	.name = "(tuner unset)",
M
Mauro Carvalho Chehab 已提交
1005
	.driver = &driver,
L
Linus Torvalds 已提交
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
};

static int __init tuner_init_module(void)
{
	return i2c_add_driver(&driver);
}

static void __exit tuner_cleanup_module(void)
{
	i2c_del_driver(&driver);
}

module_init(tuner_init_module);
module_exit(tuner_cleanup_module);

/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-basic-offset: 8
 * End:
 */