blob: 9fb207b415765f59a5a6116a890f9bcaae3a4968 [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 TDA10021 - Single Chip Cable Channel Receiver driver module
Michael Opdenacker59c51592007-05-09 08:57:56 +02004 used on the Siemens DVB-C cards
Linus Torvalds1da177e2005-04-16 15:20:36 -07005
6 Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
7 Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08008 Support for TDA10021
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
Linus Torvalds1da177e2005-04-16 15:20:36 -070010*/
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/delay.h>
13#include <linux/errno.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/string.h>
18#include <linux/slab.h>
19
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050020#include <media/dvb_frontend.h>
Hartmut Birraa323ac2007-04-21 19:37:17 -030021#include "tda1002x.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23
24struct tda10021_state {
25 struct i2c_adapter* i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 /* configuration settings */
Hartmut Birraa323ac2007-04-21 19:37:17 -030027 const struct tda1002x_config* config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 struct dvb_frontend frontend;
29
30 u8 pwm;
31 u8 reg0;
32};
33
34
35#if 0
36#define dprintk(x...) printk(x)
37#else
38#define dprintk(x...)
39#endif
40
41static int verbose;
42
43#define XIN 57840000UL
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45#define FIN (XIN >> 4)
46
47static int tda10021_inittab_size = 0x40;
48static u8 tda10021_inittab[0x40]=
49{
50 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
51 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
Hartmut Birrfd9c66e2007-04-21 19:17:49 -030052 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
54 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
55 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
56 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,
57 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
58};
59
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -030060static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080062 u8 buf[] = { reg, data };
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080064 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66 ret = i2c_transfer (state->i2c, &msg, 1);
67 if (ret != 1)
Mauro Carvalho Chehab4bd69e72016-10-18 17:44:22 -020068 printk("DVB: TDA10021(%d): %s, writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -030069 state->frontend.dvb->num, __func__, reg, data, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71 msleep(10);
72 return (ret != 1) ? -EREMOTEIO : 0;
73}
74
75static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
76{
77 u8 b0 [] = { reg };
78 u8 b1 [] = { 0 };
79 struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
Michael Krufky50c25ff2006-01-09 15:25:34 -020080 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 int ret;
82
83 ret = i2c_transfer (state->i2c, msg, 2);
Hartmut Birrdc120b02007-04-21 19:44:10 -030084 // Don't print an error message if the id is read.
85 if (ret != 2 && reg != 0x1a)
Jon Burgess88bdcc52005-09-27 21:45:26 -070086 printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
Harvey Harrison271ddbf2008-04-08 23:20:00 -030087 __func__, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 return b1[0];
89}
90
91//get access to tuner
92static int lock_tuner(struct tda10021_state* state)
93{
94 u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
95 struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
96
97 if(i2c_transfer(state->i2c, &msg, 1) != 1)
98 {
99 printk("tda10021: lock tuner fails\n");
100 return -EREMOTEIO;
101 }
102 return 0;
103}
104
105//release access from tuner
106static int unlock_tuner(struct tda10021_state* state)
107{
108 u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
109 struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
110
111 if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
112 {
113 printk("tda10021: unlock tuner fails\n");
114 return -EREMOTEIO;
115 }
116 return 0;
117}
118
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300119static int tda10021_setup_reg0(struct tda10021_state *state, u8 reg0,
120 enum fe_spectral_inversion inversion)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
122 reg0 |= state->reg0 & 0x63;
123
Hartmut Birrdc120b02007-04-21 19:44:10 -0300124 if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
125 reg0 &= ~0x20;
126 else
127 reg0 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300129 _tda10021_writereg (state, 0x00, reg0 & 0xfe);
130 _tda10021_writereg (state, 0x00, reg0 | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132 state->reg0 = reg0;
133 return 0;
134}
135
136static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
137{
138 s32 BDR;
139 s32 BDRI;
140 s16 SFIL=0;
141 u16 NDEC = 0;
142 u32 tmp, ratio;
143
144 if (symbolrate > XIN/2)
145 symbolrate = XIN/2;
146 if (symbolrate < 500000)
147 symbolrate = 500000;
148
149 if (symbolrate < XIN/16) NDEC = 1;
150 if (symbolrate < XIN/32) NDEC = 2;
151 if (symbolrate < XIN/64) NDEC = 3;
152
153 if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
154 if (symbolrate < (u32)(XIN/16)) SFIL = 0;
155 if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
156 if (symbolrate < (u32)(XIN/32)) SFIL = 0;
157 if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
158 if (symbolrate < (u32)(XIN/64)) SFIL = 0;
159 if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
160
161 symbolrate <<= NDEC;
162 ratio = (symbolrate << 4) / FIN;
163 tmp = ((symbolrate << 4) % FIN) << 8;
164 ratio = (ratio << 8) + tmp / FIN;
165 tmp = (tmp % FIN) << 8;
Julia Lawall75b697f2009-08-01 16:48:41 -0300166 ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 BDR = ratio;
169 BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
170
171 if (BDRI > 0xFF)
172 BDRI = 0xFF;
173
174 SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
175
176 NDEC = (NDEC << 6) | tda10021_inittab[0x03];
177
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300178 _tda10021_writereg (state, 0x03, NDEC);
179 _tda10021_writereg (state, 0x0a, BDR&0xff);
180 _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
181 _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300183 _tda10021_writereg (state, 0x0d, BDRI);
184 _tda10021_writereg (state, 0x0e, SFIL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 return 0;
187}
188
189static int tda10021_init (struct dvb_frontend *fe)
190{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700191 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 int i;
193
194 dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
195
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300196 //_tda10021_writereg (fe, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 for (i=0; i<tda10021_inittab_size; i++)
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300199 _tda10021_writereg (state, i, tda10021_inittab[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300201 _tda10021_writereg (state, 0x34, state->pwm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 //Comment by markus
204 //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
205 //0x2A[4] == BYPPLL -> Power down mode (default 1)
206 //0x2A[5] == LCK -> PLL Lock Flag
207 //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
208
209 //Activate PLL
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300210 _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 return 0;
212}
213
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200214struct qam_params {
215 u8 conf, agcref, lthr, mseth, aref;
216};
217
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300218static int tda10021_set_parameters(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300220 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
221 u32 delsys = c->delivery_system;
222 unsigned qam = c->modulation;
223 bool is_annex_c;
224 u32 reg0x3d;
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700225 struct tda10021_state* state = fe->demodulator_priv;
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200226 static const struct qam_params qam_params[] = {
227 /* Modulation Conf AGCref LTHR MSETH AREF */
228 [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 },
229 [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 },
230 [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 },
231 [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a },
232 [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e },
233 [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b },
234 };
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300235
236 switch (delsys) {
237 case SYS_DVBC_ANNEX_A:
238 is_annex_c = false;
239 break;
240 case SYS_DVBC_ANNEX_C:
241 is_annex_c = true;
242 break;
243 default:
244 return -EINVAL;
245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200247 /*
Mauro Carvalho Chehab5a13e402015-05-08 08:59:16 -0300248 * gcc optimizes the code below the same way as it would code:
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200249 * "if (qam > 5) return -EINVAL;"
250 * Yet, the code is clearer, as it shows what QAM standards are
251 * supported by the driver, and avoids the usage of magic numbers on
252 * it.
253 */
254 switch (qam) {
255 case QPSK:
256 case QAM_16:
257 case QAM_32:
258 case QAM_64:
259 case QAM_128:
260 case QAM_256:
261 break;
262 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return -EINVAL;
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300266 if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
Hartmut Birrdc120b02007-04-21 19:44:10 -0300267 return -EINVAL;
268
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300269 /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Patrick Boettcherdea74862006-05-14 05:01:31 -0300271 if (fe->ops.tuner_ops.set_params) {
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300272 fe->ops.tuner_ops.set_params(fe);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300273 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300276 tda10021_set_symbolrate(state, c->symbol_rate);
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200277 _tda10021_writereg(state, 0x34, state->pwm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Mauro Carvalho Chehab27d9a5e2011-12-20 13:55:47 -0200279 _tda10021_writereg(state, 0x01, qam_params[qam].agcref);
280 _tda10021_writereg(state, 0x05, qam_params[qam].lthr);
281 _tda10021_writereg(state, 0x08, qam_params[qam].mseth);
282 _tda10021_writereg(state, 0x09, qam_params[qam].aref);
Mauro Carvalho Chehab1a5cd292011-12-17 20:37:01 -0300283
284 /*
285 * Bit 0 == 0 means roll-off = 0.15 (Annex A)
286 * == 1 means roll-off = 0.13 (Annex C)
287 */
288 reg0x3d = tda10021_readreg (state, 0x3d);
289 if (is_annex_c)
290 _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
291 else
292 _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
293 tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 return 0;
296}
297
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300298static int tda10021_read_status(struct dvb_frontend *fe,
299 enum fe_status *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700301 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 int sync;
303
304 *status = 0;
305 //0x11[0] == EQALGO -> Equalizer algorithms state
306 //0x11[1] == CARLOCK -> Carrier locked
307 //0x11[2] == FSYNC -> Frame synchronisation
308 //0x11[3] == FEL -> Front End locked
309 //0x11[6] == NODVB -> DVB Mode Information
310 sync = tda10021_readreg (state, 0x11);
311
312 if (sync & 2)
313 *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
314
315 if (sync & 4)
316 *status |= FE_HAS_SYNC|FE_HAS_VITERBI;
317
318 if (sync & 8)
319 *status |= FE_HAS_LOCK;
320
321 return 0;
322}
323
324static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
325{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700326 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 u32 _ber = tda10021_readreg(state, 0x14) |
329 (tda10021_readreg(state, 0x15) << 8) |
330 ((tda10021_readreg(state, 0x16) & 0x0f) << 16);
Hartmut Birr3de0e182007-10-31 01:50:47 -0300331 _tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0)
332 | (tda10021_inittab[0x10] & 0xc0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 *ber = 10 * _ber;
334
335 return 0;
336}
337
338static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
339{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700340 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Hartmut Birr7cccccc2007-10-31 01:57:58 -0300342 u8 config = tda10021_readreg(state, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 u8 gain = tda10021_readreg(state, 0x17);
Hartmut Birr7cccccc2007-10-31 01:57:58 -0300344 if (config & 0x02)
345 /* the agc value is inverted */
346 gain = ~gain;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 *strength = (gain << 8) | gain;
348
349 return 0;
350}
351
352static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
353{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700354 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 u8 quality = ~tda10021_readreg(state, 0x18);
357 *snr = (quality << 8) | quality;
358
359 return 0;
360}
361
362static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
363{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700364 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 *ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
367 if (*ucblocks == 0x7f)
368 *ucblocks = 0xffffffff;
369
370 /* reset uncorrected block counter */
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300371 _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
372 _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 return 0;
375}
376
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -0200377static int tda10021_get_frontend(struct dvb_frontend *fe,
378 struct dtv_frontend_properties *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700380 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 int sync;
382 s8 afc = 0;
383
384 sync = tda10021_readreg(state, 0x11);
385 afc = tda10021_readreg(state, 0x19);
386 if (verbose) {
387 /* AFC only valid when carrier has been recovered */
388 printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
389 "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
390 state->frontend.dvb->num, afc,
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300391 -((s32)p->symbol_rate * afc) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
393
Hartmut Birrdc120b02007-04-21 19:44:10 -0300394 p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300395 p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300397 p->fec_inner = FEC_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 p->frequency = ((p->frequency + 31250) / 62500) * 62500;
399
400 if (sync & 2)
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300401 p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 return 0;
404}
405
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300406static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
407{
408 struct tda10021_state* state = fe->demodulator_priv;
409
410 if (enable) {
411 lock_tuner(state);
412 } else {
413 unlock_tuner(state);
414 }
415 return 0;
416}
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static int tda10021_sleep(struct dvb_frontend* fe)
419{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700420 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300422 _tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
423 _tda10021_writereg (state, 0x00, 0x80); /* standby */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 return 0;
426}
427
428static void tda10021_release(struct dvb_frontend* fe)
429{
Johannes Stezenbachb8742702005-05-16 21:54:31 -0700430 struct tda10021_state* state = fe->demodulator_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 kfree(state);
432}
433
Max Kellermannbd336e62016-08-09 18:32:21 -0300434static const struct dvb_frontend_ops tda10021_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Hartmut Birraa323ac2007-04-21 19:37:17 -0300436struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 struct i2c_adapter* i2c,
438 u8 pwm)
439{
440 struct tda10021_state* state = NULL;
Hartmut Birrdc120b02007-04-21 19:44:10 -0300441 u8 id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 /* allocate memory for the internal state */
Matthias Schwarzott084e24a2009-08-10 22:51:01 -0300444 state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 if (state == NULL) goto error;
446
447 /* setup the state */
448 state->config = config;
449 state->i2c = i2c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 state->pwm = pwm;
451 state->reg0 = tda10021_inittab[0];
452
453 /* check if the demod is there */
Hartmut Birrdc120b02007-04-21 19:44:10 -0300454 id = tda10021_readreg(state, 0x1a);
455 if ((id & 0xf0) != 0x70) goto error;
456
Niklas Edmundsson4af699c2009-12-04 05:38:21 -0300457 /* Don't claim TDA10023 */
458 if (id == 0x7d)
459 goto error;
460
Hartmut Birrdc120b02007-04-21 19:44:10 -0300461 printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
462 state->config->demod_address, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 /* create dvb_frontend */
Patrick Boettcherdea74862006-05-14 05:01:31 -0300465 memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 state->frontend.demodulator_priv = state;
467 return &state->frontend;
468
469error:
470 kfree(state);
471 return NULL;
472}
473
Max Kellermannbd336e62016-08-09 18:32:21 -0300474static const struct dvb_frontend_ops tda10021_ops = {
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300475 .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 .info = {
477 .name = "Philips TDA10021 DVB-C",
Mauro Carvalho Chehabf1b1eab2018-07-05 18:59:36 -0400478 .frequency_min_hz = 47 * MHz,
479 .frequency_max_hz = 862 * MHz,
480 .frequency_stepsize_hz = 62500,
481 .symbol_rate_min = (XIN / 2) / 64, /* SACLK/64 == (XIN/2)/64 */
482 .symbol_rate_max = (XIN / 2) / 4, /* SACLK/4 */
Mauro Carvalho Chehabacf28212007-04-27 12:31:06 -0300483 #if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 .frequency_tolerance = ???,
485 .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
486 #endif
487 .caps = 0x400 | //FE_CAN_QAM_4
488 FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
489 FE_CAN_QAM_128 | FE_CAN_QAM_256 |
490 FE_CAN_FEC_AUTO
491 },
492
493 .release = tda10021_release,
494
495 .init = tda10021_init,
496 .sleep = tda10021_sleep,
Andrew de Quinceyf1e80912006-04-18 17:47:10 -0300497 .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Mauro Carvalho Chehab7826bcd2011-12-26 14:42:48 -0300499 .set_frontend = tda10021_set_parameters,
500 .get_frontend = tda10021_get_frontend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 .read_status = tda10021_read_status,
503 .read_ber = tda10021_read_ber,
504 .read_signal_strength = tda10021_read_signal_strength,
505 .read_snr = tda10021_read_snr,
506 .read_ucblocks = tda10021_read_ucblocks,
507};
508
509module_param(verbose, int, 0644);
510MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
511
512MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
513MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
514MODULE_LICENSE("GPL");
515
516EXPORT_SYMBOL(tda10021_attach);