diff options
author | Hartmut Birr <e9hack@googlemail.com> | 2007-04-21 18:37:17 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-04-27 14:45:47 -0400 |
commit | aa323ac89c5724de89656fcf31590d19e74594ec (patch) | |
tree | a556247ba3e2d78e14e974105d6a34fc094849e5 /drivers/media/dvb/frontends/tda10023.c | |
parent | fd9c66e269a44bd3c6c615957c79b21f3dde69af (diff) |
V4L/DVB (5543): Tda10023: Add support for frontend TDA10023
Add support for the frontend TDA10023 and add cards that need the
tda10023.
Signed-off-by: Hartmut Birr <e9hack@googlemail.com>
Signed-off-by: Georg Acher <acher@in.tum.de>
Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/frontends/tda10023.c')
-rw-r--r-- | drivers/media/dvb/frontends/tda10023.c | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c new file mode 100644 index 000000000000..da796e784be3 --- /dev/null +++ b/drivers/media/dvb/frontends/tda10023.c | |||
@@ -0,0 +1,540 @@ | |||
1 | /* | ||
2 | TDA10023 - DVB-C decoder | ||
3 | (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card) | ||
4 | |||
5 | Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de) | ||
6 | Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com) | ||
7 | |||
8 | Remotely based on tda10021.c | ||
9 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
10 | Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> | ||
11 | Support for TDA10021 | ||
12 | |||
13 | This program is free software; you can redistribute it and/or modify | ||
14 | it under the terms of the GNU General Public License as published by | ||
15 | the Free Software Foundation; either version 2 of the License, or | ||
16 | (at your option) any later version. | ||
17 | |||
18 | This program is distributed in the hope that it will be useful, | ||
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | GNU General Public License for more details. | ||
22 | |||
23 | You should have received a copy of the GNU General Public License | ||
24 | along with this program; if not, write to the Free Software | ||
25 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/delay.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/slab.h> | ||
35 | |||
36 | #include <asm/div64.h> | ||
37 | |||
38 | #include "dvb_frontend.h" | ||
39 | #include "tda1002x.h" | ||
40 | |||
41 | |||
42 | struct tda10023_state { | ||
43 | struct i2c_adapter* i2c; | ||
44 | /* configuration settings */ | ||
45 | const struct tda1002x_config* config; | ||
46 | struct dvb_frontend frontend; | ||
47 | |||
48 | u8 pwm; | ||
49 | u8 reg0; | ||
50 | }; | ||
51 | |||
52 | |||
53 | #define dprintk(x...) | ||
54 | |||
55 | static int verbose; | ||
56 | |||
57 | #define XTAL 28920000UL | ||
58 | #define PLL_M 8UL | ||
59 | #define PLL_P 4UL | ||
60 | #define PLL_N 1UL | ||
61 | #define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000 | ||
62 | |||
63 | static u8 tda10023_inittab[]={ | ||
64 | // reg mask val | ||
65 | 0x2a,0xff,0x02, // PLL3, Bypass, Power Down | ||
66 | 0xff,0x64,0x00, // Sleep 100ms | ||
67 | 0x2a,0xff,0x03, // PLL3, Bypass, Power Down | ||
68 | 0xff,0x64,0x00, // Sleep 100ms | ||
69 | 0x28,0xff,PLL_M-1, // PLL1 M=8 | ||
70 | 0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2 | ||
71 | 0x00,0xff,0x23, // GPR FSAMPLING=1 | ||
72 | 0x2a,0xff,0x08, // PLL3 PSACLK=1 | ||
73 | 0xff,0x64,0x00, // Sleep 100ms | ||
74 | 0x1f,0xff,0x00, // RESET | ||
75 | 0xff,0x64,0x00, // Sleep 100ms | ||
76 | 0xe6,0x0c,0x04, // RSCFG_IND | ||
77 | 0x10,0xc0,0x80, // DECDVBCFG1 PBER=1 | ||
78 | |||
79 | 0x0e,0xff,0x82, // GAIN1 | ||
80 | 0x03,0x08,0x08, // CLKCONF DYN=1 | ||
81 | 0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0 | ||
82 | 0x01,0xff,0x30, // AGCREF | ||
83 | 0x1e,0x84,0x84, // CONTROL SACLK_ON=1 | ||
84 | 0x1b,0xff,0xc8, // ADC TWOS=1 | ||
85 | 0x3b,0xff,0xff, // IFMAX | ||
86 | 0x3c,0xff,0x00, // IFMIN | ||
87 | 0x34,0xff,0x00, // PWMREF | ||
88 | 0x35,0xff,0xff, // TUNMAX | ||
89 | 0x36,0xff,0x00, // TUNMIN | ||
90 | 0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77 | ||
91 | 0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1 | ||
92 | 0x37,0xff,0xf6, // DELTAF_LSB | ||
93 | 0x38,0xff,0xff, // DELTAF_MSB | ||
94 | 0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 | ||
95 | 0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 | ||
96 | 0x04,0x10,0x00, // SWRAMP=1 | ||
97 | 0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0 | ||
98 | 0x2b,0x01,0xa1, // INTS1 | ||
99 | 0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? | ||
100 | 0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0 | ||
101 | 0xc4,0xff,0x00, | ||
102 | 0xc3,0x30,0x00, | ||
103 | 0xb5,0xff,0x19, // ERAGC_THD | ||
104 | 0x00,0x03,0x01, // GPR, CLBS soft reset | ||
105 | 0x00,0x03,0x03, // GPR, CLBS soft reset | ||
106 | 0xff,0x64,0x00, // Sleep 100ms | ||
107 | 0xff,0xff,0xff | ||
108 | }; | ||
109 | |||
110 | static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) | ||
111 | { | ||
112 | u8 b0 [] = { reg }; | ||
113 | u8 b1 [] = { 0 }; | ||
114 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
115 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
116 | int ret; | ||
117 | |||
118 | ret = i2c_transfer (state->i2c, msg, 2); | ||
119 | if (ret != 2) | ||
120 | printk("DVB: TDA10023: %s: readreg error (ret == %i)\n", | ||
121 | __FUNCTION__, ret); | ||
122 | return b1[0]; | ||
123 | } | ||
124 | |||
125 | static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) | ||
126 | { | ||
127 | u8 buf[] = { reg, data }; | ||
128 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
129 | int ret; | ||
130 | |||
131 | ret = i2c_transfer (state->i2c, &msg, 1); | ||
132 | if (ret != 1) | ||
133 | printk("DVB: TDA10023(%d): %s, writereg error " | ||
134 | "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", | ||
135 | state->frontend.dvb->num, __FUNCTION__, reg, data, ret); | ||
136 | |||
137 | return (ret != 1) ? -EREMOTEIO : 0; | ||
138 | } | ||
139 | |||
140 | |||
141 | static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data) | ||
142 | { | ||
143 | if (mask==0xff) | ||
144 | return tda10023_writereg(state, reg, data); | ||
145 | else { | ||
146 | u8 val; | ||
147 | val=tda10023_readreg(state,reg); | ||
148 | val&=~mask; | ||
149 | val|=(data&mask); | ||
150 | return tda10023_writereg(state, reg, val); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | static void tda10023_writetab(struct tda10023_state* state, u8* tab) | ||
155 | { | ||
156 | u8 r,m,v; | ||
157 | while (1) { | ||
158 | r=*tab++; | ||
159 | m=*tab++; | ||
160 | v=*tab++; | ||
161 | if (r==0xff) { | ||
162 | if (m==0xff) | ||
163 | break; | ||
164 | else | ||
165 | msleep(m); | ||
166 | } | ||
167 | else | ||
168 | tda10023_writebit(state,r,m,v); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | //get access to tuner | ||
173 | static int lock_tuner(struct tda10023_state* state) | ||
174 | { | ||
175 | u8 buf[2] = { 0x0f, 0xc0 }; | ||
176 | struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; | ||
177 | |||
178 | if(i2c_transfer(state->i2c, &msg, 1) != 1) | ||
179 | { | ||
180 | printk("tda10023: lock tuner fails\n"); | ||
181 | return -EREMOTEIO; | ||
182 | } | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | //release access from tuner | ||
187 | static int unlock_tuner(struct tda10023_state* state) | ||
188 | { | ||
189 | u8 buf[2] = { 0x0f, 0x40 }; | ||
190 | struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; | ||
191 | |||
192 | if(i2c_transfer(state->i2c, &msg_post, 1) != 1) | ||
193 | { | ||
194 | printk("tda10023: unlock tuner fails\n"); | ||
195 | return -EREMOTEIO; | ||
196 | } | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0) | ||
201 | { | ||
202 | reg0 |= state->reg0 & 0x63; | ||
203 | |||
204 | tda10023_writereg (state, 0x00, reg0 & 0xfe); | ||
205 | tda10023_writereg (state, 0x00, reg0 | 0x01); | ||
206 | |||
207 | state->reg0 = reg0; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) | ||
212 | { | ||
213 | s32 BDR; | ||
214 | s32 BDRI; | ||
215 | s16 SFIL=0; | ||
216 | u16 NDEC = 0; | ||
217 | |||
218 | if (sr > (SYSCLK/(2*4))) | ||
219 | sr=SYSCLK/(2*4); | ||
220 | |||
221 | if (sr<870000) | ||
222 | sr=870000; | ||
223 | |||
224 | if (sr < (u32)(SYSCLK/98.40)) { | ||
225 | NDEC=3; | ||
226 | SFIL=1; | ||
227 | } else if (sr<(u32)(SYSCLK/64.0)) { | ||
228 | NDEC=3; | ||
229 | SFIL=0; | ||
230 | } else if (sr<(u32)(SYSCLK/49.2)) { | ||
231 | NDEC=2; | ||
232 | SFIL=1; | ||
233 | } else if (sr<(u32)(SYSCLK/32.0)) { | ||
234 | NDEC=2; | ||
235 | SFIL=0; | ||
236 | } else if (sr<(u32)(SYSCLK/24.6)) { | ||
237 | NDEC=1; | ||
238 | SFIL=1; | ||
239 | } else if (sr<(u32)(SYSCLK/16.0)) { | ||
240 | NDEC=1; | ||
241 | SFIL=0; | ||
242 | } else if (sr<(u32)(SYSCLK/12.3)) { | ||
243 | NDEC=0; | ||
244 | SFIL=1; | ||
245 | } | ||
246 | |||
247 | BDRI=SYSCLK*16; | ||
248 | BDRI>>=NDEC; | ||
249 | BDRI +=sr/2; | ||
250 | BDRI /=sr; | ||
251 | |||
252 | if (BDRI>255) | ||
253 | BDRI=255; | ||
254 | |||
255 | { | ||
256 | u64 BDRX; | ||
257 | |||
258 | BDRX=1<<(24+NDEC); | ||
259 | BDRX*=sr; | ||
260 | do_div(BDRX,SYSCLK); // BDRX/=SYSCLK; | ||
261 | |||
262 | BDR=(s32)BDRX; | ||
263 | } | ||
264 | // printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC); | ||
265 | tda10023_writebit (state, 0x03, 0xc0, NDEC<<6); | ||
266 | tda10023_writereg (state, 0x0a, BDR&255); | ||
267 | tda10023_writereg (state, 0x0b, (BDR>>8)&255); | ||
268 | tda10023_writereg (state, 0x0c, (BDR>>16)&31); | ||
269 | tda10023_writereg (state, 0x0d, BDRI); | ||
270 | tda10023_writereg (state, 0x3d, (SFIL<<7)); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int tda10023_init (struct dvb_frontend *fe) | ||
275 | { | ||
276 | struct tda10023_state* state = fe->demodulator_priv; | ||
277 | |||
278 | dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num); | ||
279 | |||
280 | tda10023_writetab(state, tda10023_inittab); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int tda10023_set_parameters (struct dvb_frontend *fe, | ||
286 | struct dvb_frontend_parameters *p) | ||
287 | { | ||
288 | struct tda10023_state* state = fe->demodulator_priv; | ||
289 | |||
290 | static int qamvals[6][6] = { | ||
291 | // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD | ||
292 | { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM | ||
293 | { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM | ||
294 | { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM | ||
295 | { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM | ||
296 | { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM | ||
297 | { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM | ||
298 | }; | ||
299 | |||
300 | int qam = p->u.qam.modulation; | ||
301 | |||
302 | if (qam < 0 || qam > 5) | ||
303 | return -EINVAL; | ||
304 | |||
305 | if (fe->ops.tuner_ops.set_params) { | ||
306 | fe->ops.tuner_ops.set_params(fe, p); | ||
307 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | ||
308 | } | ||
309 | |||
310 | tda10023_set_symbolrate (state, p->u.qam.symbol_rate); | ||
311 | tda10023_writereg (state, 0x05, qamvals[qam][1]); | ||
312 | tda10023_writereg (state, 0x08, qamvals[qam][2]); | ||
313 | tda10023_writereg (state, 0x09, qamvals[qam][3]); | ||
314 | tda10023_writereg (state, 0xb4, qamvals[qam][4]); | ||
315 | tda10023_writereg (state, 0xb6, qamvals[qam][5]); | ||
316 | |||
317 | // tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); | ||
318 | // tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); | ||
319 | tda10023_writebit (state, 0x04, 0x40, 0x40); | ||
320 | tda10023_setup_reg0 (state, qamvals[qam][0]); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
326 | { | ||
327 | struct tda10023_state* state = fe->demodulator_priv; | ||
328 | int sync; | ||
329 | |||
330 | *status = 0; | ||
331 | |||
332 | //0x11[1] == CARLOCK -> Carrier locked | ||
333 | //0x11[2] == FSYNC -> Frame synchronisation | ||
334 | //0x11[3] == FEL -> Front End locked | ||
335 | //0x11[6] == NODVB -> DVB Mode Information | ||
336 | sync = tda10023_readreg (state, 0x11); | ||
337 | |||
338 | if (sync & 2) | ||
339 | *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; | ||
340 | |||
341 | if (sync & 4) | ||
342 | *status |= FE_HAS_SYNC|FE_HAS_VITERBI; | ||
343 | |||
344 | if (sync & 8) | ||
345 | *status |= FE_HAS_LOCK; | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber) | ||
351 | { | ||
352 | struct tda10023_state* state = fe->demodulator_priv; | ||
353 | u8 a,b,c; | ||
354 | a=tda10023_readreg(state, 0x14); | ||
355 | b=tda10023_readreg(state, 0x15); | ||
356 | c=tda10023_readreg(state, 0x16)&0xf; | ||
357 | tda10023_writebit (state, 0x10, 0xc0, 0x00); | ||
358 | |||
359 | *ber = a | (b<<8)| (c<<16); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
364 | { | ||
365 | struct tda10023_state* state = fe->demodulator_priv; | ||
366 | u8 ifgain=tda10023_readreg(state, 0x2f); | ||
367 | |||
368 | u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16; | ||
369 | // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90 | ||
370 | if (gain>0x90) | ||
371 | gain=gain+2*(gain-0x90); | ||
372 | if (gain>255) | ||
373 | gain=255; | ||
374 | |||
375 | *strength = (gain<<8)|gain; | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr) | ||
380 | { | ||
381 | struct tda10023_state* state = fe->demodulator_priv; | ||
382 | |||
383 | u8 quality = ~tda10023_readreg(state, 0x18); | ||
384 | *snr = (quality << 8) | quality; | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
389 | { | ||
390 | struct tda10023_state* state = fe->demodulator_priv; | ||
391 | u8 a,b,c,d; | ||
392 | a= tda10023_readreg (state, 0x74); | ||
393 | b= tda10023_readreg (state, 0x75); | ||
394 | c= tda10023_readreg (state, 0x76); | ||
395 | d= tda10023_readreg (state, 0x77); | ||
396 | *ucblocks = a | (b<<8)|(c<<16)|(d<<24); | ||
397 | |||
398 | tda10023_writebit (state, 0x10, 0x20,0x00); | ||
399 | tda10023_writebit (state, 0x10, 0x20,0x20); | ||
400 | tda10023_writebit (state, 0x13, 0x01, 0x00); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
406 | { | ||
407 | struct tda10023_state* state = fe->demodulator_priv; | ||
408 | int sync,inv; | ||
409 | s8 afc = 0; | ||
410 | |||
411 | sync = tda10023_readreg(state, 0x11); | ||
412 | afc = tda10023_readreg(state, 0x19); | ||
413 | inv = tda10023_readreg(state, 0x04); | ||
414 | |||
415 | if (verbose) { | ||
416 | /* AFC only valid when carrier has been recovered */ | ||
417 | printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : | ||
418 | "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", | ||
419 | state->frontend.dvb->num, afc, | ||
420 | -((s32)p->u.qam.symbol_rate * afc) >> 10); | ||
421 | } | ||
422 | |||
423 | p->inversion = (inv&0x20?0:1); | ||
424 | p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; | ||
425 | |||
426 | p->u.qam.fec_inner = FEC_NONE; | ||
427 | p->frequency = ((p->frequency + 31250) / 62500) * 62500; | ||
428 | |||
429 | if (sync & 2) | ||
430 | p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int tda10023_sleep(struct dvb_frontend* fe) | ||
436 | { | ||
437 | struct tda10023_state* state = fe->demodulator_priv; | ||
438 | |||
439 | tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */ | ||
440 | tda10023_writereg (state, 0x00, 0x80); /* standby */ | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) | ||
446 | { | ||
447 | struct tda10023_state* state = fe->demodulator_priv; | ||
448 | |||
449 | if (enable) { | ||
450 | lock_tuner(state); | ||
451 | } else { | ||
452 | unlock_tuner(state); | ||
453 | } | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static void tda10023_release(struct dvb_frontend* fe) | ||
458 | { | ||
459 | struct tda10023_state* state = fe->demodulator_priv; | ||
460 | kfree(state); | ||
461 | } | ||
462 | |||
463 | static struct dvb_frontend_ops tda10023_ops; | ||
464 | |||
465 | struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, | ||
466 | struct i2c_adapter* i2c, | ||
467 | u8 pwm) | ||
468 | { | ||
469 | struct tda10023_state* state = NULL; | ||
470 | int i; | ||
471 | |||
472 | /* allocate memory for the internal state */ | ||
473 | state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL); | ||
474 | if (state == NULL) goto error; | ||
475 | |||
476 | /* setup the state */ | ||
477 | state->config = config; | ||
478 | state->i2c = i2c; | ||
479 | memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); | ||
480 | state->pwm = pwm; | ||
481 | for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) { | ||
482 | if (tda10023_inittab[i] == 0x00) { | ||
483 | state->reg0 = tda10023_inittab[i+2]; | ||
484 | break; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | // Wakeup if in standby | ||
489 | tda10023_writereg (state, 0x00, 0x33); | ||
490 | /* check if the demod is there */ | ||
491 | if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; | ||
492 | |||
493 | /* create dvb_frontend */ | ||
494 | memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); | ||
495 | state->frontend.demodulator_priv = state; | ||
496 | return &state->frontend; | ||
497 | |||
498 | error: | ||
499 | kfree(state); | ||
500 | return NULL; | ||
501 | } | ||
502 | |||
503 | static struct dvb_frontend_ops tda10023_ops = { | ||
504 | |||
505 | .info = { | ||
506 | .name = "Philips TDA10023 DVB-C", | ||
507 | .type = FE_QAM, | ||
508 | .frequency_stepsize = 62500, | ||
509 | .frequency_min = 51000000, | ||
510 | .frequency_max = 858000000, | ||
511 | .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ | ||
512 | .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ | ||
513 | .caps = 0x400 | //FE_CAN_QAM_4 | ||
514 | FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | | ||
515 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | | ||
516 | FE_CAN_FEC_AUTO | ||
517 | }, | ||
518 | |||
519 | .release = tda10023_release, | ||
520 | |||
521 | .init = tda10023_init, | ||
522 | .sleep = tda10023_sleep, | ||
523 | .i2c_gate_ctrl = tda10023_i2c_gate_ctrl, | ||
524 | |||
525 | .set_frontend = tda10023_set_parameters, | ||
526 | .get_frontend = tda10023_get_frontend, | ||
527 | |||
528 | .read_status = tda10023_read_status, | ||
529 | .read_ber = tda10023_read_ber, | ||
530 | .read_signal_strength = tda10023_read_signal_strength, | ||
531 | .read_snr = tda10023_read_snr, | ||
532 | .read_ucblocks = tda10023_read_ucblocks, | ||
533 | }; | ||
534 | |||
535 | |||
536 | MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver"); | ||
537 | MODULE_AUTHOR("Georg Acher, Hartmut Birr"); | ||
538 | MODULE_LICENSE("GPL"); | ||
539 | |||
540 | EXPORT_SYMBOL(tda10023_attach); | ||