1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Fitipower FC0011 tuner driver
4 *
5 * Copyright (C) 2012 Michael Buesch <m@bues.ch>
6 *
7 * Derived from FC0012 tuner driver:
8 * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
9 */
10
11#include "fc0011.h"
12
13
14/* Tuner registers */
15enum {
16	FC11_REG_0,
17	FC11_REG_FA,		/* FA */
18	FC11_REG_FP,		/* FP */
19	FC11_REG_XINHI,		/* XIN high 8 bit */
20	FC11_REG_XINLO,		/* XIN low 8 bit */
21	FC11_REG_VCO,		/* VCO */
22	FC11_REG_VCOSEL,	/* VCO select */
23	FC11_REG_7,		/* Unknown tuner reg 7 */
24	FC11_REG_8,		/* Unknown tuner reg 8 */
25	FC11_REG_9,
26	FC11_REG_10,		/* Unknown tuner reg 10 */
27	FC11_REG_11,		/* Unknown tuner reg 11 */
28	FC11_REG_12,
29	FC11_REG_RCCAL,		/* RC calibrate */
30	FC11_REG_VCOCAL,	/* VCO calibrate */
31	FC11_REG_15,
32	FC11_REG_16,		/* Unknown tuner reg 16 */
33	FC11_REG_17,
34
35	FC11_NR_REGS,		/* Number of registers */
36};
37
38enum FC11_REG_VCOSEL_bits {
39	FC11_VCOSEL_2		= 0x08, /* VCO select 2 */
40	FC11_VCOSEL_1		= 0x10, /* VCO select 1 */
41	FC11_VCOSEL_CLKOUT	= 0x20, /* Fix clock out */
42	FC11_VCOSEL_BW7M	= 0x40, /* 7MHz bw */
43	FC11_VCOSEL_BW6M	= 0x80, /* 6MHz bw */
44};
45
46enum FC11_REG_RCCAL_bits {
47	FC11_RCCAL_FORCE	= 0x10, /* force */
48};
49
50enum FC11_REG_VCOCAL_bits {
51	FC11_VCOCAL_RUN		= 0,	/* VCO calibration run */
52	FC11_VCOCAL_VALUEMASK	= 0x3F,	/* VCO calibration value mask */
53	FC11_VCOCAL_OK		= 0x40,	/* VCO calibration Ok */
54	FC11_VCOCAL_RESET	= 0x80, /* VCO calibration reset */
55};
56
57
58struct fc0011_priv {
59	struct i2c_adapter *i2c;
60	u8 addr;
61
62	u32 frequency;
63	u32 bandwidth;
64};
65
66
67static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val)
68{
69	u8 buf[2] = { reg, val };
70	struct i2c_msg msg = { .addr = priv->addr,
71		.flags = 0, .buf = buf, .len = 2 };
72
73	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
74		dev_err(&priv->i2c->dev,
75			"I2C write reg failed, reg: %02x, val: %02x\n",
76			reg, val);
77		return -EIO;
78	}
79
80	return 0;
81}
82
83static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val)
84{
85	u8 dummy;
86	struct i2c_msg msg[2] = {
87		{ .addr = priv->addr,
88		  .flags = 0, .buf = &reg, .len = 1 },
89		{ .addr = priv->addr,
90		  .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 },
91	};
92
93	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
94		dev_err(&priv->i2c->dev,
95			"I2C read failed, reg: %02x\n", reg);
96		return -EIO;
97	}
98
99	return 0;
100}
101
102static void fc0011_release(struct dvb_frontend *fe)
103{
104	kfree(fe->tuner_priv);
105	fe->tuner_priv = NULL;
106}
107
108static int fc0011_init(struct dvb_frontend *fe)
109{
110	struct fc0011_priv *priv = fe->tuner_priv;
111	int err;
112
113	if (WARN_ON(!fe->callback))
114		return -EINVAL;
115
116	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
117			   FC0011_FE_CALLBACK_POWER, priv->addr);
118	if (err) {
119		dev_err(&priv->i2c->dev, "Power-on callback failed\n");
120		return err;
121	}
122	err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
123			   FC0011_FE_CALLBACK_RESET, priv->addr);
124	if (err) {
125		dev_err(&priv->i2c->dev, "Reset callback failed\n");
126		return err;
127	}
128
129	return 0;
130}
131
132/* Initiate VCO calibration */
133static int fc0011_vcocal_trigger(struct fc0011_priv *priv)
134{
135	int err;
136
137	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET);
138	if (err)
139		return err;
140	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
141	if (err)
142		return err;
143
144	return 0;
145}
146
147/* Read VCO calibration value */
148static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value)
149{
150	int err;
151
152	err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
153	if (err)
154		return err;
155	usleep_range(10000, 20000);
156	err = fc0011_readreg(priv, FC11_REG_VCOCAL, value);
157	if (err)
158		return err;
159
160	return 0;
161}
162
163static int fc0011_set_params(struct dvb_frontend *fe)
164{
165	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
166	struct fc0011_priv *priv = fe->tuner_priv;
167	int err;
168	unsigned int i, vco_retries;
169	u32 freq = p->frequency / 1000;
170	u32 bandwidth = p->bandwidth_hz / 1000;
171	u32 fvco, xin, frac, xdiv, xdivr;
172	u8 fa, fp, vco_sel, vco_cal;
173	u8 regs[FC11_NR_REGS] = { };
174
175	regs[FC11_REG_7] = 0x0F;
176	regs[FC11_REG_8] = 0x3E;
177	regs[FC11_REG_10] = 0xB8;
178	regs[FC11_REG_11] = 0x80;
179	regs[FC11_REG_RCCAL] = 0x04;
180	err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
181	err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
182	err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
183	err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
184	err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
185	if (err)
186		return -EIO;
187
188	/* Set VCO freq and VCO div */
189	if (freq < 54000) {
190		fvco = freq * 64;
191		regs[FC11_REG_VCO] = 0x82;
192	} else if (freq < 108000) {
193		fvco = freq * 32;
194		regs[FC11_REG_VCO] = 0x42;
195	} else if (freq < 216000) {
196		fvco = freq * 16;
197		regs[FC11_REG_VCO] = 0x22;
198	} else if (freq < 432000) {
199		fvco = freq * 8;
200		regs[FC11_REG_VCO] = 0x12;
201	} else {
202		fvco = freq * 4;
203		regs[FC11_REG_VCO] = 0x0A;
204	}
205
206	/* Calc XIN. The PLL reference frequency is 18 MHz. */
207	xdiv = fvco / 18000;
208	WARN_ON(xdiv > 0xFF);
209	frac = fvco - xdiv * 18000;
210	frac = (frac << 15) / 18000;
211	if (frac >= 16384)
212		frac += 32786;
213	if (!frac)
214		xin = 0;
215	else
216		xin = clamp_t(u32, frac, 512, 65024);
217	regs[FC11_REG_XINHI] = xin >> 8;
218	regs[FC11_REG_XINLO] = xin;
219
220	/* Calc FP and FA */
221	xdivr = xdiv;
222	if (fvco - xdiv * 18000 >= 9000)
223		xdivr += 1; /* round */
224	fp = xdivr / 8;
225	fa = xdivr - fp * 8;
226	if (fa < 2) {
227		fp -= 1;
228		fa += 8;
229	}
230	if (fp > 0x1F) {
231		fp = 0x1F;
232		fa = 0xF;
233	}
234	if (fa >= fp) {
235		dev_warn(&priv->i2c->dev,
236			 "fa %02X >= fp %02X, but trying to continue\n",
237			 (unsigned int)(u8)fa, (unsigned int)(u8)fp);
238	}
239	regs[FC11_REG_FA] = fa;
240	regs[FC11_REG_FP] = fp;
241
242	/* Select bandwidth */
243	switch (bandwidth) {
244	case 8000:
245		break;
246	case 7000:
247		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M;
248		break;
249	default:
250		dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. Using 6000 kHz.\n",
251			 bandwidth);
252		bandwidth = 6000;
253		fallthrough;
254	case 6000:
255		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
256		break;
257	}
258
259	/* Pre VCO select */
260	if (fvco < 2320000) {
261		vco_sel = 0;
262		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
263	} else if (fvco < 3080000) {
264		vco_sel = 1;
265		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
266		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
267	} else {
268		vco_sel = 2;
269		regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
270		regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
271	}
272
273	/* Fix for low freqs */
274	if (freq < 45000) {
275		regs[FC11_REG_FA] = 0x6;
276		regs[FC11_REG_FP] = 0x11;
277	}
278
279	/* Clock out fix */
280	regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
281
282	/* Write the cached registers */
283	for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) {
284		err = fc0011_writereg(priv, i, regs[i]);
285		if (err)
286			return err;
287	}
288
289	/* VCO calibration */
290	err = fc0011_vcocal_trigger(priv);
291	if (err)
292		return err;
293	err = fc0011_vcocal_read(priv, &vco_cal);
294	if (err)
295		return err;
296	vco_retries = 0;
297	while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) {
298		/* Reset the tuner and try again */
299		err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
300				   FC0011_FE_CALLBACK_RESET, priv->addr);
301		if (err) {
302			dev_err(&priv->i2c->dev, "Failed to reset tuner\n");
303			return err;
304		}
305		/* Reinit tuner config */
306		err = 0;
307		for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++)
308			err |= fc0011_writereg(priv, i, regs[i]);
309		err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
310		err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
311		err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
312		err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
313		err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
314		if (err)
315			return -EIO;
316		/* VCO calibration */
317		err = fc0011_vcocal_trigger(priv);
318		if (err)
319			return err;
320		err = fc0011_vcocal_read(priv, &vco_cal);
321		if (err)
322			return err;
323		vco_retries++;
324	}
325	if (!(vco_cal & FC11_VCOCAL_OK)) {
326		dev_err(&priv->i2c->dev,
327			"Failed to read VCO calibration value (got %02X)\n",
328			(unsigned int)vco_cal);
329		return -EIO;
330	}
331	vco_cal &= FC11_VCOCAL_VALUEMASK;
332
333	switch (vco_sel) {
334	default:
335		WARN_ON(1);
336		return -EINVAL;
337	case 0:
338		if (vco_cal < 8) {
339			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
340			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
341			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
342					      regs[FC11_REG_VCOSEL]);
343			if (err)
344				return err;
345			err = fc0011_vcocal_trigger(priv);
346			if (err)
347				return err;
348		} else {
349			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
350			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
351					      regs[FC11_REG_VCOSEL]);
352			if (err)
353				return err;
354		}
355		break;
356	case 1:
357		if (vco_cal < 5) {
358			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
359			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
360			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
361					      regs[FC11_REG_VCOSEL]);
362			if (err)
363				return err;
364			err = fc0011_vcocal_trigger(priv);
365			if (err)
366				return err;
367		} else if (vco_cal <= 48) {
368			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
369			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
370			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
371					      regs[FC11_REG_VCOSEL]);
372			if (err)
373				return err;
374		} else {
375			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
376			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
377					      regs[FC11_REG_VCOSEL]);
378			if (err)
379				return err;
380			err = fc0011_vcocal_trigger(priv);
381			if (err)
382				return err;
383		}
384		break;
385	case 2:
386		if (vco_cal > 53) {
387			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
388			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
389			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
390					      regs[FC11_REG_VCOSEL]);
391			if (err)
392				return err;
393			err = fc0011_vcocal_trigger(priv);
394			if (err)
395				return err;
396		} else {
397			regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
398			regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
399			err = fc0011_writereg(priv, FC11_REG_VCOSEL,
400					      regs[FC11_REG_VCOSEL]);
401			if (err)
402				return err;
403		}
404		break;
405	}
406	err = fc0011_vcocal_read(priv, NULL);
407	if (err)
408		return err;
409	usleep_range(10000, 50000);
410
411	err = fc0011_readreg(priv, FC11_REG_RCCAL, &regs[FC11_REG_RCCAL]);
412	if (err)
413		return err;
414	regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE;
415	err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
416	if (err)
417		return err;
418	regs[FC11_REG_16] = 0xB;
419	err = fc0011_writereg(priv, FC11_REG_16, regs[FC11_REG_16]);
420	if (err)
421		return err;
422
423	dev_dbg(&priv->i2c->dev, "Tuned to fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X vcocal=%02X(%u) bw=%u\n",
424		(unsigned int)regs[FC11_REG_FA],
425		(unsigned int)regs[FC11_REG_FP],
426		(unsigned int)regs[FC11_REG_XINHI],
427		(unsigned int)regs[FC11_REG_XINLO],
428		(unsigned int)regs[FC11_REG_VCO],
429		(unsigned int)regs[FC11_REG_VCOSEL],
430		(unsigned int)vco_cal, vco_retries,
431		(unsigned int)bandwidth);
432
433	priv->frequency = p->frequency;
434	priv->bandwidth = p->bandwidth_hz;
435
436	return 0;
437}
438
439static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency)
440{
441	struct fc0011_priv *priv = fe->tuner_priv;
442
443	*frequency = priv->frequency;
444
445	return 0;
446}
447
448static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
449{
450	*frequency = 0;
451
452	return 0;
453}
454
455static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
456{
457	struct fc0011_priv *priv = fe->tuner_priv;
458
459	*bandwidth = priv->bandwidth;
460
461	return 0;
462}
463
464static const struct dvb_tuner_ops fc0011_tuner_ops = {
465	.info = {
466		.name		  = "Fitipower FC0011",
467
468		.frequency_min_hz =   45 * MHz,
469		.frequency_max_hz = 1000 * MHz,
470	},
471
472	.release		= fc0011_release,
473	.init			= fc0011_init,
474
475	.set_params		= fc0011_set_params,
476
477	.get_frequency		= fc0011_get_frequency,
478	.get_if_frequency	= fc0011_get_if_frequency,
479	.get_bandwidth		= fc0011_get_bandwidth,
480};
481
482struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
483				   struct i2c_adapter *i2c,
484				   const struct fc0011_config *config)
485{
486	struct fc0011_priv *priv;
487
488	priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL);
489	if (!priv)
490		return NULL;
491
492	priv->i2c = i2c;
493	priv->addr = config->i2c_address;
494
495	fe->tuner_priv = priv;
496	fe->ops.tuner_ops = fc0011_tuner_ops;
497
498	dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n");
499
500	return fe;
501}
502EXPORT_SYMBOL_GPL(fc0011_attach);
503
504MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
505MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
506MODULE_LICENSE("GPL");
507