tda9887.c 16.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>

12
#include <media/v4l2-common.h>
L
Linus Torvalds 已提交
13
#include <media/tuner.h>
14
#include "tuner-driver.h"
L
Linus Torvalds 已提交
15

16

L
Linus Torvalds 已提交
17 18 19 20 21
/* Chips:
   TDA9885 (PAL, NTSC)
   TDA9886 (PAL, SECAM, NTSC)
   TDA9887 (PAL, SECAM, NTSC, FM Radio)

22
   Used as part of several tuners
L
Linus Torvalds 已提交
23 24
*/

25
#define tda9887_info(fmt, arg...) do {\
26
	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
27 28 29
			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
#define tda9887_dbg(fmt, arg...) do {\
	if (tuner_debug) \
30
		printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
31
			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
L
Linus Torvalds 已提交
32

33 34 35
struct tda9887_priv {
	unsigned char 	   data[4];
};
L
Linus Torvalds 已提交
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

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

#define UNSET       (-1U)

struct tvnorm {
	v4l2_std_id       std;
	char              *name;
	unsigned char     b;
	unsigned char     c;
	unsigned char     e;
};

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

//
// TDA defines
//

//// first reg (b)
#define cVideoTrapBypassOFF     0x00    // bit b0
#define cVideoTrapBypassON      0x01    // bit b0

#define cAutoMuteFmInactive     0x00    // bit b1
#define cAutoMuteFmActive       0x02    // bit b1

#define cIntercarrier           0x00    // bit b2
#define cQSS                    0x04    // bit b2

#define cPositiveAmTV           0x00    // bit b3:4
#define cFmRadio                0x08    // bit b3:4
#define cNegativeFmTV           0x10    // bit b3:4


#define cForcedMuteAudioON      0x20    // bit b5
#define cForcedMuteAudioOFF     0x00    // bit b5

#define cOutputPort1Active      0x00    // bit b6
#define cOutputPort1Inactive    0x40    // bit b6

#define cOutputPort2Active      0x00    // bit b7
#define cOutputPort2Inactive    0x80    // bit b7


//// second reg (c)
#define cDeemphasisOFF          0x00    // bit c5
#define cDeemphasisON           0x20    // bit c5

#define cDeemphasis75           0x00    // bit c6
#define cDeemphasis50           0x40    // bit c6

#define cAudioGain0             0x00    // bit c7
#define cAudioGain6             0x80    // bit c7

90
#define cTopMask                0x1f    // bit c0:4
91
#define cTopDefault		0x10 	// bit c0:4
L
Linus Torvalds 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

//// third reg (e)
#define cAudioIF_4_5             0x00    // bit e0:1
#define cAudioIF_5_5             0x01    // bit e0:1
#define cAudioIF_6_0             0x02    // bit e0:1
#define cAudioIF_6_5             0x03    // bit e0:1


#define cVideoIF_58_75           0x00    // bit e2:4
#define cVideoIF_45_75           0x04    // bit e2:4
#define cVideoIF_38_90           0x08    // bit e2:4
#define cVideoIF_38_00           0x0C    // bit e2:4
#define cVideoIF_33_90           0x10    // bit e2:4
#define cVideoIF_33_40           0x14    // bit e2:4
#define cRadioIF_45_75           0x18    // bit e2:4
#define cRadioIF_38_90           0x1C    // bit e2:4


#define cTunerGainNormal         0x00    // bit e5
#define cTunerGainLow            0x20    // bit e5

#define cGating_18               0x00    // bit e6
#define cGating_36               0x40    // bit e6

#define cAgcOutON                0x80    // bit e7
#define cAgcOutOFF               0x00    // bit e7

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

static struct tvnorm tvnorms[] = {
	{
123 124
		.std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
		.name  = "PAL-BGHN",
L
Linus Torvalds 已提交
125 126 127
		.b     = ( cNegativeFmTV  |
			   cQSS           ),
		.c     = ( cDeemphasisON  |
128
			   cDeemphasis50  |
129
			   cTopDefault),
130 131
		.e     = ( cGating_36     |
			   cAudioIF_5_5   |
L
Linus Torvalds 已提交
132 133 134 135 136 137 138
			   cVideoIF_38_90 ),
	},{
		.std   = V4L2_STD_PAL_I,
		.name  = "PAL-I",
		.b     = ( cNegativeFmTV  |
			   cQSS           ),
		.c     = ( cDeemphasisON  |
139
			   cDeemphasis50  |
140
			   cTopDefault),
141 142
		.e     = ( cGating_36     |
			   cAudioIF_6_0   |
L
Linus Torvalds 已提交
143 144 145 146 147 148 149
			   cVideoIF_38_90 ),
	},{
		.std   = V4L2_STD_PAL_DK,
		.name  = "PAL-DK",
		.b     = ( cNegativeFmTV  |
			   cQSS           ),
		.c     = ( cDeemphasisON  |
150
			   cDeemphasis50  |
151
			   cTopDefault),
152 153 154
		.e     = ( cGating_36     |
			   cAudioIF_6_5   |
			   cVideoIF_38_90 ),
L
Linus Torvalds 已提交
155
	},{
156 157
		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
		.name  = "PAL-M/Nc",
L
Linus Torvalds 已提交
158 159 160
		.b     = ( cNegativeFmTV  |
			   cQSS           ),
		.c     = ( cDeemphasisON  |
161
			   cDeemphasis75  |
162
			   cTopDefault),
163 164
		.e     = ( cGating_36     |
			   cAudioIF_4_5   |
L
Linus Torvalds 已提交
165
			   cVideoIF_45_75 ),
166 167 168 169 170
	},{
		.std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
		.name  = "SECAM-BGH",
		.b     = ( cPositiveAmTV  |
			   cQSS           ),
171
		.c     = ( cTopDefault),
172 173 174
		.e     = ( cGating_36	  |
			   cAudioIF_5_5   |
			   cVideoIF_38_90 ),
L
Linus Torvalds 已提交
175 176 177 178 179
	},{
		.std   = V4L2_STD_SECAM_L,
		.name  = "SECAM-L",
		.b     = ( cPositiveAmTV  |
			   cQSS           ),
180
		.c     = ( cTopDefault),
N
Nickolay V. Shmyrev 已提交
181
		.e     = ( cGating_36	  |
182
			   cAudioIF_6_5   |
L
Linus Torvalds 已提交
183
			   cVideoIF_38_90 ),
184 185 186 187 188 189
	},{
		.std   = V4L2_STD_SECAM_LC,
		.name  = "SECAM-L'",
		.b     = ( cOutputPort2Inactive |
			   cPositiveAmTV  |
			   cQSS           ),
190
		.c     = ( cTopDefault),
191 192 193
		.e     = ( cGating_36	  |
			   cAudioIF_6_5   |
			   cVideoIF_33_90 ),
L
Linus Torvalds 已提交
194 195 196 197 198 199
	},{
		.std   = V4L2_STD_SECAM_DK,
		.name  = "SECAM-DK",
		.b     = ( cNegativeFmTV  |
			   cQSS           ),
		.c     = ( cDeemphasisON  |
200
			   cDeemphasis50  |
201
			   cTopDefault),
202 203 204
		.e     = ( cGating_36     |
			   cAudioIF_6_5   |
			   cVideoIF_38_90 ),
L
Linus Torvalds 已提交
205
	},{
206
		.std   = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
L
Linus Torvalds 已提交
207 208 209 210
		.name  = "NTSC-M",
		.b     = ( cNegativeFmTV  |
			   cQSS           ),
		.c     = ( cDeemphasisON  |
211
			   cDeemphasis75  |
212
			   cTopDefault),
L
Linus Torvalds 已提交
213 214 215 216 217
		.e     = ( cGating_36     |
			   cAudioIF_4_5   |
			   cVideoIF_45_75 ),
	},{
		.std   = V4L2_STD_NTSC_M_JP,
218
		.name  = "NTSC-M-JP",
L
Linus Torvalds 已提交
219 220 221
		.b     = ( cNegativeFmTV  |
			   cQSS           ),
		.c     = ( cDeemphasisON  |
222
			   cDeemphasis50  |
223
			   cTopDefault),
L
Linus Torvalds 已提交
224 225 226 227 228 229
		.e     = ( cGating_36     |
			   cAudioIF_4_5   |
			   cVideoIF_58_75 ),
	}
};

230 231 232 233 234
static struct tvnorm radio_stereo = {
	.name = "Radio Stereo",
	.b    = ( cFmRadio       |
		  cQSS           ),
	.c    = ( cDeemphasisOFF |
235
		  cAudioGain6    |
236
		  cTopDefault),
237 238
	.e    = ( cTunerGainLow  |
		  cAudioIF_5_5   |
239 240 241 242 243
		  cRadioIF_38_90 ),
};

static struct tvnorm radio_mono = {
	.name = "Radio Mono",
L
Linus Torvalds 已提交
244 245 246
	.b    = ( cFmRadio       |
		  cQSS           ),
	.c    = ( cDeemphasisON  |
247
		  cDeemphasis75  |
248
		  cTopDefault),
249 250
	.e    = ( cTunerGainLow  |
		  cAudioIF_5_5   |
L
Linus Torvalds 已提交
251 252 253 254 255
		  cRadioIF_38_90 ),
};

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

256
static void dump_read_message(struct tuner *t, unsigned char *buf)
L
Linus Torvalds 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
{
	static char *afc[16] = {
		"- 12.5 kHz",
		"- 37.5 kHz",
		"- 62.5 kHz",
		"- 87.5 kHz",
		"-112.5 kHz",
		"-137.5 kHz",
		"-162.5 kHz",
		"-187.5 kHz [min]",
		"+187.5 kHz [max]",
		"+162.5 kHz",
		"+137.5 kHz",
		"+112.5 kHz",
		"+ 87.5 kHz",
		"+ 62.5 kHz",
		"+ 37.5 kHz",
		"+ 12.5 kHz",
	};
276 277 278 279 280 281
	tda9887_info("read: 0x%2x\n", buf[0]);
	tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
	tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
	tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
	tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
	tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
L
Linus Torvalds 已提交
282 283
}

284
static void dump_write_message(struct tuner *t, unsigned char *buf)
L
Linus Torvalds 已提交
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
{
	static char *sound[4] = {
		"AM/TV",
		"FM/radio",
		"FM/TV",
		"FM/radio"
	};
	static char *adjust[32] = {
		"-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
		"-8",  "-7",  "-6",  "-5",  "-4",  "-3",  "-2",  "-1",
		"0",   "+1",  "+2",  "+3",  "+4",  "+5",  "+6",  "+7",
		"+8",  "+9",  "+10", "+11", "+12", "+13", "+14", "+15"
	};
	static char *deemph[4] = {
		"no", "no", "75", "50"
	};
	static char *carrier[4] = {
		"4.5 MHz",
		"5.5 MHz",
		"6.0 MHz",
		"6.5 MHz / AM"
	};
	static char *vif[8] = {
		"58.75 MHz",
		"45.75 MHz",
		"38.9 MHz",
		"38.0 MHz",
		"33.9 MHz",
		"33.4 MHz",
		"45.75 MHz + pin13",
		"38.9 MHz + pin13",
	};
	static char *rif[4] = {
		"44 MHz",
		"52 MHz",
		"52 MHz",
		"44 MHz",
	};

324 325
	tda9887_info("write: byte B 0x%02x\n",buf[1]);
	tda9887_info("  B0   video mode      : %s\n",
L
Linus Torvalds 已提交
326
	       (buf[1] & 0x01) ? "video trap" : "sound trap");
327
	tda9887_info("  B1   auto mute fm    : %s\n",
L
Linus Torvalds 已提交
328
	       (buf[1] & 0x02) ? "yes" : "no");
329
	tda9887_info("  B2   carrier mode    : %s\n",
L
Linus Torvalds 已提交
330
	       (buf[1] & 0x04) ? "QSS" : "Intercarrier");
331
	tda9887_info("  B3-4 tv sound/radio  : %s\n",
L
Linus Torvalds 已提交
332
	       sound[(buf[1] & 0x18) >> 3]);
333
	tda9887_info("  B5   force mute audio: %s\n",
L
Linus Torvalds 已提交
334
	       (buf[1] & 0x20) ? "yes" : "no");
335
	tda9887_info("  B6   output port 1   : %s\n",
L
Linus Torvalds 已提交
336
	       (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
337
	tda9887_info("  B7   output port 2   : %s\n",
L
Linus Torvalds 已提交
338 339
	       (buf[1] & 0x80) ? "high (inactive)" : "low (active)");

340 341 342 343
	tda9887_info("write: byte C 0x%02x\n",buf[2]);
	tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
	tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
	tda9887_info("  C7   audio gain      : %s\n",
L
Linus Torvalds 已提交
344 345
	       (buf[2] & 0x80) ? "-6" : "0");

346 347
	tda9887_info("write: byte E 0x%02x\n",buf[3]);
	tda9887_info("  E0-1 sound carrier   : %s\n",
L
Linus Torvalds 已提交
348
	       carrier[(buf[3] & 0x03)]);
349
	tda9887_info("  E6   l pll gating   : %s\n",
L
Linus Torvalds 已提交
350 351 352 353
	       (buf[3] & 0x40) ? "36" : "13");

	if (buf[1] & 0x08) {
		/* radio */
354
		tda9887_info("  E2-4 video if        : %s\n",
L
Linus Torvalds 已提交
355
		       rif[(buf[3] & 0x0c) >> 2]);
356
		tda9887_info("  E7   vif agc output  : %s\n",
L
Linus Torvalds 已提交
357 358 359 360 361
		       (buf[3] & 0x80)
		       ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
		       : "fm radio carrier afc");
	} else {
		/* video */
362
		tda9887_info("  E2-4 video if        : %s\n",
L
Linus Torvalds 已提交
363
		       vif[(buf[3] & 0x1c) >> 2]);
364
		tda9887_info("  E5   tuner gain      : %s\n",
L
Linus Torvalds 已提交
365 366 367
		       (buf[3] & 0x80)
		       ? ((buf[3] & 0x20) ? "external" : "normal")
		       : ((buf[3] & 0x20) ? "minimum"  : "normal"));
368
		tda9887_info("  E7   vif agc output  : %s\n",
L
Linus Torvalds 已提交
369 370 371 372 373 374
		       (buf[3] & 0x80)
		       ? ((buf[3] & 0x20)
			  ? "pin3 port, pin22 vif agc out"
			  : "pin22 port, pin3 vif acg ext in")
		       : "pin3+pin22 port");
	}
375
	tda9887_info("--\n");
L
Linus Torvalds 已提交
376 377 378 379
}

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

380
static int tda9887_set_tvnorm(struct tuner *t, char *buf)
L
Linus Torvalds 已提交
381 382 383 384
{
	struct tvnorm *norm = NULL;
	int i;

385 386
	if (t->mode == V4L2_TUNER_RADIO) {
		if (t->audmode == V4L2_TUNER_MODE_MONO)
387 388
			norm = &radio_mono;
		else
389
			norm = &radio_stereo;
L
Linus Torvalds 已提交
390 391 392 393 394 395 396 397 398
	} else {
		for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
			if (tvnorms[i].std & t->std) {
				norm = tvnorms+i;
				break;
			}
		}
	}
	if (NULL == norm) {
399
		tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
L
Linus Torvalds 已提交
400 401 402
		return -1;
	}

403
	tda9887_dbg("configure for: %s\n",norm->name);
L
Linus Torvalds 已提交
404 405 406 407 408 409 410 411 412
	buf[1] = norm->b;
	buf[2] = norm->c;
	buf[3] = norm->e;
	return 0;
}

static unsigned int port1  = UNSET;
static unsigned int port2  = UNSET;
static unsigned int qss    = UNSET;
413 414
static unsigned int adjust = UNSET;

L
Linus Torvalds 已提交
415 416 417 418 419
module_param(port1, int, 0644);
module_param(port2, int, 0644);
module_param(qss, int, 0644);
module_param(adjust, int, 0644);

420
static int tda9887_set_insmod(struct tuner *t, char *buf)
L
Linus Torvalds 已提交
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
{
	if (UNSET != port1) {
		if (port1)
			buf[1] |= cOutputPort1Inactive;
		else
			buf[1] &= ~cOutputPort1Inactive;
	}
	if (UNSET != port2) {
		if (port2)
			buf[1] |= cOutputPort2Inactive;
		else
			buf[1] &= ~cOutputPort2Inactive;
	}

	if (UNSET != qss) {
		if (qss)
			buf[1] |= cQSS;
		else
			buf[1] &= ~cQSS;
	}

442 443
	if (adjust >= 0x00 && adjust < 0x20) {
		buf[2] &= ~cTopMask;
L
Linus Torvalds 已提交
444
		buf[2] |= adjust;
445
	}
L
Linus Torvalds 已提交
446 447 448
	return 0;
}

449
static int tda9887_set_config(struct tuner *t, char *buf)
L
Linus Torvalds 已提交
450
{
451
	if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
L
Linus Torvalds 已提交
452
		buf[1] &= ~cOutputPort1Inactive;
453
	if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
L
Linus Torvalds 已提交
454
		buf[1] |= cOutputPort1Inactive;
455
	if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
L
Linus Torvalds 已提交
456
		buf[1] &= ~cOutputPort2Inactive;
457
	if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
L
Linus Torvalds 已提交
458 459
		buf[1] |= cOutputPort2Inactive;

460
	if (t->tda9887_config & TDA9887_QSS)
L
Linus Torvalds 已提交
461
		buf[1] |= cQSS;
462
	if (t->tda9887_config & TDA9887_INTERCARRIER)
L
Linus Torvalds 已提交
463 464
		buf[1] &= ~cQSS;

465
	if (t->tda9887_config & TDA9887_AUTOMUTE)
L
Linus Torvalds 已提交
466
		buf[1] |= cAutoMuteFmActive;
467
	if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
L
Linus Torvalds 已提交
468
		buf[2] &= ~0x60;
469
		switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
L
Linus Torvalds 已提交
470 471 472 473 474 475 476 477 478 479 480
		case TDA9887_DEEMPHASIS_NONE:
			buf[2] |= cDeemphasisOFF;
			break;
		case TDA9887_DEEMPHASIS_50:
			buf[2] |= cDeemphasisON | cDeemphasis50;
			break;
		case TDA9887_DEEMPHASIS_75:
			buf[2] |= cDeemphasisON | cDeemphasis75;
			break;
		}
	}
481
	if (t->tda9887_config & TDA9887_TOP_SET) {
482
		buf[2] &= ~cTopMask;
483
		buf[2] |= (t->tda9887_config >> 8) & cTopMask;
484
	}
485
	if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
486
		buf[1] &= ~cQSS;
487 488
	if (t->tda9887_config & TDA9887_GATING_18)
		buf[3] &= ~cGating_36;
489 490 491 492 493 494

	if (t->tda9887_config & TDA9887_GAIN_NORMAL) {
		radio_stereo.e &= ~cTunerGainLow;
		radio_mono.e &= ~cTunerGainLow;
	}

L
Linus Torvalds 已提交
495 496 497 498 499
	return 0;
}

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

500
static int tda9887_status(struct tuner *t)
L
Linus Torvalds 已提交
501 502 503 504 505
{
	unsigned char buf[1];
	int rc;

	memset(buf,0,sizeof(buf));
506
	if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
507
		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
508
	dump_read_message(t, buf);
L
Linus Torvalds 已提交
509 510 511
	return 0;
}

512
static void tda9887_configure(struct i2c_client *client)
L
Linus Torvalds 已提交
513
{
514
	struct tuner *t = i2c_get_clientdata(client);
515
	struct tda9887_priv *priv = t->priv;
L
Linus Torvalds 已提交
516 517
	int rc;

518 519
	memset(priv->data,0,sizeof(priv->data));
	tda9887_set_tvnorm(t,priv->data);
520

521 522 523 524 525 526 527 528 529 530 531 532 533
	/* A note on the port settings:
	   These settings tend to depend on the specifics of the board.
	   By default they are set to inactive (bit value 1) by this driver,
	   overwriting any changes made by the tvnorm. This means that it
	   is the responsibility of the module using the tda9887 to set
	   these values in case of changes in the tvnorm.
	   In many cases port 2 should be made active (0) when selecting
	   SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.

	   For the other standards the tda9887 application note says that
	   the ports should be set to active (0), but, again, that may
	   differ depending on the precise hardware configuration.
	 */
534 535
	priv->data[1] |= cOutputPort1Inactive;
	priv->data[1] |= cOutputPort2Inactive;
536

537 538
	tda9887_set_config(t,priv->data);
	tda9887_set_insmod(t,priv->data);
L
Linus Torvalds 已提交
539

540
	if (t->mode == T_STANDBY) {
541
		priv->data[1] |= cForcedMuteAudioON;
542 543
	}

544
	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
545
		priv->data[1],priv->data[2],priv->data[3]);
546
	if (tuner_debug > 1)
547
		dump_write_message(t, priv->data);
L
Linus Torvalds 已提交
548

549
	if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4)))
550
		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
L
Linus Torvalds 已提交
551

552
	if (tuner_debug > 2) {
L
Linus Torvalds 已提交
553 554 555 556 557 558 559
		msleep_interruptible(1000);
		tda9887_status(t);
	}
}

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

560
static void tda9887_tuner_status(struct i2c_client *client)
L
Linus Torvalds 已提交
561
{
562
	struct tuner *t = i2c_get_clientdata(client);
563 564
	struct tda9887_priv *priv = t->priv;
	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
L
Linus Torvalds 已提交
565 566
}

567
static int tda9887_get_afc(struct i2c_client *client)
L
Linus Torvalds 已提交
568
{
569 570 571 572 573 574 575 576 577
	struct tuner *t = i2c_get_clientdata(client);
	static int AFC_BITS_2_kHz[] = {
		-12500,  -37500,  -62500,  -97500,
		-112500, -137500, -162500, -187500,
		187500,  162500,  137500,  112500,
		97500 ,  62500,   37500 ,  12500
	};
	int afc=0;
	__u8 reg = 0;
L
Linus Torvalds 已提交
578

579 580
	if (1 == i2c_master_recv(&t->i2c,&reg,1))
		afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
L
Linus Torvalds 已提交
581

582
	return afc;
L
Linus Torvalds 已提交
583 584
}

585
static void tda9887_standby(struct i2c_client *client)
L
Linus Torvalds 已提交
586
{
587
	tda9887_configure(client);
L
Linus Torvalds 已提交
588 589
}

590
static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
L
Linus Torvalds 已提交
591
{
592
	tda9887_configure(client);
L
Linus Torvalds 已提交
593 594
}

595 596 597 598 599 600 601 602
static void tda9887_release(struct i2c_client *c)
{
	struct tuner *t = i2c_get_clientdata(c);

	kfree(t->priv);
	t->priv = NULL;
}

603 604 605 606 607 608 609 610 611
static struct tuner_operations tda9887_tuner_ops = {
	.set_tv_freq    = tda9887_set_freq,
	.set_radio_freq = tda9887_set_freq,
	.standby        = tda9887_standby,
	.tuner_status   = tda9887_tuner_status,
	.get_afc        = tda9887_get_afc,
	.release        = tda9887_release,
};

612
int tda9887_tuner_init(struct i2c_client *c)
L
Linus Torvalds 已提交
613
{
614
	struct tda9887_priv *priv = NULL;
615
	struct tuner *t = i2c_get_clientdata(c);
L
Linus Torvalds 已提交
616

617 618 619 620 621
	priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
	if (priv == NULL)
		return -ENOMEM;
	t->priv = priv;

622
	strlcpy(c->name, "tda9887", sizeof(c->name));
L
Linus Torvalds 已提交
623

624 625
	tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
						t->i2c.driver->driver.name);
L
Linus Torvalds 已提交
626

627
	memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
L
Linus Torvalds 已提交
628

629
	return 0;
L
Linus Torvalds 已提交
630 631 632 633 634 635 636 637 638
}

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