tda9887.c 15.9 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 14
#include <media/tuner.h>

15

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

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

24
#define tda9887_info(fmt, arg...) do {\
25
	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
26 27 28
			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
#define tda9887_dbg(fmt, arg...) do {\
	if (tuner_debug) \
29
		printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
30
			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
L
Linus Torvalds 已提交
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85


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

#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

86
#define cTopMask                0x1f    // bit c0:4
87
#define cTopDefault		0x10 	// bit c0:4
L
Linus Torvalds 已提交
88 89 90 91 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

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

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

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

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

252
static void dump_read_message(struct tuner *t, unsigned char *buf)
L
Linus Torvalds 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
{
	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",
	};
272 273 274 275 276 277
	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 已提交
278 279
}

280
static void dump_write_message(struct tuner *t, unsigned char *buf)
L
Linus Torvalds 已提交
281 282 283 284 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
{
	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",
	};

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

336 337 338 339
	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 已提交
340 341
	       (buf[2] & 0x80) ? "-6" : "0");

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

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

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

376
static int tda9887_set_tvnorm(struct tuner *t, char *buf)
L
Linus Torvalds 已提交
377 378 379 380
{
	struct tvnorm *norm = NULL;
	int i;

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

399
	tda9887_dbg("configure for: %s\n",norm->name);
L
Linus Torvalds 已提交
400 401 402 403 404 405 406 407 408
	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;
409 410
static unsigned int adjust = UNSET;

L
Linus Torvalds 已提交
411 412 413 414 415
module_param(port1, int, 0644);
module_param(port2, int, 0644);
module_param(qss, int, 0644);
module_param(adjust, int, 0644);

416
static int tda9887_set_insmod(struct tuner *t, char *buf)
L
Linus Torvalds 已提交
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
{
	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;
	}

438 439
	if (adjust >= 0x00 && adjust < 0x20) {
		buf[2] &= ~cTopMask;
L
Linus Torvalds 已提交
440
		buf[2] |= adjust;
441
	}
L
Linus Torvalds 已提交
442 443 444
	return 0;
}

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

456
	if (t->tda9887_config & TDA9887_QSS)
L
Linus Torvalds 已提交
457
		buf[1] |= cQSS;
458
	if (t->tda9887_config & TDA9887_INTERCARRIER)
L
Linus Torvalds 已提交
459 460
		buf[1] &= ~cQSS;

461
	if (t->tda9887_config & TDA9887_AUTOMUTE)
L
Linus Torvalds 已提交
462
		buf[1] |= cAutoMuteFmActive;
463
	if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
L
Linus Torvalds 已提交
464
		buf[2] &= ~0x60;
465
		switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
L
Linus Torvalds 已提交
466 467 468 469 470 471 472 473 474 475 476
		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;
		}
	}
477
	if (t->tda9887_config & TDA9887_TOP_SET) {
478
		buf[2] &= ~cTopMask;
479
		buf[2] |= (t->tda9887_config >> 8) & cTopMask;
480
	}
481
	if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
482
		buf[1] &= ~cQSS;
L
Linus Torvalds 已提交
483 484 485 486 487
	return 0;
}

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

488
static int tda9887_status(struct tuner *t)
L
Linus Torvalds 已提交
489 490 491 492 493
{
	unsigned char buf[1];
	int rc;

	memset(buf,0,sizeof(buf));
494
	if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
495
		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
496
	dump_read_message(t, buf);
L
Linus Torvalds 已提交
497 498 499
	return 0;
}

500
static void tda9887_configure(struct i2c_client *client)
L
Linus Torvalds 已提交
501
{
502
	struct tuner *t = i2c_get_clientdata(client);
L
Linus Torvalds 已提交
503 504
	int rc;

505 506
	memset(t->tda9887_data,0,sizeof(t->tda9887_data));
	tda9887_set_tvnorm(t,t->tda9887_data);
507

508 509 510 511 512 513 514 515 516 517 518 519 520
	/* 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.
	 */
521 522
	t->tda9887_data[1] |= cOutputPort1Inactive;
	t->tda9887_data[1] |= cOutputPort2Inactive;
523

524 525
	tda9887_set_config(t,t->tda9887_data);
	tda9887_set_insmod(t,t->tda9887_data);
L
Linus Torvalds 已提交
526

527
	if (t->mode == T_STANDBY) {
528
		t->tda9887_data[1] |= cForcedMuteAudioON;
529 530
	}

531
	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
532 533 534
		t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
	if (tuner_debug > 1)
		dump_write_message(t, t->tda9887_data);
L
Linus Torvalds 已提交
535

536
	if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
537
		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
L
Linus Torvalds 已提交
538

539
	if (tuner_debug > 2) {
L
Linus Torvalds 已提交
540 541 542 543 544 545 546
		msleep_interruptible(1000);
		tda9887_status(t);
	}
}

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

547
static void tda9887_tuner_status(struct i2c_client *client)
L
Linus Torvalds 已提交
548
{
549 550
	struct tuner *t = i2c_get_clientdata(client);
	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
L
Linus Torvalds 已提交
551 552
}

553
static int tda9887_get_afc(struct i2c_client *client)
L
Linus Torvalds 已提交
554
{
555 556 557 558 559 560 561 562 563
	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 已提交
564

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

568
	return afc;
L
Linus Torvalds 已提交
569 570
}

571
static void tda9887_standby(struct i2c_client *client)
L
Linus Torvalds 已提交
572
{
573
	tda9887_configure(client);
L
Linus Torvalds 已提交
574 575
}

576
static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
L
Linus Torvalds 已提交
577
{
578
	tda9887_configure(client);
L
Linus Torvalds 已提交
579 580
}

581
int tda9887_tuner_init(struct i2c_client *c)
L
Linus Torvalds 已提交
582
{
583
	struct tuner *t = i2c_get_clientdata(c);
L
Linus Torvalds 已提交
584

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

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

590 591 592 593 594
	t->set_tv_freq = tda9887_set_freq;
	t->set_radio_freq = tda9887_set_freq;
	t->standby = tda9887_standby;
	t->tuner_status=tda9887_tuner_status;
	t->get_afc=tda9887_get_afc;
L
Linus Torvalds 已提交
595

596
	return 0;
L
Linus Torvalds 已提交
597 598 599 600 601 602 603 604 605
}

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