xref: /openbmc/linux/drivers/media/tuners/fc0012.c (revision 3a83e4e6)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Fitipower FC0012 tuner driver
4  *
5  * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
6  */
7 
8 #include "fc0012.h"
9 #include "fc0012-priv.h"
10 
11 static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
12 {
13 	u8 buf[2] = {reg, val};
14 	struct i2c_msg msg = {
15 		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
16 	};
17 
18 	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
19 		dev_err(&priv->i2c->dev,
20 			"%s: I2C write reg failed, reg: %02x, val: %02x\n",
21 			KBUILD_MODNAME, reg, val);
22 		return -EREMOTEIO;
23 	}
24 	return 0;
25 }
26 
27 static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
28 {
29 	struct i2c_msg msg[2] = {
30 		{ .addr = priv->cfg->i2c_address, .flags = 0,
31 			.buf = &reg, .len = 1 },
32 		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
33 			.buf = val, .len = 1 },
34 	};
35 
36 	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
37 		dev_err(&priv->i2c->dev,
38 			"%s: I2C read reg failed, reg: %02x\n",
39 			KBUILD_MODNAME, reg);
40 		return -EREMOTEIO;
41 	}
42 	return 0;
43 }
44 
45 static void fc0012_release(struct dvb_frontend *fe)
46 {
47 	kfree(fe->tuner_priv);
48 	fe->tuner_priv = NULL;
49 }
50 
51 static int fc0012_init(struct dvb_frontend *fe)
52 {
53 	struct fc0012_priv *priv = fe->tuner_priv;
54 	int i, ret = 0;
55 	unsigned char reg[] = {
56 		0x00,	/* dummy reg. 0 */
57 		0x05,	/* reg. 0x01 */
58 		0x10,	/* reg. 0x02 */
59 		0x00,	/* reg. 0x03 */
60 		0x00,	/* reg. 0x04 */
61 		0x0f,	/* reg. 0x05: may also be 0x0a */
62 		0x00,	/* reg. 0x06: divider 2, VCO slow */
63 		0x00,	/* reg. 0x07: may also be 0x0f */
64 		0xff,	/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
65 			   Loop Bw 1/8 */
66 		0x6e,	/* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
67 		0xb8,	/* reg. 0x0a: Disable LO Test Buffer */
68 		0x82,	/* reg. 0x0b: Output Clock is same as clock frequency,
69 			   may also be 0x83 */
70 		0xfc,	/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
71 		0x02,	/* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
72 		0x00,	/* reg. 0x0e */
73 		0x00,	/* reg. 0x0f */
74 		0x00,	/* reg. 0x10: may also be 0x0d */
75 		0x00,	/* reg. 0x11 */
76 		0x1f,	/* reg. 0x12: Set to maximum gain */
77 		0x08,	/* reg. 0x13: Set to Middle Gain: 0x08,
78 			   Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
79 		0x00,	/* reg. 0x14 */
80 		0x04,	/* reg. 0x15: Enable LNA COMPS */
81 	};
82 
83 	switch (priv->cfg->xtal_freq) {
84 	case FC_XTAL_27_MHZ:
85 	case FC_XTAL_28_8_MHZ:
86 		reg[0x07] |= 0x20;
87 		break;
88 	case FC_XTAL_36_MHZ:
89 	default:
90 		break;
91 	}
92 
93 	if (priv->cfg->dual_master)
94 		reg[0x0c] |= 0x02;
95 
96 	if (priv->cfg->loop_through)
97 		reg[0x09] |= 0x01;
98 
99 	if (fe->ops.i2c_gate_ctrl)
100 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
101 
102 	for (i = 1; i < sizeof(reg); i++) {
103 		ret = fc0012_writereg(priv, i, reg[i]);
104 		if (ret)
105 			break;
106 	}
107 
108 	if (fe->ops.i2c_gate_ctrl)
109 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
110 
111 	if (ret)
112 		dev_err(&priv->i2c->dev, "%s: fc0012_writereg failed: %d\n",
113 				KBUILD_MODNAME, ret);
114 
115 	return ret;
116 }
117 
118 static int fc0012_set_params(struct dvb_frontend *fe)
119 {
120 	struct fc0012_priv *priv = fe->tuner_priv;
121 	int i, ret = 0;
122 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
123 	u32 freq = p->frequency / 1000;
124 	u32 delsys = p->delivery_system;
125 	unsigned char reg[7], am, pm, multi, tmp;
126 	unsigned long f_vco;
127 	unsigned short xtal_freq_khz_2, xin, xdiv;
128 	bool vco_select = false;
129 
130 	if (fe->callback) {
131 		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
132 			FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
133 		if (ret)
134 			goto exit;
135 	}
136 
137 	switch (priv->cfg->xtal_freq) {
138 	case FC_XTAL_27_MHZ:
139 		xtal_freq_khz_2 = 27000 / 2;
140 		break;
141 	case FC_XTAL_36_MHZ:
142 		xtal_freq_khz_2 = 36000 / 2;
143 		break;
144 	case FC_XTAL_28_8_MHZ:
145 	default:
146 		xtal_freq_khz_2 = 28800 / 2;
147 		break;
148 	}
149 
150 	/* select frequency divider and the frequency of VCO */
151 	if (freq < 37084) {		/* freq * 96 < 3560000 */
152 		multi = 96;
153 		reg[5] = 0x82;
154 		reg[6] = 0x00;
155 	} else if (freq < 55625) {	/* freq * 64 < 3560000 */
156 		multi = 64;
157 		reg[5] = 0x82;
158 		reg[6] = 0x02;
159 	} else if (freq < 74167) {	/* freq * 48 < 3560000 */
160 		multi = 48;
161 		reg[5] = 0x42;
162 		reg[6] = 0x00;
163 	} else if (freq < 111250) {	/* freq * 32 < 3560000 */
164 		multi = 32;
165 		reg[5] = 0x42;
166 		reg[6] = 0x02;
167 	} else if (freq < 148334) {	/* freq * 24 < 3560000 */
168 		multi = 24;
169 		reg[5] = 0x22;
170 		reg[6] = 0x00;
171 	} else if (freq < 222500) {	/* freq * 16 < 3560000 */
172 		multi = 16;
173 		reg[5] = 0x22;
174 		reg[6] = 0x02;
175 	} else if (freq < 296667) {	/* freq * 12 < 3560000 */
176 		multi = 12;
177 		reg[5] = 0x12;
178 		reg[6] = 0x00;
179 	} else if (freq < 445000) {	/* freq * 8 < 3560000 */
180 		multi = 8;
181 		reg[5] = 0x12;
182 		reg[6] = 0x02;
183 	} else if (freq < 593334) {	/* freq * 6 < 3560000 */
184 		multi = 6;
185 		reg[5] = 0x0a;
186 		reg[6] = 0x00;
187 	} else {
188 		multi = 4;
189 		reg[5] = 0x0a;
190 		reg[6] = 0x02;
191 	}
192 
193 	f_vco = freq * multi;
194 
195 	if (f_vco >= 3060000) {
196 		reg[6] |= 0x08;
197 		vco_select = true;
198 	}
199 
200 	if (freq >= 45000) {
201 		/* From divided value (XDIV) determined the FA and FP value */
202 		xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
203 		if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
204 			xdiv++;
205 
206 		pm = (unsigned char)(xdiv / 8);
207 		am = (unsigned char)(xdiv - (8 * pm));
208 
209 		if (am < 2) {
210 			reg[1] = am + 8;
211 			reg[2] = pm - 1;
212 		} else {
213 			reg[1] = am;
214 			reg[2] = pm;
215 		}
216 	} else {
217 		/* fix for frequency less than 45 MHz */
218 		reg[1] = 0x06;
219 		reg[2] = 0x11;
220 	}
221 
222 	/* fix clock out */
223 	reg[6] |= 0x20;
224 
225 	/* From VCO frequency determines the XIN ( fractional part of Delta
226 	   Sigma PLL) and divided value (XDIV) */
227 	xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
228 	xin = (xin << 15) / xtal_freq_khz_2;
229 	if (xin >= 16384)
230 		xin += 32768;
231 
232 	reg[3] = xin >> 8;	/* xin with 9 bit resolution */
233 	reg[4] = xin & 0xff;
234 
235 	if (delsys == SYS_DVBT) {
236 		reg[6] &= 0x3f;	/* bits 6 and 7 describe the bandwidth */
237 		switch (p->bandwidth_hz) {
238 		case 6000000:
239 			reg[6] |= 0x80;
240 			break;
241 		case 7000000:
242 			reg[6] |= 0x40;
243 			break;
244 		case 8000000:
245 		default:
246 			break;
247 		}
248 	} else {
249 		dev_err(&priv->i2c->dev, "%s: modulation type not supported!\n",
250 				KBUILD_MODNAME);
251 		return -EINVAL;
252 	}
253 
254 	/* modified for Realtek demod */
255 	reg[5] |= 0x07;
256 
257 	if (fe->ops.i2c_gate_ctrl)
258 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
259 
260 	for (i = 1; i <= 6; i++) {
261 		ret = fc0012_writereg(priv, i, reg[i]);
262 		if (ret)
263 			goto exit;
264 	}
265 
266 	/* VCO Calibration */
267 	ret = fc0012_writereg(priv, 0x0e, 0x80);
268 	if (!ret)
269 		ret = fc0012_writereg(priv, 0x0e, 0x00);
270 
271 	/* VCO Re-Calibration if needed */
272 	if (!ret)
273 		ret = fc0012_writereg(priv, 0x0e, 0x00);
274 
275 	if (!ret) {
276 		msleep(10);
277 		ret = fc0012_readreg(priv, 0x0e, &tmp);
278 	}
279 	if (ret)
280 		goto exit;
281 
282 	/* vco selection */
283 	tmp &= 0x3f;
284 
285 	if (vco_select) {
286 		if (tmp > 0x3c) {
287 			reg[6] &= ~0x08;
288 			ret = fc0012_writereg(priv, 0x06, reg[6]);
289 			if (!ret)
290 				ret = fc0012_writereg(priv, 0x0e, 0x80);
291 			if (!ret)
292 				ret = fc0012_writereg(priv, 0x0e, 0x00);
293 		}
294 	} else {
295 		if (tmp < 0x02) {
296 			reg[6] |= 0x08;
297 			ret = fc0012_writereg(priv, 0x06, reg[6]);
298 			if (!ret)
299 				ret = fc0012_writereg(priv, 0x0e, 0x80);
300 			if (!ret)
301 				ret = fc0012_writereg(priv, 0x0e, 0x00);
302 		}
303 	}
304 
305 	priv->frequency = p->frequency;
306 	priv->bandwidth = p->bandwidth_hz;
307 
308 exit:
309 	if (fe->ops.i2c_gate_ctrl)
310 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
311 	if (ret)
312 		dev_warn(&priv->i2c->dev, "%s: %s failed: %d\n",
313 				KBUILD_MODNAME, __func__, ret);
314 	return ret;
315 }
316 
317 static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
318 {
319 	struct fc0012_priv *priv = fe->tuner_priv;
320 	*frequency = priv->frequency;
321 	return 0;
322 }
323 
324 static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
325 {
326 	*frequency = 0; /* Zero-IF */
327 	return 0;
328 }
329 
330 static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
331 {
332 	struct fc0012_priv *priv = fe->tuner_priv;
333 	*bandwidth = priv->bandwidth;
334 	return 0;
335 }
336 
337 #define INPUT_ADC_LEVEL	-8
338 
339 static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
340 {
341 	struct fc0012_priv *priv = fe->tuner_priv;
342 	int ret;
343 	unsigned char tmp;
344 	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
345 	static const int fc0012_lna_gain_table[] = {
346 		/* low gain */
347 		-63, -58, -99, -73,
348 		-63, -65, -54, -60,
349 		/* middle gain */
350 		 71,  70,  68,  67,
351 		 65,  63,  61,  58,
352 		/* high gain */
353 		197, 191, 188, 186,
354 		184, 182, 181, 179,
355 	};
356 
357 	if (fe->ops.i2c_gate_ctrl)
358 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
359 
360 	ret = fc0012_writereg(priv, 0x12, 0x00);
361 	if (ret)
362 		goto err;
363 
364 	ret = fc0012_readreg(priv, 0x12, &tmp);
365 	if (ret)
366 		goto err;
367 	int_temp = tmp;
368 
369 	ret = fc0012_readreg(priv, 0x13, &tmp);
370 	if (ret)
371 		goto err;
372 	lna_gain = tmp & 0x1f;
373 
374 	if (fe->ops.i2c_gate_ctrl)
375 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
376 
377 	if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) {
378 		int_lna = fc0012_lna_gain_table[lna_gain];
379 		tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
380 				(int_temp & 0x1f)) * 2;
381 		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
382 
383 		if (power >= 45)
384 			*strength = 255;	/* 100% */
385 		else if (power < -95)
386 			*strength = 0;
387 		else
388 			*strength = (power + 95) * 255 / 140;
389 
390 		*strength |= *strength << 8;
391 	} else {
392 		ret = -1;
393 	}
394 
395 	goto exit;
396 
397 err:
398 	if (fe->ops.i2c_gate_ctrl)
399 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
400 exit:
401 	if (ret)
402 		dev_warn(&priv->i2c->dev, "%s: %s failed: %d\n",
403 				KBUILD_MODNAME, __func__, ret);
404 	return ret;
405 }
406 
407 static const struct dvb_tuner_ops fc0012_tuner_ops = {
408 	.info = {
409 		.name              = "Fitipower FC0012",
410 
411 		.frequency_min_hz  =  37 * MHz,	/* estimate */
412 		.frequency_max_hz  = 862 * MHz,	/* estimate */
413 	},
414 
415 	.release	= fc0012_release,
416 
417 	.init		= fc0012_init,
418 
419 	.set_params	= fc0012_set_params,
420 
421 	.get_frequency	= fc0012_get_frequency,
422 	.get_if_frequency = fc0012_get_if_frequency,
423 	.get_bandwidth	= fc0012_get_bandwidth,
424 
425 	.get_rf_strength = fc0012_get_rf_strength,
426 };
427 
428 struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
429 	struct i2c_adapter *i2c, const struct fc0012_config *cfg)
430 {
431 	struct fc0012_priv *priv;
432 	int ret;
433 	u8 chip_id;
434 
435 	if (fe->ops.i2c_gate_ctrl)
436 		fe->ops.i2c_gate_ctrl(fe, 1);
437 
438 	priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
439 	if (!priv) {
440 		ret = -ENOMEM;
441 		dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
442 		goto err;
443 	}
444 
445 	priv->cfg = cfg;
446 	priv->i2c = i2c;
447 
448 	/* check if the tuner is there */
449 	ret = fc0012_readreg(priv, 0x00, &chip_id);
450 	if (ret < 0)
451 		goto err;
452 
453 	dev_dbg(&i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
454 
455 	switch (chip_id) {
456 	case 0xa1:
457 		break;
458 	default:
459 		ret = -ENODEV;
460 		goto err;
461 	}
462 
463 	dev_info(&i2c->dev, "%s: Fitipower FC0012 successfully identified\n",
464 			KBUILD_MODNAME);
465 
466 	if (priv->cfg->loop_through) {
467 		ret = fc0012_writereg(priv, 0x09, 0x6f);
468 		if (ret < 0)
469 			goto err;
470 	}
471 
472 	/*
473 	 * TODO: Clock out en or div?
474 	 * For dual tuner configuration clearing bit [0] is required.
475 	 */
476 	if (priv->cfg->clock_out) {
477 		ret =  fc0012_writereg(priv, 0x0b, 0x82);
478 		if (ret < 0)
479 			goto err;
480 	}
481 
482 	fe->tuner_priv = priv;
483 	memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
484 		sizeof(struct dvb_tuner_ops));
485 
486 err:
487 	if (fe->ops.i2c_gate_ctrl)
488 		fe->ops.i2c_gate_ctrl(fe, 0);
489 
490 	if (ret) {
491 		dev_dbg(&i2c->dev, "%s: failed: %d\n", __func__, ret);
492 		kfree(priv);
493 		return NULL;
494 	}
495 
496 	return fe;
497 }
498 EXPORT_SYMBOL(fc0012_attach);
499 
500 MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
501 MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
502 MODULE_LICENSE("GPL");
503 MODULE_VERSION("0.6");
504