blob: a1629d1d565b19833ba7413802f803f5260c7e03 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 TDA10021 - Single Chip Cable Channel Receiver driver module
Michael Opdenacker59c51592007-05-09 08:57:56 +02003 used on the Siemens DVB-C cards
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5 Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
6 Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08007 Support for TDA10021
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/delay.h>
25#include <linux/errno.h>
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/string.h>
30#include <linux/slab.h>
31
32#include "dvb_frontend.h"
Hartmut Birraa323ac2007-04-21 19:37:17 -030033#include "tda1002x.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35
36struct tda10021_state {
37 struct i2c_adapter* i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 /* configuration settings */
Hartmut Birraa323ac2007-04-21 19:37:17 -030039 const struct tda1002x_config* config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 struct dvb_frontend frontend;
41
42 u8 pwm;
43 u8 reg0;
44};
45
46
47#if 0
48#define dprintk(x...) printk(x)
49#else
50#define dprintk(x...)
51#endif
52
53static int verbose;
54
55#define XIN 57840000UL
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57#define FIN (XIN >> 4)
58
59static int tda10021_inittab_size = 0x40;
60static u8 tda10021_inittab[0x40]=
61{
62 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
63 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
Hartmut Birrfd9c66e2007-04-21 19:17:49 -030064 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
66 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
67 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
68 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,
69 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
70};
71
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -030072static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080074 u8 buf[] = { reg, data };
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080076 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78 ret = i2c_transfer (state->i2c, &msg, 1);
79 if (ret != 1)
80 printk("DVB: TDA10021(%d): %s, writereg error "
81 "(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -030082 state->frontend.dvb->num, __func__, reg, data, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84 msleep(10);
85 return (ret != 1) ? -EREMOTEIO : 0;
86}
87
88static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
89{
90 u8 b0 [] = { reg };
91 u8 b1 [] = { 0 };
92 struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
Michael Krufky50c25ff2006-01-09 15:25:34 -020093 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 int ret;
95
96 ret = i2c_transfer (state->i2c, msg, 2);
Hartmut Birrdc120b02007-04-21 19:44:10 -030097 // Don't print an error message if the id is read.
98 if (ret != 2 && reg != 0x1a)
Jon Burgess88bdcc52005-09-27 21:45:26 -070099 printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -0300100 __func__, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 return b1[0];
102}
103
104//get access to tuner
105static int lock_tuner(struct tda10021_state* state)
106{
107 u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
108 struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
109
110 if(i2c_transfer(state->i2c, &msg, 1) != 1)
111 {
112 printk("tda10021: lock tuner fails\n");
113 return -EREMOTEIO;
114 }
115 return 0;
116}
117
118//release access from tuner
119static int unlock_tuner(struct tda10021_state* state)
120{
121 u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
122 struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
123
124 if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
125 {
126 printk("tda10021: unlock tuner fails\n");
127 return -EREMOTEIO;
128 }
129 return 0;
130}
131
132static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0,
133 fe_spectral_inversion_t inversion)
134{
135 reg0 |= state->reg0 & 0x63;
136
Hartmut Birrdc120b02007-04-21 19:44:10 -0300137 if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
138 reg0 &= ~0x20;
139 else
140 reg0 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300142 _tda10021_writereg (state, 0x00, reg0 & 0xfe);
143 _tda10021_writereg (state, 0x00, reg0 | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145 state->reg0 = reg0;
146 return 0;
147}
148
149static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
150{
151 s32 BDR;
152 s32 BDRI;
153 s16 SFIL=0;
154 u16 NDEC = 0;
155 u32 tmp, ratio;
156
157 if (symbolrate > XIN/2)
158 symbolrate = XIN/2;
159 if (symbolrate < 500000)
160 symbolrate = 500000;
161
162 if (symbolrate < XIN/16) NDEC = 1;
163 if (symbolrate < XIN/32) NDEC = 2;
164 if (symbolrate < XIN/64) NDEC = 3;
165
166 if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
167 if (symbolrate < (u32)(XIN/16)) SFIL = 0;
168 if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
169 if (symbolrate < (u32)(XIN/32)) SFIL = 0;
170 if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
171 if (symbolrate < (u32)(XIN/64)) SFIL = 0;
172 if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
173
174 symbolrate <<= NDEC;
175 ratio = (symbolrate << 4) / FIN;
176 tmp = ((symbolrate << 4) % FIN) << 8;
177 ratio = (ratio << 8) + tmp / FIN;
178 tmp = (tmp % FIN) << 8;
Julia Lawall75b697f2009-08-01 16:48:41 -0300179 ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 BDR = ratio;
182 BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
183
184 if (BDRI > 0xFF)
185 BDRI = 0xFF;
186
187 SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
188
189 NDEC = (NDEC << 6) | tda10021_inittab[0x03];
190
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300191 _tda10021_writereg (state, 0x03, NDEC);
192 _tda10021_writereg (state, 0x0a, BDR&0xff);
193 _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
194 _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300196 _tda10021_writereg (state, 0x0d, BDRI);
197 _tda10021_writereg (state, 0x0e, SFIL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 return 0;
200}
201
202static int tda10021_init (struct dvb_frontend *fe)
203{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700204 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 int i;
206
207 dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
208
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300209 //_tda10021_writereg (fe, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
211 for (i=0; i<tda10021_inittab_size; i++)
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300212 _tda10021_writereg (state, i, tda10021_inittab[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300214 _tda10021_writereg (state, 0x34, state->pwm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 //Comment by markus
217 //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
218 //0x2A[4] == BYPPLL -> Power down mode (default 1)
219 //0x2A[5] == LCK -> PLL Lock Flag
220 //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
221
222 //Activate PLL
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300223 _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return 0;
225}
226
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200227struct qam_params {
228 u8 conf, agcref, lthr, mseth, aref;
229};
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231static int tda10021_set_parameters (struct dvb_frontend *fe,
232 struct dvb_frontend_parameters *p)
233{
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300234 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
235 u32 delsys = c->delivery_system;
236 unsigned qam = c->modulation;
237 bool is_annex_c;
238 u32 reg0x3d;
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700239 struct tda10021_state* state = fe->demodulator_priv;
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200240 static const struct qam_params qam_params[] = {
241 /* Modulation Conf AGCref LTHR MSETH AREF */
242 [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 },
243 [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 },
244 [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 },
245 [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a },
246 [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e },
247 [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b },
248 };
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300249
250 switch (delsys) {
251 case SYS_DVBC_ANNEX_A:
252 is_annex_c = false;
253 break;
254 case SYS_DVBC_ANNEX_C:
255 is_annex_c = true;
256 break;
257 default:
258 return -EINVAL;
259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200261 /*
262 * gcc optimizes the code bellow the same way as it would code:
263 * "if (qam > 5) return -EINVAL;"
264 * Yet, the code is clearer, as it shows what QAM standards are
265 * supported by the driver, and avoids the usage of magic numbers on
266 * it.
267 */
268 switch (qam) {
269 case QPSK:
270 case QAM_16:
271 case QAM_32:
272 case QAM_64:
273 case QAM_128:
274 case QAM_256:
275 break;
276 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return -EINVAL;
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300280 if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
Hartmut Birrdc120b02007-04-21 19:44:10 -0300281 return -EINVAL;
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
284
Patrick Boettcherdea74862006-05-14 05:01:31 -0300285 if (fe->ops.tuner_ops.set_params) {
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300286 fe->ops.tuner_ops.set_params(fe);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300287 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300290 tda10021_set_symbolrate(state, c->symbol_rate);
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200291 _tda10021_writereg(state, 0x34, state->pwm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200293 _tda10021_writereg(state, 0x01, qam_params[qam].agcref);
294 _tda10021_writereg(state, 0x05, qam_params[qam].lthr);
295 _tda10021_writereg(state, 0x08, qam_params[qam].mseth);
296 _tda10021_writereg(state, 0x09, qam_params[qam].aref);
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300297
298 /*
299 * Bit 0 == 0 means roll-off = 0.15 (Annex A)
300 * == 1 means roll-off = 0.13 (Annex C)
301 */
302 reg0x3d = tda10021_readreg (state, 0x3d);
303 if (is_annex_c)
304 _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
305 else
306 _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
307 tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 return 0;
310}
311
312static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status)
313{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700314 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 int sync;
316
317 *status = 0;
318 //0x11[0] == EQALGO -> Equalizer algorithms state
319 //0x11[1] == CARLOCK -> Carrier locked
320 //0x11[2] == FSYNC -> Frame synchronisation
321 //0x11[3] == FEL -> Front End locked
322 //0x11[6] == NODVB -> DVB Mode Information
323 sync = tda10021_readreg (state, 0x11);
324
325 if (sync & 2)
326 *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
327
328 if (sync & 4)
329 *status |= FE_HAS_SYNC|FE_HAS_VITERBI;
330
331 if (sync & 8)
332 *status |= FE_HAS_LOCK;
333
334 return 0;
335}
336
337static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
338{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700339 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 u32 _ber = tda10021_readreg(state, 0x14) |
342 (tda10021_readreg(state, 0x15) << 8) |
343 ((tda10021_readreg(state, 0x16) & 0x0f) << 16);
Hartmut Birr3de0e182007-10-31 01:50:47 -0300344 _tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0)
345 | (tda10021_inittab[0x10] & 0xc0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 *ber = 10 * _ber;
347
348 return 0;
349}
350
351static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
352{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700353 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Hartmut Birr7cccccc2007-10-31 01:57:58 -0300355 u8 config = tda10021_readreg(state, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 u8 gain = tda10021_readreg(state, 0x17);
Hartmut Birr7cccccc2007-10-31 01:57:58 -0300357 if (config & 0x02)
358 /* the agc value is inverted */
359 gain = ~gain;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 *strength = (gain << 8) | gain;
361
362 return 0;
363}
364
365static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
366{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700367 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 u8 quality = ~tda10021_readreg(state, 0x18);
370 *snr = (quality << 8) | quality;
371
372 return 0;
373}
374
375static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
376{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700377 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 *ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
380 if (*ucblocks == 0x7f)
381 *ucblocks = 0xffffffff;
382
383 /* reset uncorrected block counter */
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300384 _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
385 _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 return 0;
388}
389
390static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
391{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700392 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 int sync;
394 s8 afc = 0;
395
396 sync = tda10021_readreg(state, 0x11);
397 afc = tda10021_readreg(state, 0x19);
398 if (verbose) {
399 /* AFC only valid when carrier has been recovered */
400 printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
401 "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
402 state->frontend.dvb->num, afc,
403 -((s32)p->u.qam.symbol_rate * afc) >> 10);
404 }
405
Hartmut Birrdc120b02007-04-21 19:44:10 -0300406 p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
408
409 p->u.qam.fec_inner = FEC_NONE;
410 p->frequency = ((p->frequency + 31250) / 62500) * 62500;
411
412 if (sync & 2)
413 p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
414
415 return 0;
416}
417
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300418static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
419{
420 struct tda10021_state* state = fe->demodulator_priv;
421
422 if (enable) {
423 lock_tuner(state);
424 } else {
425 unlock_tuner(state);
426 }
427 return 0;
428}
429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430static int tda10021_sleep(struct dvb_frontend* fe)
431{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700432 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300434 _tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
435 _tda10021_writereg (state, 0x00, 0x80); /* standby */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 return 0;
438}
439
440static void tda10021_release(struct dvb_frontend* fe)
441{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700442 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 kfree(state);
444}
445
446static struct dvb_frontend_ops tda10021_ops;
447
Hartmut Birraa323ac2007-04-21 19:37:17 -0300448struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 struct i2c_adapter* i2c,
450 u8 pwm)
451{
452 struct tda10021_state* state = NULL;
Hartmut Birrdc120b02007-04-21 19:44:10 -0300453 u8 id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 /* allocate memory for the internal state */
Matthias Schwarzott084e24a2009-08-10 22:51:01 -0300456 state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (state == NULL) goto error;
458
459 /* setup the state */
460 state->config = config;
461 state->i2c = i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 state->pwm = pwm;
463 state->reg0 = tda10021_inittab[0];
464
465 /* check if the demod is there */
Hartmut Birrdc120b02007-04-21 19:44:10 -0300466 id = tda10021_readreg(state, 0x1a);
467 if ((id & 0xf0) != 0x70) goto error;
468
Niklas Edmundsson4af699c2009-12-04 05:38:21 -0300469 /* Don't claim TDA10023 */
470 if (id == 0x7d)
471 goto error;
472
Hartmut Birrdc120b02007-04-21 19:44:10 -0300473 printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
474 state->config->demod_address, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 /* create dvb_frontend */
Patrick Boettcherdea74862006-05-14 05:01:31 -0300477 memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 state->frontend.demodulator_priv = state;
479 return &state->frontend;
480
481error:
482 kfree(state);
483 return NULL;
484}
485
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300486static int tda10021_get_property(struct dvb_frontend *fe,
487 struct dtv_property *p)
488{
489 switch (p->cmd) {
490 case DTV_ENUM_DELSYS:
491 p->u.buffer.data[0] = SYS_DVBC_ANNEX_A;
492 p->u.buffer.data[1] = SYS_DVBC_ANNEX_C;
493 p->u.buffer.len = 2;
494 break;
495 default:
496 break;
497 }
498 return 0;
499}
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501static struct dvb_frontend_ops tda10021_ops = {
502
503 .info = {
504 .name = "Philips TDA10021 DVB-C",
505 .type = FE_QAM,
506 .frequency_stepsize = 62500,
Hartmut Birra18255b2007-08-09 00:01:51 -0300507 .frequency_min = 47000000,
508 .frequency_max = 862000000,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */
510 .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */
Mauro Carvalho Chehabacf28212007-04-27 12:31:06 -0300511 #if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 .frequency_tolerance = ???,
513 .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
514 #endif
515 .caps = 0x400 | //FE_CAN_QAM_4
516 FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
517 FE_CAN_QAM_128 | FE_CAN_QAM_256 |
518 FE_CAN_FEC_AUTO
519 },
520
521 .release = tda10021_release,
522
523 .init = tda10021_init,
524 .sleep = tda10021_sleep,
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300525 .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 .set_frontend = tda10021_set_parameters,
528 .get_frontend = tda10021_get_frontend,
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300529 .get_property = tda10021_get_property,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 .read_status = tda10021_read_status,
532 .read_ber = tda10021_read_ber,
533 .read_signal_strength = tda10021_read_signal_strength,
534 .read_snr = tda10021_read_snr,
535 .read_ucblocks = tda10021_read_ucblocks,
536};
537
538module_param(verbose, int, 0644);
539MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
540
541MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
542MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
543MODULE_LICENSE("GPL");
544
545EXPORT_SYMBOL(tda10021_attach);