tuner-simple.c 18.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * i2c tv tuner chip device driver
 * controls all those simple 4-control-bytes style tuners.
4 5
 *
 * This "tuner-simple" module was split apart from the original "tuner" module.
L
Linus Torvalds 已提交
6 7 8 9 10
 */
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <media/tuner.h>
11
#include <media/v4l2-common.h>
12
#include <media/tuner-types.h>
13 14 15
#include "tuner-i2c.h"
#include "tuner-simple.h"

16
static int debug;
17 18 19
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");

20
#define PREFIX "tuner-simple"
L
Linus Torvalds 已提交
21

22
static int offset;
23
module_param(offset, int, 0664);
24
MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
25

L
Linus Torvalds 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38
/* ---------------------------------------------------------------------- */

/* tv standard selection for Temic 4046 FM5
   this value takes the low bits of control byte 2
   from datasheet Rev.01, Feb.00
     standard     BG      I       L       L2      D
     picture IF   38.9    38.9    38.9    33.95   38.9
     sound 1      33.4    32.9    32.4    40.45   32.4
     sound 2      33.16
     NICAM        33.05   32.348  33.05           33.05
 */
#define TEMIC_SET_PAL_I         0x05
#define TEMIC_SET_PAL_DK        0x09
39 40
#define TEMIC_SET_PAL_L         0x0a /* SECAM ? */
#define TEMIC_SET_PAL_L2        0x0b /* change IF ! */
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
#define TEMIC_SET_PAL_BG        0x0c

/* tv tuner system standard selection for Philips FQ1216ME
   this value takes the low bits of control byte 2
   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
     standard 		BG	DK	I	L	L`
     picture carrier	38.90	38.90	38.90	38.90	33.95
     colour		34.47	34.47	34.47	34.47	38.38
     sound 1		33.40	32.40	32.90	32.40	40.45
     sound 2		33.16	-	-	-	-
     NICAM		33.05	33.05	32.35	33.05	39.80
 */
#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
#define PHILIPS_SET_PAL_BGDK	0x09
#define PHILIPS_SET_PAL_L2	0x0a
#define PHILIPS_SET_PAL_L	0x0b

/* system switching for Philips FI1216MF MK2
   from datasheet "1996 Jul 09",
    standard         BG     L      L'
    picture carrier  38.90  38.90  33.95
    colour	     34.47  34.37  38.38
    sound 1          33.40  32.40  40.45
    sound 2          33.16  -      -
    NICAM            33.05  33.05  39.80
 */
67 68 69
#define PHILIPS_MF_SET_STD_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
#define PHILIPS_MF_SET_STD_L	0x03 /* Used on Secam France */
#define PHILIPS_MF_SET_STD_LC	0x02 /* Used on SECAM L' */
L
Linus Torvalds 已提交
70

M
Mauro Carvalho Chehab 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
/* Control byte */

#define TUNER_RATIO_MASK        0x06 /* Bit cb1:cb2 */
#define TUNER_RATIO_SELECT_50   0x00
#define TUNER_RATIO_SELECT_32   0x02
#define TUNER_RATIO_SELECT_166  0x04
#define TUNER_RATIO_SELECT_62   0x06

#define TUNER_CHARGE_PUMP       0x40  /* Bit cb6 */

/* Status byte */

#define TUNER_POR	  0x80
#define TUNER_FL          0x40
#define TUNER_MODE        0x38
#define TUNER_AFC         0x07
#define TUNER_SIGNAL      0x07
#define TUNER_STEREO      0x10

#define TUNER_PLL_LOCKED   0x40
#define TUNER_STEREO_MK3   0x04
L
Linus Torvalds 已提交
92

93 94
struct tuner_simple_priv {
	u16 last_div;
95
	struct tuner_i2c_props i2c_props;
96 97 98 99 100

	unsigned int type;
	struct tunertype *tun;

	u32 frequency;
101 102
};

L
Linus Torvalds 已提交
103 104
/* ---------------------------------------------------------------------- */

105
static int tuner_read_status(struct dvb_frontend *fe)
L
Linus Torvalds 已提交
106
{
107
	struct tuner_simple_priv *priv = fe->tuner_priv;
L
Linus Torvalds 已提交
108 109
	unsigned char byte;

110
	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
L
Linus Torvalds 已提交
111
		return 0;
112

L
Linus Torvalds 已提交
113 114 115
	return byte;
}

116
static inline int tuner_signal(const int status)
L
Linus Torvalds 已提交
117
{
118
	return (status & TUNER_SIGNAL) << 13;
L
Linus Torvalds 已提交
119 120
}

121
static inline int tuner_stereo(const int type, const int status)
L
Linus Torvalds 已提交
122
{
123
	switch (type) {
124 125 126 127 128 129 130
	case TUNER_PHILIPS_FM1216ME_MK3:
	case TUNER_PHILIPS_FM1236_MK3:
	case TUNER_PHILIPS_FM1256_IH3:
	case TUNER_LG_NTSC_TAPE:
		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
	default:
		return status & TUNER_STEREO;
131
	}
132
}
133

134 135 136 137 138 139 140 141
static inline int tuner_islocked(const int status)
{
	return (status & TUNER_FL);
}

static inline int tuner_afcstatus(const int status)
{
	return (status & TUNER_AFC) - 2;
L
Linus Torvalds 已提交
142 143 144
}


145 146 147
static int simple_get_status(struct dvb_frontend *fe, u32 *status)
{
	struct tuner_simple_priv *priv = fe->tuner_priv;
148
	int tuner_status = tuner_read_status(fe);
149 150 151

	*status = 0;

152
	if (tuner_islocked(tuner_status))
153
		*status = TUNER_STATUS_LOCKED;
154
	if (tuner_stereo(priv->type, tuner_status))
155 156
		*status |= TUNER_STATUS_STEREO;

157 158 159 160 161 162 163 164 165 166 167 168 169
	tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));

	return 0;
}

static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
{
	struct tuner_simple_priv *priv = fe->tuner_priv;
	int signal = tuner_signal(tuner_read_status(fe));

	*strength = signal;

	tuner_dbg("Signal strength: %d\n", signal);
170 171 172 173

	return 0;
}

L
Linus Torvalds 已提交
174 175
/* ---------------------------------------------------------------------- */

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
static inline char *tuner_param_name(enum param_type type)
{
	char *name;

	switch (type) {
	case TUNER_PARAM_TYPE_RADIO:
		name = "radio";
		break;
	case TUNER_PARAM_TYPE_PAL:
		name = "pal";
		break;
	case TUNER_PARAM_TYPE_SECAM:
		name = "secam";
		break;
	case TUNER_PARAM_TYPE_NTSC:
		name = "ntsc";
		break;
	default:
		name = "unknown";
		break;
	}
	return name;
}

static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
						enum param_type desired_type)
{
	struct tuner_simple_priv *priv = fe->tuner_priv;
	struct tunertype *tun = priv->tun;
	int i;

	for (i = 0; i < tun->count; i++)
		if (desired_type == tun->params[i].type)
			break;

	/* use default tuner params if desired_type not available */
	if (i == tun->count) {
		tuner_dbg("desired params (%s) undefined for tuner %d\n",
			  tuner_param_name(desired_type), priv->type);
		i = 0;
	}

	tuner_dbg("using tuner params #%d (%s)\n", i,
		  tuner_param_name(tun->params[i].type));

	return &tun->params[i];
}

static int simple_config_lookup(struct dvb_frontend *fe,
				struct tuner_params *t_params,
				int *frequency, u8 *config, u8 *cb)
{
	struct tuner_simple_priv *priv = fe->tuner_priv;
	int i;

	for (i = 0; i < t_params->count; i++) {
		if (*frequency > t_params->ranges[i].limit)
			continue;
		break;
	}
	if (i == t_params->count) {
		tuner_dbg("frequency out of range (%d > %d)\n",
			  *frequency, t_params->ranges[i - 1].limit);
		*frequency = t_params->ranges[--i].limit;
	}
	*config = t_params->ranges[i].config;
	*cb     = t_params->ranges[i].cb;

244 245 246 247
	tuner_dbg("freq = %d.%02d (%d), range = %d, "
		  "config = 0x%02x, cb = 0x%02x\n",
		  *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
		  i, *config, *cb);
248 249 250 251 252 253

	return i;
}

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

254 255
static int simple_set_tv_freq(struct dvb_frontend *fe,
			      struct analog_parameters *params)
L
Linus Torvalds 已提交
256
{
257
	struct tuner_simple_priv *priv = fe->tuner_priv;
258
	u8 config, cb, tuneraddr;
L
Linus Torvalds 已提交
259 260
	u16 div;
	struct tunertype *tun;
261
	u8 buffer[4];
262
	int rc, IFPCoff, i;
263
	enum param_type desired_type;
264
	struct tuner_params *t_params;
L
Linus Torvalds 已提交
265

266
	tun = priv->tun;
267

268 269 270 271 272 273 274 275 276 277 278 279
	/* IFPCoff = Video Intermediate Frequency - Vif:
		940  =16*58.75  NTSC/J (Japan)
		732  =16*45.75  M/N STD
		704  =16*44     ATSC (at DVB code)
		632  =16*39.50  I U.K.
		622.4=16*38.90  B/G D/K I, L STD
		592  =16*37.00  D China
		590  =16.36.875 B Australia
		543.2=16*33.95  L' STD
		171.2=16*10.70  FM Radio (at set_radio_freq)
	*/

280
	if (params->std == V4L2_STD_NTSC_M_JP) {
281 282
		IFPCoff      = 940;
		desired_type = TUNER_PARAM_TYPE_NTSC;
283 284
	} else if ((params->std & V4L2_STD_MN) &&
		  !(params->std & ~V4L2_STD_MN)) {
285 286
		IFPCoff      = 732;
		desired_type = TUNER_PARAM_TYPE_NTSC;
287
	} else if (params->std == V4L2_STD_SECAM_LC) {
288 289
		IFPCoff      = 543;
		desired_type = TUNER_PARAM_TYPE_SECAM;
290
	} else {
291 292
		IFPCoff      = 623;
		desired_type = TUNER_PARAM_TYPE_PAL;
293 294
	}

295
	t_params = simple_tuner_params(fe, desired_type);
296

297 298
	i = simple_config_lookup(fe, t_params, &params->frequency,
				 &config, &cb);
L
Linus Torvalds 已提交
299

300
	div = params->frequency + IFPCoff + offset;
301

302 303 304 305 306
	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "
		  "Offset=%d.%02d MHz, div=%0d\n",
		  params->frequency / 16, params->frequency % 16 * 100 / 16,
		  IFPCoff / 16, IFPCoff % 16 * 100 / 16,
		  offset / 16, offset % 16 * 100 / 16, div);
307

L
Linus Torvalds 已提交
308
	/* tv norm specific stuff for multi-norm tuners */
309
	switch (priv->type) {
310
	case TUNER_PHILIPS_SECAM: /* FI1216MF */
L
Linus Torvalds 已提交
311 312 313
		/* 0x01 -> ??? no change ??? */
		/* 0x02 -> PAL BDGHI / SECAM L */
		/* 0x04 -> ??? PAL others / SECAM others ??? */
314
		cb &= ~0x03;
315 316
		if (params->std & V4L2_STD_SECAM_L)
			/* also valid for V4L2_STD_SECAM */
317
			cb |= PHILIPS_MF_SET_STD_L;
318
		else if (params->std & V4L2_STD_SECAM_LC)
319
			cb |= PHILIPS_MF_SET_STD_LC;
320
		else /* V4L2_STD_B|V4L2_STD_GH */
321
			cb |= PHILIPS_MF_SET_STD_BG;
L
Linus Torvalds 已提交
322 323 324
		break;

	case TUNER_TEMIC_4046FM5:
325
		cb &= ~0x0f;
L
Linus Torvalds 已提交
326

327
		if (params->std & V4L2_STD_PAL_BG) {
328
			cb |= TEMIC_SET_PAL_BG;
L
Linus Torvalds 已提交
329

330
		} else if (params->std & V4L2_STD_PAL_I) {
331
			cb |= TEMIC_SET_PAL_I;
L
Linus Torvalds 已提交
332

333
		} else if (params->std & V4L2_STD_PAL_DK) {
334
			cb |= TEMIC_SET_PAL_DK;
L
Linus Torvalds 已提交
335

336
		} else if (params->std & V4L2_STD_SECAM_L) {
337
			cb |= TEMIC_SET_PAL_L;
L
Linus Torvalds 已提交
338 339 340 341 342

		}
		break;

	case TUNER_PHILIPS_FQ1216ME:
343
		cb &= ~0x0f;
L
Linus Torvalds 已提交
344

345
		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
346
			cb |= PHILIPS_SET_PAL_BGDK;
L
Linus Torvalds 已提交
347

348
		} else if (params->std & V4L2_STD_PAL_I) {
349
			cb |= PHILIPS_SET_PAL_I;
L
Linus Torvalds 已提交
350

351
		} else if (params->std & V4L2_STD_SECAM_L) {
352
			cb |= PHILIPS_SET_PAL_L;
L
Linus Torvalds 已提交
353 354 355 356 357 358 359 360 361

		}
		break;

	case TUNER_PHILIPS_ATSC:
		/* 0x00 -> ATSC antenna input 1 */
		/* 0x01 -> ATSC antenna input 2 */
		/* 0x02 -> NTSC antenna input 1 */
		/* 0x03 -> NTSC antenna input 2 */
362
		cb &= ~0x03;
363
		if (!(params->std & V4L2_STD_ATSC))
364
			cb |= 2;
L
Linus Torvalds 已提交
365 366 367 368 369
		/* FIXME: input */
		break;

	case TUNER_MICROTUNE_4042FI5:
		/* Set the charge pump for fast tuning */
370
		config |= TUNER_CHARGE_PUMP;
L
Linus Torvalds 已提交
371
		break;
372 373 374 375 376 377

	case TUNER_PHILIPS_TUV1236D:
		/* 0x40 -> ATSC antenna input 1 */
		/* 0x48 -> ATSC antenna input 2 */
		/* 0x00 -> NTSC antenna input 1 */
		/* 0x08 -> NTSC antenna input 2 */
378 379 380 381
		buffer[0] = 0x14;
		buffer[1] = 0x00;
		buffer[2] = 0x17;
		buffer[3] = 0x00;
382
		cb &= ~0x40;
383
		if (params->std & V4L2_STD_ATSC) {
384
			cb |= 0x40;
385 386 387
			buffer[1] = 0x04;
		}
		/* set to the correct mode (analog or digital) */
388 389
		tuneraddr = priv->i2c_props.addr;
		priv->i2c_props.addr = 0x0a;
390 391 392 393 394 395 396 397
		rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2);
		if (2 != rc)
			tuner_warn("i2c i/o error: rc == %d "
				   "(should be 2)\n", rc);
		rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2);
		if (2 != rc)
			tuner_warn("i2c i/o error: rc == %d "
				   "(should be 2)\n", rc);
398
		priv->i2c_props.addr = tuneraddr;
399 400
		/* FIXME: input */
		break;
L
Linus Torvalds 已提交
401 402
	}

403
	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
404
		buffer[0] = config;
405
		buffer[1] = cb;
L
Linus Torvalds 已提交
406 407 408 409 410
		buffer[2] = (div>>8) & 0x7f;
		buffer[3] = div      & 0xff;
	} else {
		buffer[0] = (div>>8) & 0x7f;
		buffer[1] = div      & 0xff;
411
		buffer[2] = config;
412
		buffer[3] = cb;
L
Linus Torvalds 已提交
413
	}
414
	priv->last_div = div;
415
	if (t_params->has_tda9887) {
416
		struct v4l2_priv_tun_config tda9887_cfg;
417
		int config = 0;
418 419 420 421
		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
						 V4L2_STD_SECAM_LC)) &&
			!(params->std & ~(V4L2_STD_SECAM_L |
					  V4L2_STD_SECAM_LC));
422

423 424 425
		tda9887_cfg.tuner = TUNER_TDA9887;
		tda9887_cfg.priv  = &config;

426 427
		if (params->std == V4L2_STD_SECAM_LC) {
			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
428
				config |= TDA9887_PORT1_ACTIVE;
429
			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
430
				config |= TDA9887_PORT2_ACTIVE;
431
		} else {
432
			if (t_params->port1_active)
433
				config |= TDA9887_PORT1_ACTIVE;
434
			if (t_params->port2_active)
435 436
				config |= TDA9887_PORT2_ACTIVE;
		}
437
		if (t_params->intercarrier_mode)
438 439
			config |= TDA9887_INTERCARRIER;
		if (is_secam_l) {
440 441 442 443 444 445
			if (i == 0 && t_params->default_top_secam_low)
				config |= TDA9887_TOP(t_params->default_top_secam_low);
			else if (i == 1 && t_params->default_top_secam_mid)
				config |= TDA9887_TOP(t_params->default_top_secam_mid);
			else if (t_params->default_top_secam_high)
				config |= TDA9887_TOP(t_params->default_top_secam_high);
446
		} else {
447 448 449 450 451 452
			if (i == 0 && t_params->default_top_low)
				config |= TDA9887_TOP(t_params->default_top_low);
			else if (i == 1 && t_params->default_top_mid)
				config |= TDA9887_TOP(t_params->default_top_mid);
			else if (t_params->default_top_high)
				config |= TDA9887_TOP(t_params->default_top_high);
453
		}
454
		if (t_params->default_pll_gating_18)
455
			config |= TDA9887_GATING_18;
456 457
		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
				    &tda9887_cfg);
458
	}
L
Linus Torvalds 已提交
459
	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
460
		  buffer[0], buffer[1], buffer[2], buffer[3]);
L
Linus Torvalds 已提交
461

462 463 464
	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
	if (4 != rc)
		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
L
Linus Torvalds 已提交
465

466
	switch (priv->type) {
467 468 469 470 471 472
	case TUNER_LG_TDVS_H06XF:
		/* Set the Auxiliary Byte. */
		buffer[0] = buffer[2];
		buffer[0] &= ~0x20;
		buffer[0] |= 0x18;
		buffer[1] = 0x20;
473
		tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
474

475 476 477 478
		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
		if (2 != rc)
			tuner_warn("i2c i/o error: rc == %d "
				   "(should be 2)\n", rc);
479 480 481
		break;
	case TUNER_MICROTUNE_4042FI5:
	{
482
		/* FIXME - this may also work for other tuners */
L
Linus Torvalds 已提交
483 484 485 486 487
		unsigned long timeout = jiffies + msecs_to_jiffies(1);
		u8 status_byte = 0;

		/* Wait until the PLL locks */
		for (;;) {
488
			if (time_after(jiffies, timeout))
489
				return 0;
490 491 492 493 494
			rc = tuner_i2c_xfer_recv(&priv->i2c_props,
						 &status_byte, 1);
			if (1 != rc) {
				tuner_warn("i2c i/o read error: rc == %d "
					   "(should be 1)\n", rc);
L
Linus Torvalds 已提交
495 496
				break;
			}
M
Mauro Carvalho Chehab 已提交
497
			if (status_byte & TUNER_PLL_LOCKED)
L
Linus Torvalds 已提交
498 499 500 501 502
				break;
			udelay(10);
		}

		/* Set the charge pump for optimized phase noise figure */
503
		config &= ~TUNER_CHARGE_PUMP;
L
Linus Torvalds 已提交
504 505
		buffer[0] = (div>>8) & 0x7f;
		buffer[1] = div      & 0xff;
506
		buffer[2] = config;
507
		buffer[3] = cb;
L
Linus Torvalds 已提交
508
		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
509
			  buffer[0], buffer[1], buffer[2], buffer[3]);
L
Linus Torvalds 已提交
510

511 512 513 514
		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
		if (4 != rc)
			tuner_warn("i2c i/o error: rc == %d "
				   "(should be 4)\n", rc);
515 516
		break;
	}
L
Linus Torvalds 已提交
517
	}
518
	return 0;
L
Linus Torvalds 已提交
519 520
}

521 522
static int simple_set_radio_freq(struct dvb_frontend *fe,
				 struct analog_parameters *params)
L
Linus Torvalds 已提交
523 524
{
	struct tunertype *tun;
525
	struct tuner_simple_priv *priv = fe->tuner_priv;
526 527
	u8 buffer[4];
	u16 div;
528
	int rc, j;
529 530
	struct tuner_params *t_params;
	unsigned int freq = params->frequency;
L
Linus Torvalds 已提交
531

532
	tun = priv->tun;
533

534 535 536
	for (j = tun->count-1; j > 0; j--)
		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
			break;
537 538
	/* default t_params (j=0) will be used if desired type wasn't found */
	t_params = &tun->params[j];
539 540

	/* Select Radio 1st IF used */
541
	switch (t_params->radio_if) {
542 543
	case 0: /* 10.7 MHz */
		freq += (unsigned int)(10.7*16000);
544
		break;
545 546 547 548 549 550 551
	case 1: /* 33.3 MHz */
		freq += (unsigned int)(33.3*16000);
		break;
	case 2: /* 41.3 MHz */
		freq += (unsigned int)(41.3*16000);
		break;
	default:
552 553
		tuner_warn("Unsupported radio_if value %d\n",
			   t_params->radio_if);
554
		return 0;
555
	}
L
Linus Torvalds 已提交
556

557
	/* Bandswitch byte */
558
	switch (priv->type) {
559
	case TUNER_TENA_9533_DI:
560
	case TUNER_YMEC_TVF_5533MF:
561 562
		tuner_dbg("This tuner doesn't have FM. "
			  "Most cards have a TEA5767 for FM\n");
563
		return 0;
L
Linus Torvalds 已提交
564 565
	case TUNER_PHILIPS_FM1216ME_MK3:
	case TUNER_PHILIPS_FM1236_MK3:
566
	case TUNER_PHILIPS_FMD1216ME_MK3:
567
	case TUNER_LG_NTSC_TAPE:
568
	case TUNER_PHILIPS_FM1256_IH3:
L
Linus Torvalds 已提交
569 570
		buffer[3] = 0x19;
		break;
571 572 573
	case TUNER_TNF_5335MF:
		buffer[3] = 0x11;
		break;
L
Linus Torvalds 已提交
574 575 576
	case TUNER_LG_PAL_FM:
		buffer[3] = 0xa5;
		break;
577 578
	case TUNER_THOMSON_DTT761X:
		buffer[3] = 0x39;
579
		break;
580
	case TUNER_MICROTUNE_4049FM5:
L
Linus Torvalds 已提交
581 582 583 584
	default:
		buffer[3] = 0xa4;
		break;
	}
585

586
	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
587 588 589 590 591 592 593
		    TUNER_RATIO_SELECT_50; /* 50 kHz step */

	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
	   freq * (1/800) */
	div = (freq + 400) / 800;

594
	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
595 596 597 598 599 600 601 602
		buffer[0] = buffer[2];
		buffer[1] = buffer[3];
		buffer[2] = (div>>8) & 0x7f;
		buffer[3] = div      & 0xff;
	} else {
		buffer[0] = (div>>8) & 0x7f;
		buffer[1] = div      & 0xff;
	}
L
Linus Torvalds 已提交
603 604

	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
605
	       buffer[0], buffer[1], buffer[2], buffer[3]);
606
	priv->last_div = div;
L
Linus Torvalds 已提交
607

608
	if (t_params->has_tda9887) {
609
		int config = 0;
610 611 612 613 614
		struct v4l2_priv_tun_config tda9887_cfg;

		tda9887_cfg.tuner = TUNER_TDA9887;
		tda9887_cfg.priv = &config;

615 616
		if (t_params->port1_active &&
		    !t_params->port1_fm_high_sensitivity)
617
			config |= TDA9887_PORT1_ACTIVE;
618 619
		if (t_params->port2_active &&
		    !t_params->port2_fm_high_sensitivity)
620
			config |= TDA9887_PORT2_ACTIVE;
621
		if (t_params->intercarrier_mode)
622
			config |= TDA9887_INTERCARRIER;
623
/*		if (t_params->port1_set_for_fm_mono)
624
			config &= ~TDA9887_PORT1_ACTIVE;*/
625
		if (t_params->fm_gain_normal)
626
			config |= TDA9887_GAIN_NORMAL;
627
		if (t_params->radio_if == 2)
628
			config |= TDA9887_RIF_41_3;
629
		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
630
				    &tda9887_cfg);
631
	}
632 633 634
	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
	if (4 != rc)
		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
635 636

	return 0;
L
Linus Torvalds 已提交
637 638
}

639 640
static int simple_set_params(struct dvb_frontend *fe,
			     struct analog_parameters *params)
641
{
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
	struct tuner_simple_priv *priv = fe->tuner_priv;
	int ret = -EINVAL;

	switch (params->mode) {
	case V4L2_TUNER_RADIO:
		ret = simple_set_radio_freq(fe, params);
		priv->frequency = params->frequency * 125 / 2;
		break;
	case V4L2_TUNER_ANALOG_TV:
	case V4L2_TUNER_DIGITAL_TV:
		ret = simple_set_tv_freq(fe, params);
		priv->frequency = params->frequency * 62500;
		break;
	}

	return ret;
}


static int simple_release(struct dvb_frontend *fe)
{
	kfree(fe->tuner_priv);
	fe->tuner_priv = NULL;

	return 0;
}

static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
	struct tuner_simple_priv *priv = fe->tuner_priv;
	*frequency = priv->frequency;
	return 0;
674 675
}

676 677
static struct dvb_tuner_ops simple_tuner_ops = {
	.set_analog_params = simple_set_params,
678 679 680 681
	.release           = simple_release,
	.get_frequency     = simple_get_frequency,
	.get_status        = simple_get_status,
	.get_rf_strength   = simple_get_rf_strength,
682 683
};

684 685 686 687
struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
					 struct i2c_adapter *i2c_adap,
					 u8 i2c_addr,
					 struct simple_tuner_config *cfg)
L
Linus Torvalds 已提交
688
{
689 690
	struct tuner_simple_priv *priv = NULL;

691 692 693 694 695 696
	if (type >= tuner_count) {
		printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
		       __FUNCTION__, type, tuner_count-1);
		return NULL;
	}

697 698
	priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL);
	if (priv == NULL)
699 700
		return NULL;
	fe->tuner_priv = priv;
L
Linus Torvalds 已提交
701

702 703 704 705
	priv->i2c_props.addr = i2c_addr;
	priv->i2c_props.adap = i2c_adap;
	priv->type = cfg->type;
	priv->tun  = cfg->tun;
706

707 708
	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
	       sizeof(struct dvb_tuner_ops));
L
Linus Torvalds 已提交
709

710
	tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name);
711

712 713
	strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name,
		sizeof(fe->ops.tuner_ops.info.name));
714 715

	return fe;
L
Linus Torvalds 已提交
716
}
717 718 719 720 721 722
EXPORT_SYMBOL_GPL(simple_tuner_attach);

MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");

L
Linus Torvalds 已提交
723 724 725 726 727 728 729
/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-basic-offset: 8
 * End:
 */