]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/dvb-frontends/cx22702.c
Merge tag 'xtensa-20150416' of git://github.com/czankel/xtensa-linux
[mirror_ubuntu-artful-kernel.git] / drivers / media / dvb-frontends / cx22702.c
CommitLineData
1da177e4
LT
1/*
2 Conexant 22702 DVB OFDM demodulator driver
3
4 based on:
9101e622 5 Alps TDMB7 DVB OFDM demodulator driver
1da177e4
LT
6
7 Copyright (C) 2001-2002 Convergence Integrated Media GmbH
8 Holger Waechtler <holger@convergence.de>
9
6d897616 10 Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
1da177e4
LT
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
1da177e4
LT
37struct cx22702_state {
38
4e3599a5 39 struct i2c_adapter *i2c;
1da177e4 40
1da177e4 41 /* configuration settings */
4e3599a5 42 const struct cx22702_config *config;
1da177e4
LT
43
44 struct dvb_frontend frontend;
45
46 /* previous uncorrected block counter */
47 u8 prevUCBlocks;
48};
49
ff699e6b 50static int debug;
4e3599a5
ST
51module_param(debug, int, 0644);
52MODULE_PARM_DESC(debug, "Enable verbose debug messages");
53
1da177e4
LT
54#define dprintk if (debug) printk
55
56/* Register values to initialise the demod */
bdc6fad3 57static const u8 init_tab[] = {
25985edc 58 0x00, 0x00, /* Stop acquisition */
1da177e4
LT
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,
1da177e4
LT
78 0xf9, 0x00,
79 0xfa, 0x00,
80 0xfb, 0x00,
81 0xfc, 0x00,
82 0xfd, 0x00,
83};
84
4e3599a5 85static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
1da177e4
LT
86{
87 int ret;
4e3599a5
ST
88 u8 buf[] = { reg, data };
89 struct i2c_msg msg = {
90 .addr = state->config->demod_address, .flags = 0,
91 .buf = buf, .len = 2 };
1da177e4
LT
92
93 ret = i2c_transfer(state->i2c, &msg, 1);
94
24764107 95 if (unlikely(ret != 1)) {
4e3599a5
ST
96 printk(KERN_ERR
97 "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
271ddbf7 98 __func__, reg, data, ret);
24764107
JD
99 return -1;
100 }
1da177e4 101
24764107 102 return 0;
1da177e4
LT
103}
104
4e3599a5 105static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
1da177e4
LT
106{
107 int ret;
24764107 108 u8 data;
1da177e4 109
4e3599a5
ST
110 struct i2c_msg msg[] = {
111 { .addr = state->config->demod_address, .flags = 0,
24764107 112 .buf = &reg, .len = 1 },
4e3599a5 113 { .addr = state->config->demod_address, .flags = I2C_M_RD,
24764107 114 .buf = &data, .len = 1 } };
1da177e4
LT
115
116 ret = i2c_transfer(state->i2c, msg, 2);
117
24764107
JD
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 }
1da177e4 123
24764107 124 return data;
1da177e4
LT
125}
126
4e3599a5 127static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
1da177e4
LT
128{
129 u8 val;
130
27f84acf 131 val = cx22702_readreg(state, 0x0C);
1da177e4 132 switch (inversion) {
4e3599a5
ST
133 case INVERSION_AUTO:
134 return -EOPNOTSUPP;
135 case INVERSION_ON:
27f84acf
JD
136 val |= 0x01;
137 break;
4e3599a5 138 case INVERSION_OFF:
27f84acf
JD
139 val &= 0xfe;
140 break;
4e3599a5
ST
141 default:
142 return -EINVAL;
1da177e4 143 }
27f84acf 144 return cx22702_writereg(state, 0x0C, val);
1da177e4
LT
145}
146
147/* Retrieve the demod settings */
4e3599a5 148static int cx22702_get_tps(struct cx22702_state *state,
19289a24 149 struct dtv_frontend_properties *p)
1da177e4
LT
150{
151 u8 val;
152
153 /* Make sure the TPS regs are valid */
154 if (!(cx22702_readreg(state, 0x0A) & 0x20))
155 return -EAGAIN;
156
4e3599a5
ST
157 val = cx22702_readreg(state, 0x01);
158 switch ((val & 0x18) >> 3) {
159 case 0:
19289a24 160 p->modulation = QPSK;
4e3599a5
ST
161 break;
162 case 1:
19289a24 163 p->modulation = QAM_16;
4e3599a5
ST
164 break;
165 case 2:
19289a24 166 p->modulation = QAM_64;
4e3599a5 167 break;
1da177e4 168 }
4e3599a5
ST
169 switch (val & 0x07) {
170 case 0:
19289a24 171 p->hierarchy = HIERARCHY_NONE;
4e3599a5
ST
172 break;
173 case 1:
19289a24 174 p->hierarchy = HIERARCHY_1;
4e3599a5
ST
175 break;
176 case 2:
19289a24 177 p->hierarchy = HIERARCHY_2;
4e3599a5
ST
178 break;
179 case 3:
19289a24 180 p->hierarchy = HIERARCHY_4;
4e3599a5 181 break;
1da177e4
LT
182 }
183
184
4e3599a5
ST
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;
1da177e4 202 }
4e3599a5
ST
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;
1da177e4
LT
219 }
220
4e3599a5
ST
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;
1da177e4 235 }
4e3599a5
ST
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;
1da177e4
LT
243 }
244
245 return 0;
246}
247
4e3599a5 248static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
611900c1 249{
4e3599a5 250 struct cx22702_state *state = fe->demodulator_priv;
27f84acf
JD
251 u8 val;
252
4e3599a5 253 dprintk("%s(%d)\n", __func__, enable);
27f84acf 254 val = cx22702_readreg(state, 0x0D);
611900c1 255 if (enable)
27f84acf 256 val &= 0xfe;
611900c1 257 else
27f84acf
JD
258 val |= 0x01;
259 return cx22702_writereg(state, 0x0D, val);
611900c1
ST
260}
261
1da177e4 262/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
19289a24 263static int cx22702_set_tps(struct dvb_frontend *fe)
1da177e4 264{
19289a24 265 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
1da177e4 266 u8 val;
4e3599a5 267 struct cx22702_state *state = fe->demodulator_priv;
1da177e4 268
dea74869 269 if (fe->ops.tuner_ops.set_params) {
14d24d14 270 fe->ops.tuner_ops.set_params(fe);
4e3599a5
ST
271 if (fe->ops.i2c_gate_ctrl)
272 fe->ops.i2c_gate_ctrl(fe, 0);
9990d744 273 }
1da177e4
LT
274
275 /* set inversion */
4e3599a5 276 cx22702_set_inversion(state, p->inversion);
1da177e4
LT
277
278 /* set bandwidth */
27f84acf 279 val = cx22702_readreg(state, 0x0C) & 0xcf;
19289a24
MCC
280 switch (p->bandwidth_hz) {
281 case 6000000:
27f84acf 282 val |= 0x20;
1da177e4 283 break;
19289a24 284 case 7000000:
27f84acf 285 val |= 0x10;
1da177e4 286 break;
19289a24 287 case 8000000:
1da177e4
LT
288 break;
289 default:
4e3599a5 290 dprintk("%s: invalid bandwidth\n", __func__);
1da177e4
LT
291 return -EINVAL;
292 }
27f84acf 293 cx22702_writereg(state, 0x0C, val);
1da177e4 294
19289a24 295 p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
1da177e4
LT
296
297 /* use auto configuration? */
19289a24
MCC
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)) {
1da177e4
LT
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);
4e3599a5
ST
309 cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
310 & 0xfc);
311 cx22702_writereg(state, 0x0C,
312 (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
25985edc 313 cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */
4e3599a5 314 dprintk("%s: Autodetecting\n", __func__);
1da177e4
LT
315 return 0;
316 }
317
318 /* manually programmed values */
19289a24 319 switch (p->modulation) { /* mask 0x18 */
4e3599a5 320 case QPSK:
f89ca6fa 321 val = 0x00;
4e3599a5
ST
322 break;
323 case QAM_16:
f89ca6fa 324 val = 0x08;
4e3599a5
ST
325 break;
326 case QAM_64:
f89ca6fa 327 val = 0x10;
4e3599a5
ST
328 break;
329 default:
19289a24 330 dprintk("%s: invalid modulation\n", __func__);
4e3599a5 331 return -EINVAL;
1da177e4 332 }
19289a24 333 switch (p->hierarchy) { /* mask 0x07 */
4e3599a5 334 case HIERARCHY_NONE:
4e3599a5
ST
335 break;
336 case HIERARCHY_1:
f89ca6fa 337 val |= 0x01;
4e3599a5
ST
338 break;
339 case HIERARCHY_2:
f89ca6fa 340 val |= 0x02;
4e3599a5
ST
341 break;
342 case HIERARCHY_4:
f89ca6fa 343 val |= 0x03;
4e3599a5
ST
344 break;
345 default:
346 dprintk("%s: invalid hierarchy\n", __func__);
347 return -EINVAL;
1da177e4 348 }
4e3599a5
ST
349 cx22702_writereg(state, 0x06, val);
350
19289a24 351 switch (p->code_rate_HP) { /* mask 0x38 */
4e3599a5
ST
352 case FEC_NONE:
353 case FEC_1_2:
f89ca6fa 354 val = 0x00;
4e3599a5
ST
355 break;
356 case FEC_2_3:
f89ca6fa 357 val = 0x08;
4e3599a5
ST
358 break;
359 case FEC_3_4:
f89ca6fa 360 val = 0x10;
4e3599a5
ST
361 break;
362 case FEC_5_6:
f89ca6fa 363 val = 0x18;
4e3599a5
ST
364 break;
365 case FEC_7_8:
f89ca6fa 366 val = 0x20;
4e3599a5
ST
367 break;
368 default:
369 dprintk("%s: invalid code_rate_HP\n", __func__);
370 return -EINVAL;
1da177e4 371 }
19289a24 372 switch (p->code_rate_LP) { /* mask 0x07 */
4e3599a5
ST
373 case FEC_NONE:
374 case FEC_1_2:
4e3599a5
ST
375 break;
376 case FEC_2_3:
f89ca6fa 377 val |= 0x01;
4e3599a5
ST
378 break;
379 case FEC_3_4:
f89ca6fa 380 val |= 0x02;
4e3599a5
ST
381 break;
382 case FEC_5_6:
f89ca6fa 383 val |= 0x03;
4e3599a5
ST
384 break;
385 case FEC_7_8:
f89ca6fa 386 val |= 0x04;
4e3599a5
ST
387 break;
388 default:
389 dprintk("%s: invalid code_rate_LP\n", __func__);
390 return -EINVAL;
1da177e4 391 }
4e3599a5
ST
392 cx22702_writereg(state, 0x07, val);
393
19289a24 394 switch (p->guard_interval) { /* mask 0x0c */
4e3599a5 395 case GUARD_INTERVAL_1_32:
f89ca6fa 396 val = 0x00;
4e3599a5
ST
397 break;
398 case GUARD_INTERVAL_1_16:
f89ca6fa 399 val = 0x04;
4e3599a5
ST
400 break;
401 case GUARD_INTERVAL_1_8:
f89ca6fa 402 val = 0x08;
4e3599a5
ST
403 break;
404 case GUARD_INTERVAL_1_4:
f89ca6fa 405 val = 0x0c;
4e3599a5
ST
406 break;
407 default:
408 dprintk("%s: invalid guard_interval\n", __func__);
409 return -EINVAL;
1da177e4 410 }
19289a24 411 switch (p->transmission_mode) { /* mask 0x03 */
4e3599a5 412 case TRANSMISSION_MODE_2K:
4e3599a5
ST
413 break;
414 case TRANSMISSION_MODE_8K:
f89ca6fa 415 val |= 0x1;
4e3599a5
ST
416 break;
417 default:
418 dprintk("%s: invalid transmission_mode\n", __func__);
419 return -EINVAL;
1da177e4
LT
420 }
421 cx22702_writereg(state, 0x08, val);
4e3599a5
ST
422 cx22702_writereg(state, 0x0B,
423 (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
424 cx22702_writereg(state, 0x0C,
425 (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
1da177e4 426
25985edc 427 /* Begin channel acquisition */
1da177e4
LT
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. */
4e3599a5 435static int cx22702_init(struct dvb_frontend *fe)
1da177e4
LT
436{
437 int i;
4e3599a5 438 struct cx22702_state *state = fe->demodulator_priv;
1da177e4 439
4e3599a5 440 cx22702_writereg(state, 0x00, 0x02);
1da177e4
LT
441
442 msleep(10);
443
4e3599a5
ST
444 for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
445 cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
1da177e4 446
4e3599a5
ST
447 cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
448 & 0x02);
1da177e4 449
611900c1 450 cx22702_i2c_gate_ctrl(fe, 0);
1da177e4
LT
451
452 return 0;
453}
454
4e3599a5 455static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status)
1da177e4 456{
4e3599a5 457 struct cx22702_state *state = fe->demodulator_priv;
1da177e4
LT
458 u8 reg0A;
459 u8 reg23;
460
461 *status = 0;
462
4e3599a5
ST
463 reg0A = cx22702_readreg(state, 0x0A);
464 reg23 = cx22702_readreg(state, 0x23);
1da177e4 465
4e3599a5
ST
466 dprintk("%s: status demod=0x%02x agc=0x%02x\n"
467 , __func__, reg0A, reg23);
1da177e4 468
4e3599a5 469 if (reg0A & 0x10) {
1da177e4
LT
470 *status |= FE_HAS_LOCK;
471 *status |= FE_HAS_VITERBI;
472 *status |= FE_HAS_SYNC;
473 }
474
4e3599a5 475 if (reg0A & 0x20)
1da177e4
LT
476 *status |= FE_HAS_CARRIER;
477
4e3599a5 478 if (reg23 < 0xf0)
1da177e4
LT
479 *status |= FE_HAS_SIGNAL;
480
481 return 0;
482}
483
4e3599a5 484static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
1da177e4 485{
4e3599a5 486 struct cx22702_state *state = fe->demodulator_priv;
1da177e4 487
4e3599a5 488 if (cx22702_readreg(state, 0xE4) & 0x02) {
1da177e4 489 /* Realtime statistics */
4e3599a5
ST
490 *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
491 | (cx22702_readreg(state, 0xDF) & 0x7F);
1da177e4
LT
492 } else {
493 /* Averagtine statistics */
4e3599a5
ST
494 *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
495 | cx22702_readreg(state, 0xDF);
1da177e4
LT
496 }
497
498 return 0;
499}
500
4e3599a5
ST
501static int cx22702_read_signal_strength(struct dvb_frontend *fe,
502 u16 *signal_strength)
1da177e4 503{
4e3599a5 504 struct cx22702_state *state = fe->demodulator_priv;
06302ffb 505 u8 reg23;
1da177e4 506
06302ffb
JD
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 }
1da177e4
LT
525
526 return 0;
527}
528
4e3599a5 529static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
1da177e4 530{
4e3599a5 531 struct cx22702_state *state = fe->demodulator_priv;
1da177e4 532
5b9a6f37 533 u16 rs_ber;
4e3599a5 534 if (cx22702_readreg(state, 0xE4) & 0x02) {
1da177e4 535 /* Realtime statistics */
4e3599a5
ST
536 rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
537 | (cx22702_readreg(state, 0xDF) & 0x7F);
1da177e4
LT
538 } else {
539 /* Averagine statistics */
4e3599a5
ST
540 rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
541 | cx22702_readreg(state, 0xDF);
1da177e4
LT
542 }
543 *snr = ~rs_ber;
544
545 return 0;
546}
547
4e3599a5 548static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
1da177e4 549{
4e3599a5 550 struct cx22702_state *state = fe->demodulator_priv;
1da177e4
LT
551
552 u8 _ucblocks;
553
554 /* RS Uncorrectable Packet Count then reset */
4e3599a5 555 _ucblocks = cx22702_readreg(state, 0xE3);
f46dbb05
PB
556 if (state->prevUCBlocks < _ucblocks)
557 *ucblocks = (_ucblocks - state->prevUCBlocks);
558 else
559 *ucblocks = state->prevUCBlocks - _ucblocks;
1da177e4
LT
560 state->prevUCBlocks = _ucblocks;
561
562 return 0;
563}
564
7c61d80a 565static int cx22702_get_frontend(struct dvb_frontend *fe)
1da177e4 566{
7c61d80a 567 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
4e3599a5 568 struct cx22702_state *state = fe->demodulator_priv;
1da177e4 569
4e3599a5 570 u8 reg0C = cx22702_readreg(state, 0x0C);
1da177e4 571
19289a24
MCC
572 c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
573 return cx22702_get_tps(state, c);
1da177e4
LT
574}
575
4e3599a5
ST
576static int cx22702_get_tune_settings(struct dvb_frontend *fe,
577 struct dvb_frontend_tune_settings *tune)
f46dbb05
PB
578{
579 tune->min_delay_ms = 1000;
580 return 0;
581}
582
4e3599a5 583static void cx22702_release(struct dvb_frontend *fe)
1da177e4 584{
4e3599a5 585 struct cx22702_state *state = fe->demodulator_priv;
1da177e4
LT
586 kfree(state);
587}
588
bdc6fad3 589static const struct dvb_frontend_ops cx22702_ops;
1da177e4 590
4e3599a5
ST
591struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
592 struct i2c_adapter *i2c)
1da177e4 593{
4e3599a5 594 struct cx22702_state *state = NULL;
1da177e4
LT
595
596 /* allocate memory for the internal state */
084e24ac 597 state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL);
f46dbb05
PB
598 if (state == NULL)
599 goto error;
1da177e4
LT
600
601 /* setup the state */
602 state->config = config;
603 state->i2c = i2c;
1da177e4
LT
604
605 /* check if the demod is there */
f46dbb05
PB
606 if (cx22702_readreg(state, 0x1f) != 0x3)
607 goto error;
1da177e4
LT
608
609 /* create dvb_frontend */
4e3599a5
ST
610 memcpy(&state->frontend.ops, &cx22702_ops,
611 sizeof(struct dvb_frontend_ops));
1da177e4
LT
612 state->frontend.demodulator_priv = state;
613 return &state->frontend;
614
615error:
616 kfree(state);
617 return NULL;
618}
4e3599a5 619EXPORT_SYMBOL(cx22702_attach);
1da177e4 620
bdc6fad3 621static const struct dvb_frontend_ops cx22702_ops = {
19289a24 622 .delsys = { SYS_DVBT },
1da177e4
LT
623 .info = {
624 .name = "Conexant CX22702 DVB-T",
1da177e4
LT
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,
02444222 638 .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
1da177e4 639
19289a24
MCC
640 .set_frontend = cx22702_set_tps,
641 .get_frontend = cx22702_get_frontend,
f46dbb05 642 .get_tune_settings = cx22702_get_tune_settings,
1da177e4
LT
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
1da177e4
LT
651MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
652MODULE_AUTHOR("Steven Toth");
653MODULE_LICENSE("GPL");