1/*
2    Conexant 22702 DVB OFDM demodulator driver
3
4    based on:
5	Alps TDMB7 DVB OFDM demodulator driver
6
7    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
8	  Holger Waechtler <holger@convergence.de>
9
10    Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26*/
27
28#include <linux/kernel.h>
29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/string.h>
32#include <linux/slab.h>
33#include <linux/delay.h>
34#include "dvb_frontend.h"
35#include "cx22702.h"
36
37struct cx22702_state {
38
39	struct i2c_adapter *i2c;
40
41	/* configuration settings */
42	const struct cx22702_config *config;
43
44	struct dvb_frontend frontend;
45
46	/* previous uncorrected block counter */
47	u8 prevUCBlocks;
48};
49
50static int debug;
51module_param(debug, int, 0644);
52MODULE_PARM_DESC(debug, "Enable verbose debug messages");
53
54#define dprintk	if (debug) printk
55
56/* Register values to initialise the demod */
57static const u8 init_tab[] = {
58	0x00, 0x00, /* Stop acquisition */
59	0x0B, 0x06,
60	0x09, 0x01,
61	0x0D, 0x41,
62	0x16, 0x32,
63	0x20, 0x0A,
64	0x21, 0x17,
65	0x24, 0x3e,
66	0x26, 0xff,
67	0x27, 0x10,
68	0x28, 0x00,
69	0x29, 0x00,
70	0x2a, 0x10,
71	0x2b, 0x00,
72	0x2c, 0x10,
73	0x2d, 0x00,
74	0x48, 0xd4,
75	0x49, 0x56,
76	0x6b, 0x1e,
77	0xc8, 0x02,
78	0xf9, 0x00,
79	0xfa, 0x00,
80	0xfb, 0x00,
81	0xfc, 0x00,
82	0xfd, 0x00,
83};
84
85static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
86{
87	int ret;
88	u8 buf[] = { reg, data };
89	struct i2c_msg msg = {
90		.addr = state->config->demod_address, .flags = 0,
91			.buf = buf, .len = 2 };
92
93	ret = i2c_transfer(state->i2c, &msg, 1);
94
95	if (unlikely(ret != 1)) {
96		printk(KERN_ERR
97			"%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
98			__func__, reg, data, ret);
99		return -1;
100	}
101
102	return 0;
103}
104
105static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
106{
107	int ret;
108	u8 data;
109
110	struct i2c_msg msg[] = {
111		{ .addr = state->config->demod_address, .flags = 0,
112			.buf = &reg, .len = 1 },
113		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
114			.buf = &data, .len = 1 } };
115
116	ret = i2c_transfer(state->i2c, msg, 2);
117
118	if (unlikely(ret != 2)) {
119		printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
120			__func__, reg, ret);
121		return 0;
122	}
123
124	return data;
125}
126
127static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
128{
129	u8 val;
130
131	val = cx22702_readreg(state, 0x0C);
132	switch (inversion) {
133	case INVERSION_AUTO:
134		return -EOPNOTSUPP;
135	case INVERSION_ON:
136		val |= 0x01;
137		break;
138	case INVERSION_OFF:
139		val &= 0xfe;
140		break;
141	default:
142		return -EINVAL;
143	}
144	return cx22702_writereg(state, 0x0C, val);
145}
146
147/* Retrieve the demod settings */
148static int cx22702_get_tps(struct cx22702_state *state,
149			   struct dtv_frontend_properties *p)
150{
151	u8 val;
152
153	/* Make sure the TPS regs are valid */
154	if (!(cx22702_readreg(state, 0x0A) & 0x20))
155		return -EAGAIN;
156
157	val = cx22702_readreg(state, 0x01);
158	switch ((val & 0x18) >> 3) {
159	case 0:
160		p->modulation = QPSK;
161		break;
162	case 1:
163		p->modulation = QAM_16;
164		break;
165	case 2:
166		p->modulation = QAM_64;
167		break;
168	}
169	switch (val & 0x07) {
170	case 0:
171		p->hierarchy = HIERARCHY_NONE;
172		break;
173	case 1:
174		p->hierarchy = HIERARCHY_1;
175		break;
176	case 2:
177		p->hierarchy = HIERARCHY_2;
178		break;
179	case 3:
180		p->hierarchy = HIERARCHY_4;
181		break;
182	}
183
184
185	val = cx22702_readreg(state, 0x02);
186	switch ((val & 0x38) >> 3) {
187	case 0:
188		p->code_rate_HP = FEC_1_2;
189		break;
190	case 1:
191		p->code_rate_HP = FEC_2_3;
192		break;
193	case 2:
194		p->code_rate_HP = FEC_3_4;
195		break;
196	case 3:
197		p->code_rate_HP = FEC_5_6;
198		break;
199	case 4:
200		p->code_rate_HP = FEC_7_8;
201		break;
202	}
203	switch (val & 0x07) {
204	case 0:
205		p->code_rate_LP = FEC_1_2;
206		break;
207	case 1:
208		p->code_rate_LP = FEC_2_3;
209		break;
210	case 2:
211		p->code_rate_LP = FEC_3_4;
212		break;
213	case 3:
214		p->code_rate_LP = FEC_5_6;
215		break;
216	case 4:
217		p->code_rate_LP = FEC_7_8;
218		break;
219	}
220
221	val = cx22702_readreg(state, 0x03);
222	switch ((val & 0x0c) >> 2) {
223	case 0:
224		p->guard_interval = GUARD_INTERVAL_1_32;
225		break;
226	case 1:
227		p->guard_interval = GUARD_INTERVAL_1_16;
228		break;
229	case 2:
230		p->guard_interval = GUARD_INTERVAL_1_8;
231		break;
232	case 3:
233		p->guard_interval = GUARD_INTERVAL_1_4;
234		break;
235	}
236	switch (val & 0x03) {
237	case 0:
238		p->transmission_mode = TRANSMISSION_MODE_2K;
239		break;
240	case 1:
241		p->transmission_mode = TRANSMISSION_MODE_8K;
242		break;
243	}
244
245	return 0;
246}
247
248static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
249{
250	struct cx22702_state *state = fe->demodulator_priv;
251	u8 val;
252
253	dprintk("%s(%d)\n", __func__, enable);
254	val = cx22702_readreg(state, 0x0D);
255	if (enable)
256		val &= 0xfe;
257	else
258		val |= 0x01;
259	return cx22702_writereg(state, 0x0D, val);
260}
261
262/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
263static int cx22702_set_tps(struct dvb_frontend *fe)
264{
265	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
266	u8 val;
267	struct cx22702_state *state = fe->demodulator_priv;
268
269	if (fe->ops.tuner_ops.set_params) {
270		fe->ops.tuner_ops.set_params(fe);
271		if (fe->ops.i2c_gate_ctrl)
272			fe->ops.i2c_gate_ctrl(fe, 0);
273	}
274
275	/* set inversion */
276	cx22702_set_inversion(state, p->inversion);
277
278	/* set bandwidth */
279	val = cx22702_readreg(state, 0x0C) & 0xcf;
280	switch (p->bandwidth_hz) {
281	case 6000000:
282		val |= 0x20;
283		break;
284	case 7000000:
285		val |= 0x10;
286		break;
287	case 8000000:
288		break;
289	default:
290		dprintk("%s: invalid bandwidth\n", __func__);
291		return -EINVAL;
292	}
293	cx22702_writereg(state, 0x0C, val);
294
295	p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
296
297	/* use auto configuration? */
298	if ((p->hierarchy == HIERARCHY_AUTO) ||
299	   (p->modulation == QAM_AUTO) ||
300	   (p->code_rate_HP == FEC_AUTO) ||
301	   (p->code_rate_LP == FEC_AUTO) ||
302	   (p->guard_interval == GUARD_INTERVAL_AUTO) ||
303	   (p->transmission_mode == TRANSMISSION_MODE_AUTO)) {
304
305		/* TPS Source - use hardware driven values */
306		cx22702_writereg(state, 0x06, 0x10);
307		cx22702_writereg(state, 0x07, 0x9);
308		cx22702_writereg(state, 0x08, 0xC1);
309		cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
310			& 0xfc);
311		cx22702_writereg(state, 0x0C,
312			(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
313		cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */
314		dprintk("%s: Autodetecting\n", __func__);
315		return 0;
316	}
317
318	/* manually programmed values */
319	switch (p->modulation) {		/* mask 0x18 */
320	case QPSK:
321		val = 0x00;
322		break;
323	case QAM_16:
324		val = 0x08;
325		break;
326	case QAM_64:
327		val = 0x10;
328		break;
329	default:
330		dprintk("%s: invalid modulation\n", __func__);
331		return -EINVAL;
332	}
333	switch (p->hierarchy) {	/* mask 0x07 */
334	case HIERARCHY_NONE:
335		break;
336	case HIERARCHY_1:
337		val |= 0x01;
338		break;
339	case HIERARCHY_2:
340		val |= 0x02;
341		break;
342	case HIERARCHY_4:
343		val |= 0x03;
344		break;
345	default:
346		dprintk("%s: invalid hierarchy\n", __func__);
347		return -EINVAL;
348	}
349	cx22702_writereg(state, 0x06, val);
350
351	switch (p->code_rate_HP) {		/* mask 0x38 */
352	case FEC_NONE:
353	case FEC_1_2:
354		val = 0x00;
355		break;
356	case FEC_2_3:
357		val = 0x08;
358		break;
359	case FEC_3_4:
360		val = 0x10;
361		break;
362	case FEC_5_6:
363		val = 0x18;
364		break;
365	case FEC_7_8:
366		val = 0x20;
367		break;
368	default:
369		dprintk("%s: invalid code_rate_HP\n", __func__);
370		return -EINVAL;
371	}
372	switch (p->code_rate_LP) {		/* mask 0x07 */
373	case FEC_NONE:
374	case FEC_1_2:
375		break;
376	case FEC_2_3:
377		val |= 0x01;
378		break;
379	case FEC_3_4:
380		val |= 0x02;
381		break;
382	case FEC_5_6:
383		val |= 0x03;
384		break;
385	case FEC_7_8:
386		val |= 0x04;
387		break;
388	default:
389		dprintk("%s: invalid code_rate_LP\n", __func__);
390		return -EINVAL;
391	}
392	cx22702_writereg(state, 0x07, val);
393
394	switch (p->guard_interval) {		/* mask 0x0c */
395	case GUARD_INTERVAL_1_32:
396		val = 0x00;
397		break;
398	case GUARD_INTERVAL_1_16:
399		val = 0x04;
400		break;
401	case GUARD_INTERVAL_1_8:
402		val = 0x08;
403		break;
404	case GUARD_INTERVAL_1_4:
405		val = 0x0c;
406		break;
407	default:
408		dprintk("%s: invalid guard_interval\n", __func__);
409		return -EINVAL;
410	}
411	switch (p->transmission_mode) {		/* mask 0x03 */
412	case TRANSMISSION_MODE_2K:
413		break;
414	case TRANSMISSION_MODE_8K:
415		val |= 0x1;
416		break;
417	default:
418		dprintk("%s: invalid transmission_mode\n", __func__);
419		return -EINVAL;
420	}
421	cx22702_writereg(state, 0x08, val);
422	cx22702_writereg(state, 0x0B,
423		(cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
424	cx22702_writereg(state, 0x0C,
425		(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
426
427	/* Begin channel acquisition */
428	cx22702_writereg(state, 0x00, 0x01);
429
430	return 0;
431}
432
433/* Reset the demod hardware and reset all of the configuration registers
434   to a default state. */
435static int cx22702_init(struct dvb_frontend *fe)
436{
437	int i;
438	struct cx22702_state *state = fe->demodulator_priv;
439
440	cx22702_writereg(state, 0x00, 0x02);
441
442	msleep(10);
443
444	for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
445		cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
446
447	cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
448		& 0x02);
449
450	cx22702_i2c_gate_ctrl(fe, 0);
451
452	return 0;
453}
454
455static int cx22702_read_status(struct dvb_frontend *fe, enum fe_status *status)
456{
457	struct cx22702_state *state = fe->demodulator_priv;
458	u8 reg0A;
459	u8 reg23;
460
461	*status = 0;
462
463	reg0A = cx22702_readreg(state, 0x0A);
464	reg23 = cx22702_readreg(state, 0x23);
465
466	dprintk("%s: status demod=0x%02x agc=0x%02x\n"
467		, __func__, reg0A, reg23);
468
469	if (reg0A & 0x10) {
470		*status |= FE_HAS_LOCK;
471		*status |= FE_HAS_VITERBI;
472		*status |= FE_HAS_SYNC;
473	}
474
475	if (reg0A & 0x20)
476		*status |= FE_HAS_CARRIER;
477
478	if (reg23 < 0xf0)
479		*status |= FE_HAS_SIGNAL;
480
481	return 0;
482}
483
484static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
485{
486	struct cx22702_state *state = fe->demodulator_priv;
487
488	if (cx22702_readreg(state, 0xE4) & 0x02) {
489		/* Realtime statistics */
490		*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
491			| (cx22702_readreg(state, 0xDF) & 0x7F);
492	} else {
493		/* Averagtine statistics */
494		*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
495			| cx22702_readreg(state, 0xDF);
496	}
497
498	return 0;
499}
500
501static int cx22702_read_signal_strength(struct dvb_frontend *fe,
502	u16 *signal_strength)
503{
504	struct cx22702_state *state = fe->demodulator_priv;
505	u8 reg23;
506
507	/*
508	 * Experience suggests that the strength signal register works as
509	 * follows:
510	 * - In the absence of signal, value is 0xff.
511	 * - In the presence of a weak signal, bit 7 is set, not sure what
512	 *   the lower 7 bits mean.
513	 * - In the presence of a strong signal, the register holds a 7-bit
514	 *   value (bit 7 is cleared), with greater values standing for
515	 *   weaker signals.
516	 */
517	reg23 = cx22702_readreg(state, 0x23);
518	if (reg23 & 0x80) {
519		*signal_strength = 0;
520	} else {
521		reg23 = ~reg23 & 0x7f;
522		/* Scale to 16 bit */
523		*signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
524	}
525
526	return 0;
527}
528
529static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
530{
531	struct cx22702_state *state = fe->demodulator_priv;
532
533	u16 rs_ber;
534	if (cx22702_readreg(state, 0xE4) & 0x02) {
535		/* Realtime statistics */
536		rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
537			| (cx22702_readreg(state, 0xDF) & 0x7F);
538	} else {
539		/* Averagine statistics */
540		rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
541			| cx22702_readreg(state, 0xDF);
542	}
543	*snr = ~rs_ber;
544
545	return 0;
546}
547
548static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
549{
550	struct cx22702_state *state = fe->demodulator_priv;
551
552	u8 _ucblocks;
553
554	/* RS Uncorrectable Packet Count then reset */
555	_ucblocks = cx22702_readreg(state, 0xE3);
556	if (state->prevUCBlocks < _ucblocks)
557		*ucblocks = (_ucblocks - state->prevUCBlocks);
558	else
559		*ucblocks = state->prevUCBlocks - _ucblocks;
560	state->prevUCBlocks = _ucblocks;
561
562	return 0;
563}
564
565static int cx22702_get_frontend(struct dvb_frontend *fe)
566{
567	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
568	struct cx22702_state *state = fe->demodulator_priv;
569
570	u8 reg0C = cx22702_readreg(state, 0x0C);
571
572	c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
573	return cx22702_get_tps(state, c);
574}
575
576static int cx22702_get_tune_settings(struct dvb_frontend *fe,
577	struct dvb_frontend_tune_settings *tune)
578{
579	tune->min_delay_ms = 1000;
580	return 0;
581}
582
583static void cx22702_release(struct dvb_frontend *fe)
584{
585	struct cx22702_state *state = fe->demodulator_priv;
586	kfree(state);
587}
588
589static const struct dvb_frontend_ops cx22702_ops;
590
591struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
592	struct i2c_adapter *i2c)
593{
594	struct cx22702_state *state = NULL;
595
596	/* allocate memory for the internal state */
597	state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL);
598	if (state == NULL)
599		goto error;
600
601	/* setup the state */
602	state->config = config;
603	state->i2c = i2c;
604
605	/* check if the demod is there */
606	if (cx22702_readreg(state, 0x1f) != 0x3)
607		goto error;
608
609	/* create dvb_frontend */
610	memcpy(&state->frontend.ops, &cx22702_ops,
611		sizeof(struct dvb_frontend_ops));
612	state->frontend.demodulator_priv = state;
613	return &state->frontend;
614
615error:
616	kfree(state);
617	return NULL;
618}
619EXPORT_SYMBOL(cx22702_attach);
620
621static const struct dvb_frontend_ops cx22702_ops = {
622	.delsys = { SYS_DVBT },
623	.info = {
624		.name			= "Conexant CX22702 DVB-T",
625		.frequency_min		= 177000000,
626		.frequency_max		= 858000000,
627		.frequency_stepsize	= 166666,
628		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
629		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
630		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
631		FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
632		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
633	},
634
635	.release = cx22702_release,
636
637	.init = cx22702_init,
638	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
639
640	.set_frontend = cx22702_set_tps,
641	.get_frontend = cx22702_get_frontend,
642	.get_tune_settings = cx22702_get_tune_settings,
643
644	.read_status = cx22702_read_status,
645	.read_ber = cx22702_read_ber,
646	.read_signal_strength = cx22702_read_signal_strength,
647	.read_snr = cx22702_read_snr,
648	.read_ucblocks = cx22702_read_ucblocks,
649};
650
651MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
652MODULE_AUTHOR("Steven Toth");
653MODULE_LICENSE("GPL");
654