tuner-simple.c 17.5 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 16 17 18 19
#include "tuner-i2c.h"
#include "tuner-simple.h"

static int debug = 0;
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 = 0;
23
module_param(offset, int, 0664);
24 25
MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");

L
Linus Torvalds 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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
/* ---------------------------------------------------------------------- */

/* 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
#define TEMIC_SET_PAL_L         0x0a // SECAM ?
#define TEMIC_SET_PAL_L2        0x0b // change IF !
#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
		case TUNER_PHILIPS_FM1216ME_MK3:
125
		case TUNER_PHILIPS_FM1236_MK3:
126
		case TUNER_PHILIPS_FM1256_IH3:
127
		case TUNER_LG_NTSC_TAPE:
128
			return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
129
		default:
130
			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
static int simple_set_tv_freq(struct dvb_frontend *fe,
			      struct analog_parameters *params)
L
Linus Torvalds 已提交
178
{
179
	struct tuner_simple_priv *priv = fe->tuner_priv;
180
	u8 config, cb, tuneraddr;
L
Linus Torvalds 已提交
181 182
	u16 div;
	struct tunertype *tun;
183
	u8 buffer[4];
184
	int rc, IFPCoff, i, j;
185
	enum param_type desired_type;
186
	struct tuner_params *t_params;
L
Linus Torvalds 已提交
187

188
	tun = priv->tun;
189

190 191 192 193 194 195 196 197 198 199 200 201
	/* 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)
	*/

202
	if (params->std == V4L2_STD_NTSC_M_JP) {
203 204
		IFPCoff      = 940;
		desired_type = TUNER_PARAM_TYPE_NTSC;
205 206
	} else if ((params->std & V4L2_STD_MN) &&
		  !(params->std & ~V4L2_STD_MN)) {
207 208
		IFPCoff      = 732;
		desired_type = TUNER_PARAM_TYPE_NTSC;
209
	} else if (params->std == V4L2_STD_SECAM_LC) {
210 211
		IFPCoff      = 543;
		desired_type = TUNER_PARAM_TYPE_SECAM;
212
	} else {
213 214
		IFPCoff      = 623;
		desired_type = TUNER_PARAM_TYPE_PAL;
215 216
	}

217 218 219 220 221
	for (j = 0; j < tun->count-1; j++) {
		if (desired_type != tun->params[j].type)
			continue;
		break;
	}
222
	/* use default tuner_t_params if desired_type not available */
223
	if (desired_type != tun->params[j].type) {
224 225
		tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n",
			  IFPCoff, priv->type);
226
		j = 0;
227
	}
228
	t_params = &tun->params[j];
229

230 231
	for (i = 0; i < t_params->count; i++) {
		if (params->frequency > t_params->ranges[i].limit)
232 233
			continue;
		break;
L
Linus Torvalds 已提交
234
	}
235
	if (i == t_params->count) {
236
		tuner_dbg("TV frequency out of range (%d > %d)",
237 238
				params->frequency, t_params->ranges[i - 1].limit);
		params->frequency = t_params->ranges[--i].limit;
239
	}
240 241
	config = t_params->ranges[i].config;
	cb     = t_params->ranges[i].cb;
242 243 244
	/*  i == 0 -> VHF_LO
	 *  i == 1 -> VHF_HI
	 *  i == 2 -> UHF     */
245
	tuner_dbg("tv: param %d, range %d\n",j,i);
L
Linus Torvalds 已提交
246

247
	div=params->frequency + IFPCoff + offset;
248 249

	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
250
					params->frequency / 16, params->frequency % 16 * 100 / 16,
251 252 253 254
					IFPCoff / 16, IFPCoff % 16 * 100 / 16,
					offset / 16, offset % 16 * 100 / 16,
					div);

L
Linus Torvalds 已提交
255
	/* tv norm specific stuff for multi-norm tuners */
256
	switch (priv->type) {
L
Linus Torvalds 已提交
257 258 259 260
	case TUNER_PHILIPS_SECAM: // FI1216MF
		/* 0x01 -> ??? no change ??? */
		/* 0x02 -> PAL BDGHI / SECAM L */
		/* 0x04 -> ??? PAL others / SECAM others ??? */
261
		cb &= ~0x03;
262
		if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
263
			cb |= PHILIPS_MF_SET_STD_L;
264
		else if (params->std & V4L2_STD_SECAM_LC)
265
			cb |= PHILIPS_MF_SET_STD_LC;
266
		else /* V4L2_STD_B|V4L2_STD_GH */
267
			cb |= PHILIPS_MF_SET_STD_BG;
L
Linus Torvalds 已提交
268 269 270
		break;

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

273
		if (params->std & V4L2_STD_PAL_BG) {
274
			cb |= TEMIC_SET_PAL_BG;
L
Linus Torvalds 已提交
275

276
		} else if (params->std & V4L2_STD_PAL_I) {
277
			cb |= TEMIC_SET_PAL_I;
L
Linus Torvalds 已提交
278

279
		} else if (params->std & V4L2_STD_PAL_DK) {
280
			cb |= TEMIC_SET_PAL_DK;
L
Linus Torvalds 已提交
281

282
		} else if (params->std & V4L2_STD_SECAM_L) {
283
			cb |= TEMIC_SET_PAL_L;
L
Linus Torvalds 已提交
284 285 286 287 288

		}
		break;

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

291
		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
292
			cb |= PHILIPS_SET_PAL_BGDK;
L
Linus Torvalds 已提交
293

294
		} else if (params->std & V4L2_STD_PAL_I) {
295
			cb |= PHILIPS_SET_PAL_I;
L
Linus Torvalds 已提交
296

297
		} else if (params->std & V4L2_STD_SECAM_L) {
298
			cb |= PHILIPS_SET_PAL_L;
L
Linus Torvalds 已提交
299 300 301 302 303 304 305 306 307

		}
		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 */
308
		cb &= ~0x03;
309
		if (!(params->std & V4L2_STD_ATSC))
310
			cb |= 2;
L
Linus Torvalds 已提交
311 312 313 314 315
		/* FIXME: input */
		break;

	case TUNER_MICROTUNE_4042FI5:
		/* Set the charge pump for fast tuning */
316
		config |= TUNER_CHARGE_PUMP;
L
Linus Torvalds 已提交
317
		break;
318 319 320 321 322 323

	case TUNER_PHILIPS_TUV1236D:
		/* 0x40 -> ATSC antenna input 1 */
		/* 0x48 -> ATSC antenna input 2 */
		/* 0x00 -> NTSC antenna input 1 */
		/* 0x08 -> NTSC antenna input 2 */
324 325 326 327
		buffer[0] = 0x14;
		buffer[1] = 0x00;
		buffer[2] = 0x17;
		buffer[3] = 0x00;
328
		cb &= ~0x40;
329
		if (params->std & V4L2_STD_ATSC) {
330
			cb |= 0x40;
331 332 333
			buffer[1] = 0x04;
		}
		/* set to the correct mode (analog or digital) */
334 335 336
		tuneraddr = priv->i2c_props.addr;
		priv->i2c_props.addr = 0x0a;
		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2)))
337
			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
338
		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2)))
339
			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
340
		priv->i2c_props.addr = tuneraddr;
341 342
		/* FIXME: input */
		break;
L
Linus Torvalds 已提交
343 344
	}

345
	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
346
		buffer[0] = config;
347
		buffer[1] = cb;
L
Linus Torvalds 已提交
348 349 350 351 352
		buffer[2] = (div>>8) & 0x7f;
		buffer[3] = div      & 0xff;
	} else {
		buffer[0] = (div>>8) & 0x7f;
		buffer[1] = div      & 0xff;
353
		buffer[2] = config;
354
		buffer[3] = cb;
L
Linus Torvalds 已提交
355
	}
356
	priv->last_div = div;
357
	if (t_params->has_tda9887) {
358
		struct v4l2_priv_tun_config tda9887_cfg;
359
		int config = 0;
360 361
		int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
			!(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
362

363 364 365
		tda9887_cfg.tuner = TUNER_TDA9887;
		tda9887_cfg.priv  = &config;

366 367
		if (params->std == V4L2_STD_SECAM_LC) {
			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
368
				config |= TDA9887_PORT1_ACTIVE;
369
			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
370 371 372
				config |= TDA9887_PORT2_ACTIVE;
		}
		else {
373
			if (t_params->port1_active)
374
				config |= TDA9887_PORT1_ACTIVE;
375
			if (t_params->port2_active)
376 377
				config |= TDA9887_PORT2_ACTIVE;
		}
378
		if (t_params->intercarrier_mode)
379 380
			config |= TDA9887_INTERCARRIER;
		if (is_secam_l) {
381 382 383 384 385 386
			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);
387 388
		}
		else {
389 390 391 392 393 394
			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);
395
		}
396
		if (t_params->default_pll_gating_18)
397
			config |= TDA9887_GATING_18;
398 399
		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
				    &tda9887_cfg);
400
	}
L
Linus Torvalds 已提交
401 402 403
	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
		  buffer[0],buffer[1],buffer[2],buffer[3]);

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

407
	switch (priv->type) {
408 409 410 411 412 413 414 415
	case TUNER_LG_TDVS_H06XF:
		/* Set the Auxiliary Byte. */
		buffer[0] = buffer[2];
		buffer[0] &= ~0x20;
		buffer[0] |= 0x18;
		buffer[1] = 0x20;
		tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);

416
		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2)))
417 418 419 420
			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
		break;
	case TUNER_MICROTUNE_4042FI5:
	{
L
Linus Torvalds 已提交
421 422 423 424 425 426 427
		// FIXME - this may also work for other tuners
		unsigned long timeout = jiffies + msecs_to_jiffies(1);
		u8 status_byte = 0;

		/* Wait until the PLL locks */
		for (;;) {
			if (time_after(jiffies,timeout))
428
				return 0;
429
			if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) {
L
Linus Torvalds 已提交
430 431 432
				tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
				break;
			}
M
Mauro Carvalho Chehab 已提交
433
			if (status_byte & TUNER_PLL_LOCKED)
L
Linus Torvalds 已提交
434 435 436 437 438
				break;
			udelay(10);
		}

		/* Set the charge pump for optimized phase noise figure */
439
		config &= ~TUNER_CHARGE_PUMP;
L
Linus Torvalds 已提交
440 441
		buffer[0] = (div>>8) & 0x7f;
		buffer[1] = div      & 0xff;
442
		buffer[2] = config;
443
		buffer[3] = cb;
L
Linus Torvalds 已提交
444
		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
445
			  buffer[0],buffer[1],buffer[2],buffer[3]);
L
Linus Torvalds 已提交
446

447
		if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
L
Linus Torvalds 已提交
448
			tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
449 450
		break;
	}
L
Linus Torvalds 已提交
451
	}
452
	return 0;
L
Linus Torvalds 已提交
453 454
}

455 456
static int simple_set_radio_freq(struct dvb_frontend *fe,
				 struct analog_parameters *params)
L
Linus Torvalds 已提交
457 458
{
	struct tunertype *tun;
459
	struct tuner_simple_priv *priv = fe->tuner_priv;
460 461
	u8 buffer[4];
	u16 div;
462
	int rc, j;
463 464
	struct tuner_params *t_params;
	unsigned int freq = params->frequency;
L
Linus Torvalds 已提交
465

466
	tun = priv->tun;
467

468 469 470
	for (j = tun->count-1; j > 0; j--)
		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
			break;
471 472
	/* default t_params (j=0) will be used if desired type wasn't found */
	t_params = &tun->params[j];
473 474

	/* Select Radio 1st IF used */
475
	switch (t_params->radio_if) {
476 477
	case 0: /* 10.7 MHz */
		freq += (unsigned int)(10.7*16000);
478
		break;
479 480 481 482 483 484 485
	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:
486 487
		tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if);
		return 0;
488
	}
L
Linus Torvalds 已提交
489

490
	/* Bandswitch byte */
491
	switch (priv->type) {
492
	case TUNER_TENA_9533_DI:
493
	case TUNER_YMEC_TVF_5533MF:
494 495
		tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
		return 0;
L
Linus Torvalds 已提交
496 497
	case TUNER_PHILIPS_FM1216ME_MK3:
	case TUNER_PHILIPS_FM1236_MK3:
498
	case TUNER_PHILIPS_FMD1216ME_MK3:
499
	case TUNER_LG_NTSC_TAPE:
500
	case TUNER_PHILIPS_FM1256_IH3:
L
Linus Torvalds 已提交
501 502
		buffer[3] = 0x19;
		break;
503 504 505
	case TUNER_TNF_5335MF:
		buffer[3] = 0x11;
		break;
L
Linus Torvalds 已提交
506 507 508
	case TUNER_LG_PAL_FM:
		buffer[3] = 0xa5;
		break;
509 510
	case TUNER_THOMSON_DTT761X:
		buffer[3] = 0x39;
511
		break;
512
	case TUNER_MICROTUNE_4049FM5:
L
Linus Torvalds 已提交
513 514 515 516
	default:
		buffer[3] = 0xa4;
		break;
	}
517

518
	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
519 520 521 522 523 524 525
		    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;

526
	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
527 528 529 530 531 532 533 534
		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 已提交
535 536 537

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

540
	if (t_params->has_tda9887) {
541
		int config = 0;
542 543 544 545 546
		struct v4l2_priv_tun_config tda9887_cfg;

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

547
		if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
548
			config |= TDA9887_PORT1_ACTIVE;
549
		if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
550
			config |= TDA9887_PORT2_ACTIVE;
551
		if (t_params->intercarrier_mode)
552
			config |= TDA9887_INTERCARRIER;
553
/*		if (t_params->port1_set_for_fm_mono)
554
			config &= ~TDA9887_PORT1_ACTIVE;*/
555
		if (t_params->fm_gain_normal)
556
			config |= TDA9887_GAIN_NORMAL;
557
		if (t_params->radio_if == 2)
558
			config |= TDA9887_RIF_41_3;
559 560
		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
					&tda9887_cfg);
561
	}
562
	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
L
Linus Torvalds 已提交
563
		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
564 565

	return 0;
L
Linus Torvalds 已提交
566 567
}

568 569
static int simple_set_params(struct dvb_frontend *fe,
			     struct analog_parameters *params)
570
{
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
	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;
603 604
}

605 606
static struct dvb_tuner_ops simple_tuner_ops = {
	.set_analog_params = simple_set_params,
607 608 609 610
	.release           = simple_release,
	.get_frequency     = simple_get_frequency,
	.get_status        = simple_get_status,
	.get_rf_strength   = simple_get_rf_strength,
611 612
};

613 614 615 616
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 已提交
617
{
618 619 620 621
	struct tuner_simple_priv *priv = NULL;

	priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL);
	if (priv == NULL)
622 623
		return NULL;
	fe->tuner_priv = priv;
L
Linus Torvalds 已提交
624

625 626 627 628
	priv->i2c_props.addr = i2c_addr;
	priv->i2c_props.adap = i2c_adap;
	priv->type = cfg->type;
	priv->tun  = cfg->tun;
629

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

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

634 635 636
	strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name));

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

639 640 641 642 643 644 645

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 已提交
646 647 648 649 650 651 652
/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-basic-offset: 8
 * End:
 */