blob: 5cd885d4ea04f2243f48e86a3344832245dba872 [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
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050032#include <media/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)
Mauro Carvalho Chehab4bd69e72016-10-18 17:44:22 -020080 printk("DVB: TDA10021(%d): %s, writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -030081 state->frontend.dvb->num, __func__, reg, data, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83 msleep(10);
84 return (ret != 1) ? -EREMOTEIO : 0;
85}
86
87static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
88{
89 u8 b0 [] = { reg };
90 u8 b1 [] = { 0 };
91 struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
Michael Krufky50c25ff2006-01-09 15:25:34 -020092 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 int ret;
94
95 ret = i2c_transfer (state->i2c, msg, 2);
Hartmut Birrdc120b02007-04-21 19:44:10 -030096 // Don't print an error message if the id is read.
97 if (ret != 2 && reg != 0x1a)
Jon Burgess88bdcc52005-09-27 21:45:26 -070098 printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -030099 __func__, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 return b1[0];
101}
102
103//get access to tuner
104static int lock_tuner(struct tda10021_state* state)
105{
106 u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
107 struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
108
109 if(i2c_transfer(state->i2c, &msg, 1) != 1)
110 {
111 printk("tda10021: lock tuner fails\n");
112 return -EREMOTEIO;
113 }
114 return 0;
115}
116
117//release access from tuner
118static int unlock_tuner(struct tda10021_state* state)
119{
120 u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
121 struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
122
123 if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
124 {
125 printk("tda10021: unlock tuner fails\n");
126 return -EREMOTEIO;
127 }
128 return 0;
129}
130
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300131static int tda10021_setup_reg0(struct tda10021_state *state, u8 reg0,
132 enum fe_spectral_inversion inversion)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
134 reg0 |= state->reg0 & 0x63;
135
Hartmut Birrdc120b02007-04-21 19:44:10 -0300136 if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
137 reg0 &= ~0x20;
138 else
139 reg0 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300141 _tda10021_writereg (state, 0x00, reg0 & 0xfe);
142 _tda10021_writereg (state, 0x00, reg0 | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 state->reg0 = reg0;
145 return 0;
146}
147
148static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
149{
150 s32 BDR;
151 s32 BDRI;
152 s16 SFIL=0;
153 u16 NDEC = 0;
154 u32 tmp, ratio;
155
156 if (symbolrate > XIN/2)
157 symbolrate = XIN/2;
158 if (symbolrate < 500000)
159 symbolrate = 500000;
160
161 if (symbolrate < XIN/16) NDEC = 1;
162 if (symbolrate < XIN/32) NDEC = 2;
163 if (symbolrate < XIN/64) NDEC = 3;
164
165 if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
166 if (symbolrate < (u32)(XIN/16)) SFIL = 0;
167 if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
168 if (symbolrate < (u32)(XIN/32)) SFIL = 0;
169 if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
170 if (symbolrate < (u32)(XIN/64)) SFIL = 0;
171 if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
172
173 symbolrate <<= NDEC;
174 ratio = (symbolrate << 4) / FIN;
175 tmp = ((symbolrate << 4) % FIN) << 8;
176 ratio = (ratio << 8) + tmp / FIN;
177 tmp = (tmp % FIN) << 8;
Julia Lawall75b697f2009-08-01 16:48:41 -0300178 ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 BDR = ratio;
181 BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
182
183 if (BDRI > 0xFF)
184 BDRI = 0xFF;
185
186 SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
187
188 NDEC = (NDEC << 6) | tda10021_inittab[0x03];
189
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300190 _tda10021_writereg (state, 0x03, NDEC);
191 _tda10021_writereg (state, 0x0a, BDR&0xff);
192 _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
193 _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300195 _tda10021_writereg (state, 0x0d, BDRI);
196 _tda10021_writereg (state, 0x0e, SFIL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 return 0;
199}
200
201static int tda10021_init (struct dvb_frontend *fe)
202{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700203 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 int i;
205
206 dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
207
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300208 //_tda10021_writereg (fe, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210 for (i=0; i<tda10021_inittab_size; i++)
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300211 _tda10021_writereg (state, i, tda10021_inittab[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300213 _tda10021_writereg (state, 0x34, state->pwm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 //Comment by markus
216 //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
217 //0x2A[4] == BYPPLL -> Power down mode (default 1)
218 //0x2A[5] == LCK -> PLL Lock Flag
219 //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
220
221 //Activate PLL
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300222 _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 return 0;
224}
225
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200226struct qam_params {
227 u8 conf, agcref, lthr, mseth, aref;
228};
229
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300230static int tda10021_set_parameters(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300232 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
233 u32 delsys = c->delivery_system;
234 unsigned qam = c->modulation;
235 bool is_annex_c;
236 u32 reg0x3d;
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700237 struct tda10021_state* state = fe->demodulator_priv;
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200238 static const struct qam_params qam_params[] = {
239 /* Modulation Conf AGCref LTHR MSETH AREF */
240 [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 },
241 [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 },
242 [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 },
243 [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a },
244 [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e },
245 [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b },
246 };
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300247
248 switch (delsys) {
249 case SYS_DVBC_ANNEX_A:
250 is_annex_c = false;
251 break;
252 case SYS_DVBC_ANNEX_C:
253 is_annex_c = true;
254 break;
255 default:
256 return -EINVAL;
257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200259 /*
Mauro Carvalho Chehab5a13e402015-05-08 08:59:16 -0300260 * gcc optimizes the code below the same way as it would code:
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200261 * "if (qam > 5) return -EINVAL;"
262 * Yet, the code is clearer, as it shows what QAM standards are
263 * supported by the driver, and avoids the usage of magic numbers on
264 * it.
265 */
266 switch (qam) {
267 case QPSK:
268 case QAM_16:
269 case QAM_32:
270 case QAM_64:
271 case QAM_128:
272 case QAM_256:
273 break;
274 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 return -EINVAL;
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300278 if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
Hartmut Birrdc120b02007-04-21 19:44:10 -0300279 return -EINVAL;
280
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300281 /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Patrick Boettcherdea74862006-05-14 05:01:31 -0300283 if (fe->ops.tuner_ops.set_params) {
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300284 fe->ops.tuner_ops.set_params(fe);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300285 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300288 tda10021_set_symbolrate(state, c->symbol_rate);
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200289 _tda10021_writereg(state, 0x34, state->pwm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200291 _tda10021_writereg(state, 0x01, qam_params[qam].agcref);
292 _tda10021_writereg(state, 0x05, qam_params[qam].lthr);
293 _tda10021_writereg(state, 0x08, qam_params[qam].mseth);
294 _tda10021_writereg(state, 0x09, qam_params[qam].aref);
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300295
296 /*
297 * Bit 0 == 0 means roll-off = 0.15 (Annex A)
298 * == 1 means roll-off = 0.13 (Annex C)
299 */
300 reg0x3d = tda10021_readreg (state, 0x3d);
301 if (is_annex_c)
302 _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
303 else
304 _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
305 tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 return 0;
308}
309
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300310static int tda10021_read_status(struct dvb_frontend *fe,
311 enum fe_status *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700313 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 int sync;
315
316 *status = 0;
317 //0x11[0] == EQALGO -> Equalizer algorithms state
318 //0x11[1] == CARLOCK -> Carrier locked
319 //0x11[2] == FSYNC -> Frame synchronisation
320 //0x11[3] == FEL -> Front End locked
321 //0x11[6] == NODVB -> DVB Mode Information
322 sync = tda10021_readreg (state, 0x11);
323
324 if (sync & 2)
325 *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
326
327 if (sync & 4)
328 *status |= FE_HAS_SYNC|FE_HAS_VITERBI;
329
330 if (sync & 8)
331 *status |= FE_HAS_LOCK;
332
333 return 0;
334}
335
336static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
337{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700338 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 u32 _ber = tda10021_readreg(state, 0x14) |
341 (tda10021_readreg(state, 0x15) << 8) |
342 ((tda10021_readreg(state, 0x16) & 0x0f) << 16);
Hartmut Birr3de0e182007-10-31 01:50:47 -0300343 _tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0)
344 | (tda10021_inittab[0x10] & 0xc0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 *ber = 10 * _ber;
346
347 return 0;
348}
349
350static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
351{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700352 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Hartmut Birr7cccccc2007-10-31 01:57:58 -0300354 u8 config = tda10021_readreg(state, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 u8 gain = tda10021_readreg(state, 0x17);
Hartmut Birr7cccccc2007-10-31 01:57:58 -0300356 if (config & 0x02)
357 /* the agc value is inverted */
358 gain = ~gain;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 *strength = (gain << 8) | gain;
360
361 return 0;
362}
363
364static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
365{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700366 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 u8 quality = ~tda10021_readreg(state, 0x18);
369 *snr = (quality << 8) | quality;
370
371 return 0;
372}
373
374static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
375{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700376 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 *ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
379 if (*ucblocks == 0x7f)
380 *ucblocks = 0xffffffff;
381
382 /* reset uncorrected block counter */
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300383 _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
384 _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 return 0;
387}
388
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -0200389static int tda10021_get_frontend(struct dvb_frontend *fe,
390 struct dtv_frontend_properties *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
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,
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300403 -((s32)p->symbol_rate * afc) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405
Hartmut Birrdc120b02007-04-21 19:44:10 -0300406 p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300407 p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300409 p->fec_inner = FEC_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 p->frequency = ((p->frequency + 31250) / 62500) * 62500;
411
412 if (sync & 2)
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300413 p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
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
Max Kellermannbd336e62016-08-09 18:32:21 -0300446static const struct dvb_frontend_ops tda10021_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
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
Max Kellermannbd336e62016-08-09 18:32:21 -0300486static const struct dvb_frontend_ops tda10021_ops = {
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300487 .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 .info = {
489 .name = "Philips TDA10021 DVB-C",
Mauro Carvalho Chehabf1b1eab2018-07-05 18:59:36 -0400490 .frequency_min_hz = 47 * MHz,
491 .frequency_max_hz = 862 * MHz,
492 .frequency_stepsize_hz = 62500,
493 .symbol_rate_min = (XIN / 2) / 64, /* SACLK/64 == (XIN/2)/64 */
494 .symbol_rate_max = (XIN / 2) / 4, /* SACLK/4 */
Mauro Carvalho Chehabacf28212007-04-27 12:31:06 -0300495 #if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 .frequency_tolerance = ???,
497 .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
498 #endif
499 .caps = 0x400 | //FE_CAN_QAM_4
500 FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
501 FE_CAN_QAM_128 | FE_CAN_QAM_256 |
502 FE_CAN_FEC_AUTO
503 },
504
505 .release = tda10021_release,
506
507 .init = tda10021_init,
508 .sleep = tda10021_sleep,
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300509 .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300511 .set_frontend = tda10021_set_parameters,
512 .get_frontend = tda10021_get_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 .read_status = tda10021_read_status,
515 .read_ber = tda10021_read_ber,
516 .read_signal_strength = tda10021_read_signal_strength,
517 .read_snr = tda10021_read_snr,
518 .read_ucblocks = tda10021_read_ucblocks,
519};
520
521module_param(verbose, int, 0644);
522MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
523
524MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
525MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
526MODULE_LICENSE("GPL");
527
528EXPORT_SYMBOL(tda10021_attach);