xref: /openbmc/linux/drivers/media/tuners/fc0013.c (revision 3a0e75ad)
1 /*
2  * Fitipower FC0013 tuner driver
3  *
4  * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
5  * partially based on driver code from Fitipower
6  * Copyright (C) 2010 Fitipower Integrated Technology Inc
7  *
8  *    This program is free software; you can redistribute it and/or modify
9  *    it under the terms of the GNU General Public License as published by
10  *    the Free Software Foundation; either version 2 of the License, or
11  *    (at your option) any later version.
12  *
13  *    This program is distributed in the hope that it will be useful,
14  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *    GNU General Public License for more details.
17  *
18  */
19 
20 #include "fc0013.h"
21 #include "fc0013-priv.h"
22 
23 static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val)
24 {
25 	u8 buf[2] = {reg, val};
26 	struct i2c_msg msg = {
27 		.addr = priv->addr, .flags = 0, .buf = buf, .len = 2
28 	};
29 
30 	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
31 		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
32 		return -EREMOTEIO;
33 	}
34 	return 0;
35 }
36 
37 static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val)
38 {
39 	struct i2c_msg msg[2] = {
40 		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
41 		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
42 	};
43 
44 	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
45 		err("I2C read reg failed, reg: %02x", reg);
46 		return -EREMOTEIO;
47 	}
48 	return 0;
49 }
50 
51 static void fc0013_release(struct dvb_frontend *fe)
52 {
53 	kfree(fe->tuner_priv);
54 	fe->tuner_priv = NULL;
55 }
56 
57 static int fc0013_init(struct dvb_frontend *fe)
58 {
59 	struct fc0013_priv *priv = fe->tuner_priv;
60 	int i, ret = 0;
61 	unsigned char reg[] = {
62 		0x00,	/* reg. 0x00: dummy */
63 		0x09,	/* reg. 0x01 */
64 		0x16,	/* reg. 0x02 */
65 		0x00,	/* reg. 0x03 */
66 		0x00,	/* reg. 0x04 */
67 		0x17,	/* reg. 0x05 */
68 		0x02,	/* reg. 0x06 */
69 		0x0a,	/* reg. 0x07: CHECK */
70 		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
71 			   Loop Bw 1/8 */
72 		0x6f,	/* reg. 0x09: enable LoopThrough */
73 		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
74 		0x82,	/* reg. 0x0b: CHECK */
75 		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
76 		0x01,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */
77 		0x00,	/* reg. 0x0e */
78 		0x00,	/* reg. 0x0f */
79 		0x00,	/* reg. 0x10 */
80 		0x00,	/* reg. 0x11 */
81 		0x00,	/* reg. 0x12 */
82 		0x00,	/* reg. 0x13 */
83 		0x50,	/* reg. 0x14: DVB-t High Gain, UHF.
84 			   Middle Gain: 0x48, Low Gain: 0x40 */
85 		0x01,	/* reg. 0x15 */
86 	};
87 
88 	switch (priv->xtal_freq) {
89 	case FC_XTAL_27_MHZ:
90 	case FC_XTAL_28_8_MHZ:
91 		reg[0x07] |= 0x20;
92 		break;
93 	case FC_XTAL_36_MHZ:
94 	default:
95 		break;
96 	}
97 
98 	if (priv->dual_master)
99 		reg[0x0c] |= 0x02;
100 
101 	if (fe->ops.i2c_gate_ctrl)
102 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
103 
104 	for (i = 1; i < sizeof(reg); i++) {
105 		ret = fc0013_writereg(priv, i, reg[i]);
106 		if (ret)
107 			break;
108 	}
109 
110 	if (fe->ops.i2c_gate_ctrl)
111 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
112 
113 	if (ret)
114 		err("fc0013_writereg failed: %d", ret);
115 
116 	return ret;
117 }
118 
119 static int fc0013_sleep(struct dvb_frontend *fe)
120 {
121 	/* nothing to do here */
122 	return 0;
123 }
124 
125 int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
126 {
127 	struct fc0013_priv *priv = fe->tuner_priv;
128 	int ret;
129 	u8 rc_cal;
130 	int val;
131 
132 	if (fe->ops.i2c_gate_ctrl)
133 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
134 
135 	/* push rc_cal value, get rc_cal value */
136 	ret = fc0013_writereg(priv, 0x10, 0x00);
137 	if (ret)
138 		goto error_out;
139 
140 	/* get rc_cal value */
141 	ret = fc0013_readreg(priv, 0x10, &rc_cal);
142 	if (ret)
143 		goto error_out;
144 
145 	rc_cal &= 0x0f;
146 
147 	val = (int)rc_cal + rc_val;
148 
149 	/* forcing rc_cal */
150 	ret = fc0013_writereg(priv, 0x0d, 0x11);
151 	if (ret)
152 		goto error_out;
153 
154 	/* modify rc_cal value */
155 	if (val > 15)
156 		ret = fc0013_writereg(priv, 0x10, 0x0f);
157 	else if (val < 0)
158 		ret = fc0013_writereg(priv, 0x10, 0x00);
159 	else
160 		ret = fc0013_writereg(priv, 0x10, (u8)val);
161 
162 error_out:
163 	if (fe->ops.i2c_gate_ctrl)
164 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
165 
166 	return ret;
167 }
168 EXPORT_SYMBOL(fc0013_rc_cal_add);
169 
170 int fc0013_rc_cal_reset(struct dvb_frontend *fe)
171 {
172 	struct fc0013_priv *priv = fe->tuner_priv;
173 	int ret;
174 
175 	if (fe->ops.i2c_gate_ctrl)
176 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
177 
178 	ret = fc0013_writereg(priv, 0x0d, 0x01);
179 	if (!ret)
180 		ret = fc0013_writereg(priv, 0x10, 0x00);
181 
182 	if (fe->ops.i2c_gate_ctrl)
183 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
184 
185 	return ret;
186 }
187 EXPORT_SYMBOL(fc0013_rc_cal_reset);
188 
189 static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq)
190 {
191 	int ret;
192 	u8 tmp;
193 
194 	ret = fc0013_readreg(priv, 0x1d, &tmp);
195 	if (ret)
196 		goto error_out;
197 	tmp &= 0xe3;
198 	if (freq <= 177500) {		/* VHF Track: 7 */
199 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
200 	} else if (freq <= 184500) {	/* VHF Track: 6 */
201 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x18);
202 	} else if (freq <= 191500) {	/* VHF Track: 5 */
203 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x14);
204 	} else if (freq <= 198500) {	/* VHF Track: 4 */
205 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x10);
206 	} else if (freq <= 205500) {	/* VHF Track: 3 */
207 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c);
208 	} else if (freq <= 219500) {	/* VHF Track: 2 */
209 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x08);
210 	} else if (freq < 300000) {	/* VHF Track: 1 */
211 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x04);
212 	} else {			/* UHF and GPS */
213 		ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
214 	}
215 error_out:
216 	return ret;
217 }
218 
219 static int fc0013_set_params(struct dvb_frontend *fe)
220 {
221 	struct fc0013_priv *priv = fe->tuner_priv;
222 	int i, ret = 0;
223 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
224 	u32 freq = p->frequency / 1000;
225 	u32 delsys = p->delivery_system;
226 	unsigned char reg[7], am, pm, multi, tmp;
227 	unsigned long f_vco;
228 	unsigned short xtal_freq_khz_2, xin, xdiv;
229 	bool vco_select = false;
230 
231 	if (fe->callback) {
232 		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
233 			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
234 		if (ret)
235 			goto exit;
236 	}
237 
238 	switch (priv->xtal_freq) {
239 	case FC_XTAL_27_MHZ:
240 		xtal_freq_khz_2 = 27000 / 2;
241 		break;
242 	case FC_XTAL_36_MHZ:
243 		xtal_freq_khz_2 = 36000 / 2;
244 		break;
245 	case FC_XTAL_28_8_MHZ:
246 	default:
247 		xtal_freq_khz_2 = 28800 / 2;
248 		break;
249 	}
250 
251 	if (fe->ops.i2c_gate_ctrl)
252 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
253 
254 	/* set VHF track */
255 	ret = fc0013_set_vhf_track(priv, freq);
256 	if (ret)
257 		goto exit;
258 
259 	if (freq < 300000) {
260 		/* enable VHF filter */
261 		ret = fc0013_readreg(priv, 0x07, &tmp);
262 		if (ret)
263 			goto exit;
264 		ret = fc0013_writereg(priv, 0x07, tmp | 0x10);
265 		if (ret)
266 			goto exit;
267 
268 		/* disable UHF & disable GPS */
269 		ret = fc0013_readreg(priv, 0x14, &tmp);
270 		if (ret)
271 			goto exit;
272 		ret = fc0013_writereg(priv, 0x14, tmp & 0x1f);
273 		if (ret)
274 			goto exit;
275 	} else if (freq <= 862000) {
276 		/* disable VHF filter */
277 		ret = fc0013_readreg(priv, 0x07, &tmp);
278 		if (ret)
279 			goto exit;
280 		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
281 		if (ret)
282 			goto exit;
283 
284 		/* enable UHF & disable GPS */
285 		ret = fc0013_readreg(priv, 0x14, &tmp);
286 		if (ret)
287 			goto exit;
288 		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40);
289 		if (ret)
290 			goto exit;
291 	} else {
292 		/* disable VHF filter */
293 		ret = fc0013_readreg(priv, 0x07, &tmp);
294 		if (ret)
295 			goto exit;
296 		ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
297 		if (ret)
298 			goto exit;
299 
300 		/* disable UHF & enable GPS */
301 		ret = fc0013_readreg(priv, 0x14, &tmp);
302 		if (ret)
303 			goto exit;
304 		ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20);
305 		if (ret)
306 			goto exit;
307 	}
308 
309 	/* select frequency divider and the frequency of VCO */
310 	if (freq < 37084) {		/* freq * 96 < 3560000 */
311 		multi = 96;
312 		reg[5] = 0x82;
313 		reg[6] = 0x00;
314 	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
315 		multi = 64;
316 		reg[5] = 0x02;
317 		reg[6] = 0x02;
318 	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
319 		multi = 48;
320 		reg[5] = 0x42;
321 		reg[6] = 0x00;
322 	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
323 		multi = 32;
324 		reg[5] = 0x82;
325 		reg[6] = 0x02;
326 	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
327 		multi = 24;
328 		reg[5] = 0x22;
329 		reg[6] = 0x00;
330 	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
331 		multi = 16;
332 		reg[5] = 0x42;
333 		reg[6] = 0x02;
334 	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
335 		multi = 12;
336 		reg[5] = 0x12;
337 		reg[6] = 0x00;
338 	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
339 		multi = 8;
340 		reg[5] = 0x22;
341 		reg[6] = 0x02;
342 	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
343 		multi = 6;
344 		reg[5] = 0x0a;
345 		reg[6] = 0x00;
346 	} else if (freq < 950000) {	/* freq * 4 < 3800000 */
347 		multi = 4;
348 		reg[5] = 0x12;
349 		reg[6] = 0x02;
350 	} else {
351 		multi = 2;
352 		reg[5] = 0x0a;
353 		reg[6] = 0x02;
354 	}
355 
356 	f_vco = freq * multi;
357 
358 	if (f_vco >= 3060000) {
359 		reg[6] |= 0x08;
360 		vco_select = true;
361 	}
362 
363 	if (freq >= 45000) {
364 		/* From divided value (XDIV) determined the FA and FP value */
365 		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
366 		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
367 			xdiv++;
368 
369 		pm = (unsigned char)(xdiv / 8);
370 		am = (unsigned char)(xdiv - (8 * pm));
371 
372 		if (am < 2) {
373 			reg[1] = am + 8;
374 			reg[2] = pm - 1;
375 		} else {
376 			reg[1] = am;
377 			reg[2] = pm;
378 		}
379 	} else {
380 		/* fix for frequency less than 45 MHz */
381 		reg[1] = 0x06;
382 		reg[2] = 0x11;
383 	}
384 
385 	/* fix clock out */
386 	reg[6] |= 0x20;
387 
388 	/* From VCO frequency determines the XIN ( fractional part of Delta
389 	   Sigma PLL) and divided value (XDIV) */
390 	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
391 	xin = (xin << 15) / xtal_freq_khz_2;
392 	if (xin >= 16384)
393 		xin += 32768;
394 
395 	reg[3] = xin >> 8;
396 	reg[4] = xin & 0xff;
397 
398 	if (delsys == SYS_DVBT) {
399 		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
400 		switch (p->bandwidth_hz) {
401 		case 6000000:
402 			reg[6] |= 0x80;
403 			break;
404 		case 7000000:
405 			reg[6] |= 0x40;
406 			break;
407 		case 8000000:
408 		default:
409 			break;
410 		}
411 	} else {
412 		err("%s: modulation type not supported!", __func__);
413 		return -EINVAL;
414 	}
415 
416 	/* modified for Realtek demod */
417 	reg[5] |= 0x07;
418 
419 	for (i = 1; i <= 6; i++) {
420 		ret = fc0013_writereg(priv, i, reg[i]);
421 		if (ret)
422 			goto exit;
423 	}
424 
425 	ret = fc0013_readreg(priv, 0x11, &tmp);
426 	if (ret)
427 		goto exit;
428 	if (multi == 64)
429 		ret = fc0013_writereg(priv, 0x11, tmp | 0x04);
430 	else
431 		ret = fc0013_writereg(priv, 0x11, tmp & 0xfb);
432 	if (ret)
433 		goto exit;
434 
435 	/* VCO Calibration */
436 	ret = fc0013_writereg(priv, 0x0e, 0x80);
437 	if (!ret)
438 		ret = fc0013_writereg(priv, 0x0e, 0x00);
439 
440 	/* VCO Re-Calibration if needed */
441 	if (!ret)
442 		ret = fc0013_writereg(priv, 0x0e, 0x00);
443 
444 	if (!ret) {
445 		msleep(10);
446 		ret = fc0013_readreg(priv, 0x0e, &tmp);
447 	}
448 	if (ret)
449 		goto exit;
450 
451 	/* vco selection */
452 	tmp &= 0x3f;
453 
454 	if (vco_select) {
455 		if (tmp > 0x3c) {
456 			reg[6] &= ~0x08;
457 			ret = fc0013_writereg(priv, 0x06, reg[6]);
458 			if (!ret)
459 				ret = fc0013_writereg(priv, 0x0e, 0x80);
460 			if (!ret)
461 				ret = fc0013_writereg(priv, 0x0e, 0x00);
462 		}
463 	} else {
464 		if (tmp < 0x02) {
465 			reg[6] |= 0x08;
466 			ret = fc0013_writereg(priv, 0x06, reg[6]);
467 			if (!ret)
468 				ret = fc0013_writereg(priv, 0x0e, 0x80);
469 			if (!ret)
470 				ret = fc0013_writereg(priv, 0x0e, 0x00);
471 		}
472 	}
473 
474 	priv->frequency = p->frequency;
475 	priv->bandwidth = p->bandwidth_hz;
476 
477 exit:
478 	if (fe->ops.i2c_gate_ctrl)
479 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
480 	if (ret)
481 		warn("%s: failed: %d", __func__, ret);
482 	return ret;
483 }
484 
485 static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency)
486 {
487 	struct fc0013_priv *priv = fe->tuner_priv;
488 	*frequency = priv->frequency;
489 	return 0;
490 }
491 
492 static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
493 {
494 	/* always ? */
495 	*frequency = 0;
496 	return 0;
497 }
498 
499 static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
500 {
501 	struct fc0013_priv *priv = fe->tuner_priv;
502 	*bandwidth = priv->bandwidth;
503 	return 0;
504 }
505 
506 #define INPUT_ADC_LEVEL	-8
507 
508 static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
509 {
510 	struct fc0013_priv *priv = fe->tuner_priv;
511 	int ret;
512 	unsigned char tmp;
513 	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
514 	const int fc0013_lna_gain_table[] = {
515 		/* low gain */
516 		-63, -58, -99, -73,
517 		-63, -65, -54, -60,
518 		/* middle gain */
519 		 71,  70,  68,  67,
520 		 65,  63,  61,  58,
521 		/* high gain */
522 		197, 191, 188, 186,
523 		184, 182, 181, 179,
524 	};
525 
526 	if (fe->ops.i2c_gate_ctrl)
527 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
528 
529 	ret = fc0013_writereg(priv, 0x13, 0x00);
530 	if (ret)
531 		goto err;
532 
533 	ret = fc0013_readreg(priv, 0x13, &tmp);
534 	if (ret)
535 		goto err;
536 	int_temp = tmp;
537 
538 	ret = fc0013_readreg(priv, 0x14, &tmp);
539 	if (ret)
540 		goto err;
541 	lna_gain = tmp & 0x1f;
542 
543 	if (fe->ops.i2c_gate_ctrl)
544 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
545 
546 	if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) {
547 		int_lna = fc0013_lna_gain_table[lna_gain];
548 		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
549 				(int_temp & 0x1f)) * 2;
550 		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
551 
552 		if (power >= 45)
553 			*strength = 255;	/* 100% */
554 		else if (power < -95)
555 			*strength = 0;
556 		else
557 			*strength = (power + 95) * 255 / 140;
558 
559 		*strength |= *strength << 8;
560 	} else {
561 		ret = -1;
562 	}
563 
564 	goto exit;
565 
566 err:
567 	if (fe->ops.i2c_gate_ctrl)
568 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
569 exit:
570 	if (ret)
571 		warn("%s: failed: %d", __func__, ret);
572 	return ret;
573 }
574 
575 static const struct dvb_tuner_ops fc0013_tuner_ops = {
576 	.info = {
577 		.name		= "Fitipower FC0013",
578 
579 		.frequency_min	= 37000000,	/* estimate */
580 		.frequency_max	= 1680000000,	/* CHECK */
581 		.frequency_step	= 0,
582 	},
583 
584 	.release	= fc0013_release,
585 
586 	.init		= fc0013_init,
587 	.sleep		= fc0013_sleep,
588 
589 	.set_params	= fc0013_set_params,
590 
591 	.get_frequency	= fc0013_get_frequency,
592 	.get_if_frequency = fc0013_get_if_frequency,
593 	.get_bandwidth	= fc0013_get_bandwidth,
594 
595 	.get_rf_strength = fc0013_get_rf_strength,
596 };
597 
598 struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
599 	struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
600 	enum fc001x_xtal_freq xtal_freq)
601 {
602 	struct fc0013_priv *priv = NULL;
603 
604 	priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL);
605 	if (priv == NULL)
606 		return NULL;
607 
608 	priv->i2c = i2c;
609 	priv->dual_master = dual_master;
610 	priv->addr = i2c_address;
611 	priv->xtal_freq = xtal_freq;
612 
613 	info("Fitipower FC0013 successfully attached.");
614 
615 	fe->tuner_priv = priv;
616 
617 	memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops,
618 		sizeof(struct dvb_tuner_ops));
619 
620 	return fe;
621 }
622 EXPORT_SYMBOL(fc0013_attach);
623 
624 MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver");
625 MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
626 MODULE_LICENSE("GPL");
627 MODULE_VERSION("0.2");
628