]> err.no Git - linux-2.6/blob - drivers/media/dvb/frontends/drx397xD.c
V4L/DVB (7736): This patch adds support for the Micronas DRX3975D/DRX3977D DVB-T...
[linux-2.6] / drivers / media / dvb / frontends / drx397xD.c
1 /*
2  * Driver for Micronas drx397xD demodulator
3  *
4  * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #define DEBUG                   /* uncomment if you want debugging output */
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/moduleparam.h>
24 #include <linux/init.h>
25 #include <linux/device.h>
26 #include <linux/delay.h>
27 #include <linux/string.h>
28 #include <linux/firmware.h>
29
30 #include "dvb_frontend.h"
31 #include "drx397xD.h"
32
33 static const char mod_name[] = "drx397xD";
34
35 #define MAX_CLOCK_DRIFT         200     /* maximal 200 PPM allowed */
36
37 #define F_SET_0D0h      1
38 #define F_SET_0D4h      2
39
40 typedef enum fw_ix {
41 #define _FW_ENTRY(a, b)         b
42 #include "drx397xD_fw.h"
43 } fw_ix_t;
44
45 /* chip specifics */
46 struct drx397xD_state {
47         struct i2c_adapter *i2c;
48         struct dvb_frontend frontend;
49         struct drx397xD_config config;
50         fw_ix_t chip_rev;
51         int flags;
52         u32 bandwidth_parm;     /* internal bandwidth conversions */
53         u32 f_osc;              /* w90: actual osc frequency [Hz] */
54 };
55
56 /*******************************************************************************
57  * Firmware
58  ******************************************************************************/
59
60 static const char *blob_name[] = {
61 #define _BLOB_ENTRY(a, b)               a
62 #include "drx397xD_fw.h"
63 };
64
65 typedef enum blob_ix {
66 #define _BLOB_ENTRY(a, b)               b
67 #include "drx397xD_fw.h"
68 } blob_ix_t;
69
70 static struct {
71         const char *name;
72         const struct firmware *file;
73         rwlock_t lock;
74         int refcnt;
75         u8 *data[ARRAY_SIZE(blob_name)];
76 } fw[] = {
77 #define _FW_ENTRY(a, b)         {                       \
78                         .name   = a,                    \
79                         .file   = 0,                    \
80                         .lock   = RW_LOCK_UNLOCKED,     \
81                         .refcnt = 0,                    \
82                         .data   = { }           }
83 #include "drx397xD_fw.h"
84 };
85
86 /* use only with writer lock aquired */
87 static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
88 {
89         memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
90         if (fw[ix].file)
91                 release_firmware(fw[ix].file);
92 }
93
94 static void drx_release_fw(struct drx397xD_state *s)
95 {
96         fw_ix_t ix = s->chip_rev;
97
98         pr_debug("%s\n", __FUNCTION__);
99
100         write_lock(&fw[ix].lock);
101         if (fw[ix].refcnt) {
102                 fw[ix].refcnt--;
103                 if (fw[ix].refcnt == 0)
104                         _drx_release_fw(s, ix);
105         }
106         write_unlock(&fw[ix].lock);
107 }
108
109 static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
110 {
111         u8 *data;
112         size_t size, len;
113         int i = 0, j, rc = -EINVAL;
114
115         pr_debug("%s\n", __FUNCTION__);
116
117         if (ix < 0 || ix >= ARRAY_SIZE(fw))
118                 return -EINVAL;
119         s->chip_rev = ix;
120
121         write_lock(&fw[ix].lock);
122         if (fw[ix].file) {
123                 rc = 0;
124                 goto exit_ok;
125         }
126         memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
127
128         if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) {
129                 printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
130                        mod_name, fw[ix].name);
131                 rc = -ENOENT;
132                 goto exit_err;
133         }
134
135         if (!fw[ix].file->data || fw[ix].file->size < 10)
136                 goto exit_corrupt;
137
138         data = fw[ix].file->data;
139         size = fw[ix].file->size;
140
141         if (data[i++] != 2)     /* check firmware version */
142                 goto exit_corrupt;
143
144         do {
145                 switch (data[i++]) {
146                 case 0x00:      /* bytecode */
147                         if (i >= size)
148                                 break;
149                         i += data[i];
150                 case 0x01:      /* reset */
151                 case 0x02:      /* sleep */
152                         i++;
153                         break;
154                 case 0xfe:      /* name */
155                         len = strnlen(&data[i], size - i);
156                         if (i + len + 1 >= size)
157                                 goto exit_corrupt;
158                         if (data[i + len + 1] != 0)
159                                 goto exit_corrupt;
160                         for (j = 0; j < ARRAY_SIZE(blob_name); j++) {
161                                 if (strcmp(blob_name[j], &data[i]) == 0) {
162                                         fw[ix].data[j] = &data[i + len + 1];
163                                         pr_debug("Loading %s\n", blob_name[j]);
164                                 }
165                         }
166                         i += len + 1;
167                         break;
168                 case 0xff:      /* file terminator */
169                         if (i == size) {
170                                 rc = 0;
171                                 goto exit_ok;
172                         }
173                 default:
174                         goto exit_corrupt;
175                 }
176         } while (i < size);
177       exit_corrupt:
178         printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
179       exit_err:
180         _drx_release_fw(s, ix);
181         fw[ix].refcnt--;
182       exit_ok:
183         fw[ix].refcnt++;
184         write_unlock(&fw[ix].lock);
185         return rc;
186 }
187
188 /*******************************************************************************
189  * i2c bus IO
190  ******************************************************************************/
191
192 static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
193 {
194         struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 };
195         u8 *data;
196         int len, rc = 0, i = 0;
197
198         if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
199                 pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__);
200                 return -EINVAL;
201         }
202         pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]);
203
204         read_lock(&fw[s->chip_rev].lock);
205         data = fw[s->chip_rev].data[ix];
206         if (!data) {
207                 rc = -EINVAL;
208                 goto exit_rc;
209         }
210
211         for (;;) {
212                 switch (data[i++]) {
213                 case 0: /* bytecode */
214                         len = data[i++];
215                         msg.len = len;
216                         msg.buf = &data[i];
217                         if (i2c_transfer(s->i2c, &msg, 1) != 1) {
218                                 rc = -EIO;
219                                 goto exit_rc;
220                         }
221                         i += len;
222                         break;
223                 case 1: /* reset */
224                 case 2: /* sleep */
225                         i++;
226                         break;
227                 default:
228                         goto exit_rc;
229                 }
230         }
231       exit_rc:
232         read_unlock(&fw[s->chip_rev].lock);
233         return 0;
234 }
235
236 /* Function is not endian safe, use the RD16 wrapper below */
237 static int _read16(struct drx397xD_state *s, u32 i2c_adr)
238 {
239         int rc;
240         u8 a[4];
241         u16 v;
242         struct i2c_msg msg[2] = {
243                 {
244                  .addr = s->config.demod_address,
245                  .flags = 0,
246                  .buf = a,
247                  .len = sizeof(a)
248                  }
249                 , {
250                    .addr = s->config.demod_address,
251                    .flags = I2C_M_RD,
252                    .buf = (u8 *) & v,
253                    .len = sizeof(v)
254                    }
255         };
256
257         *(u32 *) a = i2c_adr;
258
259         rc = i2c_transfer(s->i2c, msg, 2);
260         if (rc != 2)
261                 return -EIO;
262
263         return le16_to_cpu(v);
264 }
265
266 /* Function is not endian safe, use the WR16.. wrappers below */
267 static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
268 {
269         u8 a[6];
270         int rc;
271         struct i2c_msg msg = {
272                 .addr = s->config.demod_address,
273                 .flags = 0,
274                 .buf = a,
275                 .len = sizeof(a)
276         };
277
278         *(u32 *) a = i2c_adr;
279         *(u16 *) & a[4] = val;
280
281         rc = i2c_transfer(s->i2c, &msg, 1);
282         if (rc != 1)
283                 return -EIO;
284         return 0;
285 }
286
287 #define WR16(ss,adr, val) \
288                 _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
289 #define WR16_E0(ss,adr, val) \
290                 _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
291 #define RD16(ss,adr) \
292                 _read16(ss, I2C_ADR_C0(adr))
293
294 #define EXIT_RC( cmd )  if ( (rc = (cmd)) < 0) goto exit_rc
295
296 /*******************************************************************************
297  * Tuner callback
298  ******************************************************************************/
299
300 static int PLL_Set(struct drx397xD_state *s,
301                    struct dvb_frontend_parameters *fep, int *df_tuner)
302 {
303         struct dvb_frontend *fe = &s->frontend;
304         u32 f_tuner, f = fep->frequency;
305         int rc;
306
307         pr_debug("%s\n", __FUNCTION__);
308
309         if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
310             (f < s->frontend.ops.tuner_ops.info.frequency_min))
311                 return -EINVAL;
312
313         *df_tuner = 0;
314         if (!s->frontend.ops.tuner_ops.set_params ||
315             !s->frontend.ops.tuner_ops.get_frequency)
316                 return -ENOSYS;
317
318         rc = s->frontend.ops.tuner_ops.set_params(fe, fep);
319         if (rc < 0)
320                 return rc;
321
322         rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner);
323         if (rc < 0)
324                 return rc;
325
326         *df_tuner = f_tuner - f;
327         pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f,
328                  f_tuner);
329
330         return 0;
331 }
332
333 /*******************************************************************************
334  * Demodulator helper functions
335  ******************************************************************************/
336
337 static int SC_WaitForReady(struct drx397xD_state *s)
338 {
339         int cnt = 1000;
340         int rc;
341
342         pr_debug("%s\n", __FUNCTION__);
343
344         while (cnt--) {
345                 rc = RD16(s, 0x820043);
346                 if (rc == 0)
347                         return 0;
348         }
349         return -1;
350 }
351
352 static int SC_SendCommand(struct drx397xD_state *s, int cmd)
353 {
354         int rc;
355
356         pr_debug("%s\n", __FUNCTION__);
357
358         WR16(s, 0x820043, cmd);
359         SC_WaitForReady(s);
360         rc = RD16(s, 0x820042);
361         if ((rc & 0xffff) == 0xffff)
362                 return -1;
363         return 0;
364 }
365
366 static int HI_Command(struct drx397xD_state *s, u16 cmd)
367 {
368         int rc, cnt = 1000;
369
370         pr_debug("%s\n", __FUNCTION__);
371
372         rc = WR16(s, 0x420032, cmd);
373         if (rc < 0)
374                 return rc;
375
376         do {
377                 rc = RD16(s, 0x420032);
378                 if (rc == 0) {
379                         rc = RD16(s, 0x420031);
380                         return rc;
381                 }
382                 if (rc < 0)
383                         return rc;
384         } while (--cnt);
385         return rc;
386 }
387
388 static int HI_CfgCommand(struct drx397xD_state *s)
389 {
390
391         pr_debug("%s\n", __FUNCTION__);
392
393         WR16(s, 0x420033, 0x3973);
394         WR16(s, 0x420034, s->config.w50);       // code 4, log 4
395         WR16(s, 0x420035, s->config.w52);       // code 15,  log 9
396         WR16(s, 0x420036, s->config.demod_address << 1);
397         WR16(s, 0x420037, s->config.w56);       // code (set_i2c ??  initX 1 ), log 1
398 //      WR16(s, 0x420033, 0x3973);
399         if ((s->config.w56 & 8) == 0)
400                 return HI_Command(s, 3);
401         return WR16(s, 0x420032, 0x3);
402 }
403
404 static const u8 fastIncrDecLUT_15273[] = {
405         0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14,
406         0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f
407 };
408
409 static const u8 slowIncrDecLUT_15272[] = {
410         3, 4, 4, 5, 6
411 };
412
413 static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
414 {
415         u16 w06 = agc->w06;
416         u16 w08 = agc->w08;
417         u16 w0A = agc->w0A;
418         u16 w0C = agc->w0C;
419         int quot, rem, i, rc = -EINVAL;
420
421         pr_debug("%s\n", __FUNCTION__);
422
423         if (agc->w04 > 0x3ff)
424                 goto exit_rc;
425
426         if (agc->d00 == 1) {
427                 EXIT_RC(RD16(s, 0x0c20010));
428                 rc &= ~0x10;
429                 EXIT_RC(WR16(s, 0x0c20010, rc));
430                 return WR16(s, 0x0c20030, agc->w04 & 0x7ff);
431         }
432
433         if (agc->d00 != 0)
434                 goto exit_rc;
435         if (w0A < w08)
436                 goto exit_rc;
437         if (w0A > 0x3ff)
438                 goto exit_rc;
439         if (w0C > 0x3ff)
440                 goto exit_rc;
441         if (w06 > 0x3ff)
442                 goto exit_rc;
443
444         EXIT_RC(RD16(s, 0x0c20010));
445         rc |= 0x10;
446         EXIT_RC(WR16(s, 0x0c20010, rc));
447
448         EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff));
449         EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1));
450         EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff));
451
452         quot = w0C / 113;
453         rem = w0C % 113;
454         if (quot <= 8) {
455                 quot = 8 - quot;
456         } else {
457                 quot = 0;
458                 rem += 113;
459         }
460
461         EXIT_RC(WR16(s, 0x0c20024, quot));
462
463         i = fastIncrDecLUT_15273[rem / 8];
464         EXIT_RC(WR16(s, 0x0c2002d, i));
465         EXIT_RC(WR16(s, 0x0c2002e, i));
466
467         i = slowIncrDecLUT_15272[rem / 28];
468         EXIT_RC(WR16(s, 0x0c2002b, i));
469         rc = WR16(s, 0x0c2002c, i);
470       exit_rc:
471         return rc;
472 }
473
474 static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
475 {
476         u16 w04 = agc->w04;
477         u16 w06 = agc->w06;
478         int rc = -1;
479
480         pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06);
481
482         if (w04 > 0x3ff)
483                 goto exit_rc;
484
485         switch (agc->d00) {
486         case 1:
487                 if (w04 == 0x3ff)
488                         w04 = 0x400;
489
490                 EXIT_RC(WR16(s, 0x0c20036, w04));
491                 s->config.w9C &= ~2;
492                 EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
493                 EXIT_RC(RD16(s, 0x0c20010));
494                 rc &= 0xbfdf;
495                 EXIT_RC(WR16(s, 0x0c20010, rc));
496                 EXIT_RC(RD16(s, 0x0c20013));
497                 rc &= ~2;
498                 break;
499         case 0:
500                 // loc_8000659
501                 s->config.w9C &= ~2;
502                 EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
503                 EXIT_RC(RD16(s, 0x0c20010));
504                 rc &= 0xbfdf;
505                 rc |= 0x4000;
506                 EXIT_RC(WR16(s, 0x0c20010, rc));
507                 EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f));
508                 EXIT_RC(RD16(s, 0x0c20013));
509                 rc &= ~2;
510                 break;
511         default:
512                 s->config.w9C |= 2;
513                 EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
514                 EXIT_RC(RD16(s, 0x0c20010));
515                 rc &= 0xbfdf;
516                 EXIT_RC(WR16(s, 0x0c20010, rc));
517
518                 EXIT_RC(WR16(s, 0x0c20036, 0));
519
520                 EXIT_RC(RD16(s, 0x0c20013));
521                 rc |= 2;
522         }
523         rc = WR16(s, 0x0c20013, rc);
524       exit_rc:
525         return rc;
526 }
527
528 static int GetLockStatus(struct drx397xD_state *s, int *lockstat)
529 {
530         int rc;
531
532         *lockstat = 0;
533
534         rc = RD16(s, 0x082004b);
535         if (rc < 0)
536                 return rc;
537
538         if (s->config.d60 != 2)
539                 return 0;
540
541         if ((rc & 7) == 7)
542                 *lockstat |= 1;
543         if ((rc & 3) == 3)
544                 *lockstat |= 2;
545         if (rc & 1)
546                 *lockstat |= 4;
547         return 0;
548 }
549
550 static int CorrectSysClockDeviation(struct drx397xD_state *s)
551 {
552         int rc = -EINVAL;
553         int lockstat;
554         u32 clk, clk_limit;
555
556         pr_debug("%s\n", __FUNCTION__);
557
558         if (s->config.d5C == 0) {
559                 EXIT_RC(WR16(s, 0x08200e8, 0x010));
560                 EXIT_RC(WR16(s, 0x08200e9, 0x113));
561                 s->config.d5C = 1;
562                 return rc;
563         }
564         if (s->config.d5C != 1)
565                 goto exit_rc;
566
567         rc = RD16(s, 0x0820048);
568
569         rc = GetLockStatus(s, &lockstat);
570         if (rc < 0)
571                 goto exit_rc;
572         if ((lockstat & 1) == 0)
573                 goto exit_rc;
574
575         EXIT_RC(WR16(s, 0x0420033, 0x200));
576         EXIT_RC(WR16(s, 0x0420034, 0xc5));
577         EXIT_RC(WR16(s, 0x0420035, 0x10));
578         EXIT_RC(WR16(s, 0x0420036, 0x1));
579         EXIT_RC(WR16(s, 0x0420037, 0xa));
580         EXIT_RC(HI_Command(s, 6));
581         EXIT_RC(RD16(s, 0x0420040));
582         clk = rc;
583         EXIT_RC(RD16(s, 0x0420041));
584         clk |= rc << 16;
585
586         if (clk <= 0x26ffff)
587                 goto exit_rc;
588         if (clk > 0x610000)
589                 goto exit_rc;
590
591         if (!s->bandwidth_parm)
592                 return -EINVAL;
593
594         /* round & convert to Hz */
595         clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21;
596         clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000;
597
598         if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
599                 s->f_osc = clk;
600                 pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__,
601                          s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
602         }
603         rc = WR16(s, 0x08200e8, 0);
604       exit_rc:
605         return rc;
606 }
607
608 static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
609 {
610         int rc, si, bp;
611
612         pr_debug("%s\n", __FUNCTION__);
613
614         si = s->config.wA0;
615         if (s->config.w98 == 0) {
616                 si |= 1;
617                 bp = 0;
618         } else {
619                 si &= ~1;
620                 bp = 0x200;
621         }
622         if (s->config.w9A == 0) {
623                 si |= 0x80;
624         } else {
625                 si &= ~0x80;
626         }
627
628         EXIT_RC(WR16(s, 0x2150045, 0));
629         EXIT_RC(WR16(s, 0x2150010, si));
630         EXIT_RC(WR16(s, 0x2150011, bp));
631         rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
632       exit_rc:
633         return rc;
634 }
635
636 static int drx_tune(struct drx397xD_state *s,
637                     struct dvb_frontend_parameters *fep)
638 {
639         u16 v22 = 0;
640         u16 v1C = 0;
641         u16 v1A = 0;
642         u16 v18 = 0;
643         u32 edi = 0, ebx = 0, ebp = 0, edx = 0;
644         u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0;
645
646         int rc, df_tuner;
647         int a, b, c, d;
648         pr_debug("%s %d\n", __FUNCTION__, s->config.d60);
649
650         if (s->config.d60 != 2)
651                 goto set_tuner;
652         rc = CorrectSysClockDeviation(s);
653         if (rc < 0)
654                 goto set_tuner;
655
656         s->config.d60 = 1;
657         rc = ConfigureMPEGOutput(s, 0);
658         if (rc < 0)
659                 goto set_tuner;
660       set_tuner:
661
662         rc = PLL_Set(s, fep, &df_tuner);
663         if (rc < 0) {
664                 printk(KERN_ERR "Error in pll_set\n");
665                 goto exit_rc;
666         }
667         msleep(200);
668
669         a = rc = RD16(s, 0x2150016);
670         if (rc < 0)
671                 goto exit_rc;
672         b = rc = RD16(s, 0x2150010);
673         if (rc < 0)
674                 goto exit_rc;
675         c = rc = RD16(s, 0x2150034);
676         if (rc < 0)
677                 goto exit_rc;
678         d = rc = RD16(s, 0x2150035);
679         if (rc < 0)
680                 goto exit_rc;
681         rc = WR16(s, 0x2150014, c);
682         rc = WR16(s, 0x2150015, d);
683         rc = WR16(s, 0x2150010, 0);
684         rc = WR16(s, 0x2150000, 2);
685         rc = WR16(s, 0x2150036, 0x0fff);
686         rc = WR16(s, 0x2150016, a);
687
688         rc = WR16(s, 0x2150010, 2);
689         rc = WR16(s, 0x2150007, 0);
690         rc = WR16(s, 0x2150000, 1);
691         rc = WR16(s, 0x2110000, 0);
692         rc = WR16(s, 0x0800000, 0);
693         rc = WR16(s, 0x2800000, 0);
694         rc = WR16(s, 0x2110010, 0x664);
695
696         rc = write_fw(s, DRXD_ResetECRAM);
697         rc = WR16(s, 0x2110000, 1);
698
699         rc = write_fw(s, DRXD_InitSC);
700         if (rc < 0)
701                 goto exit_rc;
702
703         rc = SetCfgIfAgc(s, &s->config.ifagc);
704         if (rc < 0)
705                 goto exit_rc;
706
707         rc = SetCfgRfAgc(s, &s->config.rfagc);
708         if (rc < 0)
709                 goto exit_rc;
710
711         if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K)
712                 v22 = 1;
713         switch (fep->u.ofdm.transmission_mode) {
714         case TRANSMISSION_MODE_8K:
715                 edi = 1;
716                 if (s->chip_rev == DRXD_FW_B1)
717                         break;
718
719                 rc = WR16(s, 0x2010010, 0);
720                 if (rc < 0)
721                         break;
722                 v1C = 0x63;
723                 v1A = 0x53;
724                 v18 = 0x43;
725                 break;
726         default:
727                 edi = 0;
728                 if (s->chip_rev == DRXD_FW_B1)
729                         break;
730
731                 rc = WR16(s, 0x2010010, 1);
732                 if (rc < 0)
733                         break;
734
735                 v1C = 0x61;
736                 v1A = 0x47;
737                 v18 = 0x41;
738         }
739
740         switch (fep->u.ofdm.guard_interval) {
741         case GUARD_INTERVAL_1_4:
742                 edi |= 0x0c;
743                 break;
744         case GUARD_INTERVAL_1_8:
745                 edi |= 0x08;
746                 break;
747         case GUARD_INTERVAL_1_16:
748                 edi |= 0x04;
749                 break;
750         case GUARD_INTERVAL_1_32:
751                 break;
752         default:
753                 v22 |= 2;
754         }
755
756         ebx = 0;
757         ebp = 0;
758         v20 = 0;
759         v1E = 0;
760         v16 = 0;
761         v14 = 0;
762         v12 = 0;
763         v10 = 0;
764         v0E = 0;
765
766         switch (fep->u.ofdm.hierarchy_information) {
767         case HIERARCHY_1:
768                 edi |= 0x40;
769                 if (s->chip_rev == DRXD_FW_B1)
770                         break;
771                 rc = WR16(s, 0x1c10047, 1);
772                 if (rc < 0)
773                         goto exit_rc;
774                 rc = WR16(s, 0x2010012, 1);
775                 if (rc < 0)
776                         goto exit_rc;
777                 ebx = 0x19f;
778                 ebp = 0x1fb;
779                 v20 = 0x0c0;
780                 v1E = 0x195;
781                 v16 = 0x1d6;
782                 v14 = 0x1ef;
783                 v12 = 4;
784                 v10 = 5;
785                 v0E = 5;
786                 break;
787         case HIERARCHY_2:
788                 edi |= 0x80;
789                 if (s->chip_rev == DRXD_FW_B1)
790                         break;
791                 rc = WR16(s, 0x1c10047, 2);
792                 if (rc < 0)
793                         goto exit_rc;
794                 rc = WR16(s, 0x2010012, 2);
795                 if (rc < 0)
796                         goto exit_rc;
797                 ebx = 0x08f;
798                 ebp = 0x12f;
799                 v20 = 0x0c0;
800                 v1E = 0x11e;
801                 v16 = 0x1d6;
802                 v14 = 0x15e;
803                 v12 = 4;
804                 v10 = 5;
805                 v0E = 5;
806                 break;
807         case HIERARCHY_4:
808                 edi |= 0xc0;
809                 if (s->chip_rev == DRXD_FW_B1)
810                         break;
811                 rc = WR16(s, 0x1c10047, 3);
812                 if (rc < 0)
813                         goto exit_rc;
814                 rc = WR16(s, 0x2010012, 3);
815                 if (rc < 0)
816                         goto exit_rc;
817                 ebx = 0x14d;
818                 ebp = 0x197;
819                 v20 = 0x0c0;
820                 v1E = 0x1ce;
821                 v16 = 0x1d6;
822                 v14 = 0x11a;
823                 v12 = 4;
824                 v10 = 6;
825                 v0E = 5;
826                 break;
827         default:
828                 v22 |= 8;
829                 if (s->chip_rev == DRXD_FW_B1)
830                         break;
831                 rc = WR16(s, 0x1c10047, 0);
832                 if (rc < 0)
833                         goto exit_rc;
834                 rc = WR16(s, 0x2010012, 0);
835                 if (rc < 0)
836                         goto exit_rc;
837                 //              QPSK    QAM16   QAM64
838                 ebx = 0x19f;    //                 62
839                 ebp = 0x1fb;    //                 15
840                 v20 = 0x16a;    //  62
841                 v1E = 0x195;    //         62
842                 v16 = 0x1bb;    //  15
843                 v14 = 0x1ef;    //         15
844                 v12 = 5;        //  16
845                 v10 = 5;        //         16
846                 v0E = 5;        //                 16
847         }
848
849         switch (fep->u.ofdm.constellation) {
850         default:
851                 v22 |= 4;
852         case QPSK:
853                 if (s->chip_rev == DRXD_FW_B1)
854                         break;
855
856                 rc = WR16(s, 0x1c10046, 0);
857                 if (rc < 0)
858                         goto exit_rc;
859                 rc = WR16(s, 0x2010011, 0);
860                 if (rc < 0)
861                         goto exit_rc;
862                 rc = WR16(s, 0x201001a, 0x10);
863                 if (rc < 0)
864                         goto exit_rc;
865                 rc = WR16(s, 0x201001b, 0);
866                 if (rc < 0)
867                         goto exit_rc;
868                 rc = WR16(s, 0x201001c, 0);
869                 if (rc < 0)
870                         goto exit_rc;
871                 rc = WR16(s, 0x1c10062, v20);
872                 if (rc < 0)
873                         goto exit_rc;
874                 rc = WR16(s, 0x1c1002a, v1C);
875                 if (rc < 0)
876                         goto exit_rc;
877                 rc = WR16(s, 0x1c10015, v16);
878                 if (rc < 0)
879                         goto exit_rc;
880                 rc = WR16(s, 0x1c10016, v12);
881                 if (rc < 0)
882                         goto exit_rc;
883                 break;
884         case QAM_16:
885                 edi |= 0x10;
886                 if (s->chip_rev == DRXD_FW_B1)
887                         break;
888
889                 rc = WR16(s, 0x1c10046, 1);
890                 if (rc < 0)
891                         goto exit_rc;
892                 rc = WR16(s, 0x2010011, 1);
893                 if (rc < 0)
894                         goto exit_rc;
895                 rc = WR16(s, 0x201001a, 0x10);
896                 if (rc < 0)
897                         goto exit_rc;
898                 rc = WR16(s, 0x201001b, 4);
899                 if (rc < 0)
900                         goto exit_rc;
901                 rc = WR16(s, 0x201001c, 0);
902                 if (rc < 0)
903                         goto exit_rc;
904                 rc = WR16(s, 0x1c10062, v1E);
905                 if (rc < 0)
906                         goto exit_rc;
907                 rc = WR16(s, 0x1c1002a, v1A);
908                 if (rc < 0)
909                         goto exit_rc;
910                 rc = WR16(s, 0x1c10015, v14);
911                 if (rc < 0)
912                         goto exit_rc;
913                 rc = WR16(s, 0x1c10016, v10);
914                 if (rc < 0)
915                         goto exit_rc;
916                 break;
917         case QAM_64:
918                 edi |= 0x20;
919                 rc = WR16(s, 0x1c10046, 2);
920                 if (rc < 0)
921                         goto exit_rc;
922                 rc = WR16(s, 0x2010011, 2);
923                 if (rc < 0)
924                         goto exit_rc;
925                 rc = WR16(s, 0x201001a, 0x20);
926                 if (rc < 0)
927                         goto exit_rc;
928                 rc = WR16(s, 0x201001b, 8);
929                 if (rc < 0)
930                         goto exit_rc;
931                 rc = WR16(s, 0x201001c, 2);
932                 if (rc < 0)
933                         goto exit_rc;
934                 rc = WR16(s, 0x1c10062, ebx);
935                 if (rc < 0)
936                         goto exit_rc;
937                 rc = WR16(s, 0x1c1002a, v18);
938                 if (rc < 0)
939                         goto exit_rc;
940                 rc = WR16(s, 0x1c10015, ebp);
941                 if (rc < 0)
942                         goto exit_rc;
943                 rc = WR16(s, 0x1c10016, v0E);
944                 if (rc < 0)
945                         goto exit_rc;
946                 break;
947         }
948
949         if (s->config.s20d24 == 1) {
950                 rc = WR16(s, 0x2010013, 0);
951         } else {
952                 rc = WR16(s, 0x2010013, 1);
953                 edi |= 0x1000;
954         }
955
956         switch (fep->u.ofdm.code_rate_HP) {
957         default:
958                 v22 |= 0x10;
959         case FEC_1_2:
960                 if (s->chip_rev == DRXD_FW_B1)
961                         break;
962                 rc = WR16(s, 0x2090011, 0);
963                 break;
964         case FEC_2_3:
965                 edi |= 0x200;
966                 if (s->chip_rev == DRXD_FW_B1)
967                         break;
968                 rc = WR16(s, 0x2090011, 1);
969                 break;
970         case FEC_3_4:
971                 edi |= 0x400;
972                 if (s->chip_rev == DRXD_FW_B1)
973                         break;
974                 rc = WR16(s, 0x2090011, 2);
975                 break;
976         case FEC_5_6:           /* 5 */
977                 edi |= 0x600;
978                 if (s->chip_rev == DRXD_FW_B1)
979                         break;
980                 rc = WR16(s, 0x2090011, 3);
981                 break;
982         case FEC_7_8:           /* 7 */
983                 edi |= 0x800;
984                 if (s->chip_rev == DRXD_FW_B1)
985                         break;
986                 rc = WR16(s, 0x2090011, 4);
987                 break;
988         };
989         if (rc < 0)
990                 goto exit_rc;
991
992         switch (fep->u.ofdm.bandwidth) {
993         default:
994                 rc = -EINVAL;
995                 goto exit_rc;
996         case BANDWIDTH_8_MHZ:   /* 0 */
997         case BANDWIDTH_AUTO:
998                 rc = WR16(s, 0x0c2003f, 0x32);
999                 s->bandwidth_parm = ebx = 0x8b8249;     // 9142857
1000                 edx = 0;
1001                 break;
1002         case BANDWIDTH_7_MHZ:
1003                 rc = WR16(s, 0x0c2003f, 0x3b);
1004                 s->bandwidth_parm = ebx = 0x7a1200;     // 8000000
1005                 edx = 0x4807;
1006                 break;
1007         case BANDWIDTH_6_MHZ:
1008                 rc = WR16(s, 0x0c2003f, 0x47);
1009                 s->bandwidth_parm = ebx = 0x68a1b6;     // 6857142
1010                 edx = 0x0f07;
1011                 break;
1012         };
1013
1014         if (rc < 0)
1015                 goto exit_rc;
1016
1017         rc = WR16(s, 0x08200ec, edx);
1018         if (rc < 0)
1019                 goto exit_rc;
1020
1021         rc = RD16(s, 0x0820050);
1022         if (rc < 0)
1023                 goto exit_rc;
1024         rc = WR16(s, 0x0820050, rc);
1025
1026         {
1027                 long dummy;
1028
1029                 /* Configure bandwidth specific factor */
1030                 ebx = div_ll_X_l_rem(((u64) (s->f_osc) << 21) + (ebx >> 1),
1031                                      ebx, &dummy) - 0x800000;
1032                 EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff));
1033                 EXIT_RC(WR16(s, 0x0c50011, ebx >> 16));
1034
1035                 /* drx397xD oscillator calibration */
1036                 ebx = div_ll_X_l_rem(((u64) (s->config.f_if + df_tuner) << 28) +
1037                                      (s->f_osc >> 1), s->f_osc, &dummy);
1038         }
1039         ebx &= 0xfffffff;
1040         if (fep->inversion == INVERSION_ON)
1041                 ebx = 0x10000000 - ebx;
1042
1043         EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff));
1044         EXIT_RC(WR16(s, 0x0c30011, ebx >> 16));
1045
1046         EXIT_RC(WR16(s, 0x0800000, 1));
1047         EXIT_RC(RD16(s, 0x0800000));
1048
1049
1050         EXIT_RC(SC_WaitForReady(s));
1051         EXIT_RC(WR16(s, 0x0820042, 0));
1052         EXIT_RC(WR16(s, 0x0820041, v22));
1053         EXIT_RC(WR16(s, 0x0820040, edi));
1054         EXIT_RC(SC_SendCommand(s, 3));
1055
1056         rc = RD16(s, 0x0800000);
1057
1058         SC_WaitForReady(s);
1059         WR16(s, 0x0820042, 0);
1060         WR16(s, 0x0820041, 1);
1061         WR16(s, 0x0820040, 1);
1062         SC_SendCommand(s, 1);
1063
1064 //      rc = WR16(s, 0x2150000, 1);
1065 //      if (rc < 0) goto exit_rc;
1066
1067         rc = WR16(s, 0x2150000, 2);
1068         rc = WR16(s, 0x2150016, a);
1069         rc = WR16(s, 0x2150010, 4);
1070         rc = WR16(s, 0x2150036, 0);
1071         rc = WR16(s, 0x2150000, 1);
1072         s->config.d60 = 2;
1073       exit_rc:
1074         return rc;
1075 }
1076
1077 /*******************************************************************************
1078  * DVB interface
1079  ******************************************************************************/
1080
1081 static int drx397x_init(struct dvb_frontend *fe)
1082 {
1083         struct drx397xD_state *s = fe->demodulator_priv;
1084         int rc;
1085
1086         pr_debug("%s\n", __FUNCTION__);
1087
1088         s->config.rfagc.d00 = 2;        /* 0x7c */
1089         s->config.rfagc.w04 = 0;
1090         s->config.rfagc.w06 = 0x3ff;
1091
1092         s->config.ifagc.d00 = 0;        /* 0x68 */
1093         s->config.ifagc.w04 = 0;
1094         s->config.ifagc.w06 = 140;
1095         s->config.ifagc.w08 = 0;
1096         s->config.ifagc.w0A = 0x3ff;
1097         s->config.ifagc.w0C = 0x388;
1098
1099         /* for signal strenght calculations */
1100         s->config.ss76 = 820;
1101         s->config.ss78 = 2200;
1102         s->config.ss7A = 150;
1103
1104         /* HI_CfgCommand */
1105         s->config.w50 = 4;
1106         s->config.w52 = 9;      // 0xf;
1107
1108         s->config.f_if = 42800000;      /* d14: intermediate frequency [Hz]     */
1109         s->config.f_osc = 48000;        /* s66 : oscillator frequency [kHz]     */
1110         s->config.w92 = 12000;  // 20000;
1111
1112         s->config.w9C = 0x000e;
1113         s->config.w9E = 0x0000;
1114
1115         /* ConfigureMPEGOutput params */
1116         s->config.wA0 = 4;
1117         s->config.w98 = 1;      // 0;
1118         s->config.w9A = 1;
1119
1120         /* get chip revision */
1121         rc = RD16(s, 0x2410019);
1122         if (rc < 0)
1123                 return -ENODEV;
1124
1125         if (rc == 0) {
1126                 printk(KERN_INFO "%s: chip revision A2\n", mod_name);
1127                 rc = drx_load_fw(s, DRXD_FW_A2);
1128         } else {
1129
1130                 rc = (rc >> 12) - 3;
1131                 switch (rc) {
1132                 case 1:
1133                         s->flags |= F_SET_0D4h;
1134                 case 0:
1135                 case 4:
1136                         s->flags |= F_SET_0D0h;
1137                         break;
1138                 case 2:
1139                 case 5:
1140                         break;
1141                 case 3:
1142                         s->flags |= F_SET_0D4h;
1143                         break;
1144                 default:
1145                         return -ENODEV;
1146                 };
1147                 printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc);
1148                 rc = drx_load_fw(s, DRXD_FW_B1);
1149         }
1150         if (rc < 0)
1151                 goto error;
1152
1153         rc = WR16(s, 0x0420033, 0x3973);
1154         if (rc < 0)
1155                 goto error;
1156
1157         rc = HI_Command(s, 2);
1158
1159         msleep(1);
1160
1161         if (s->chip_rev == DRXD_FW_A2) {
1162                 rc = WR16(s, 0x043012d, 0x47F);
1163                 if (rc < 0)
1164                         goto error;
1165         }
1166         rc = WR16_E0(s, 0x0400000, 0);
1167         if (rc < 0)
1168                 goto error;
1169
1170         if (s->config.w92 > 20000 || s->config.w92 % 4000) {
1171                 printk(KERN_ERR "%s: invalid osc frequency\n", mod_name);
1172                 rc = -1;
1173                 goto error;
1174         }
1175
1176         rc = WR16(s, 0x2410010, 1);
1177         if (rc < 0)
1178                 goto error;
1179         rc = WR16(s, 0x2410011, 0x15);
1180         if (rc < 0)
1181                 goto error;
1182         rc = WR16(s, 0x2410012, s->config.w92 / 4000);
1183         if (rc < 0)
1184                 goto error;
1185 #ifdef ORIG_FW
1186         rc = WR16(s, 0x2410015, 2);
1187         if (rc < 0)
1188                 goto error;
1189 #endif
1190         rc = WR16(s, 0x2410017, 0x3973);
1191         if (rc < 0)
1192                 goto error;
1193
1194         s->f_osc = s->config.f_osc * 1000;      /* initial estimator */
1195
1196         s->config.w56 = 1;
1197
1198         rc = HI_CfgCommand(s);
1199         if (rc < 0)
1200                 goto error;
1201
1202         rc = write_fw(s, DRXD_InitAtomicRead);
1203         if (rc < 0)
1204                 goto error;
1205
1206         if (s->chip_rev == DRXD_FW_A2) {
1207                 rc = WR16(s, 0x2150013, 0);
1208                 if (rc < 0)
1209                         goto error;
1210         }
1211
1212         rc = WR16_E0(s, 0x0400002, 0);
1213         if (rc < 0)
1214                 goto error;
1215         rc = WR16(s, 0x0400002, 0);
1216         if (rc < 0)
1217                 goto error;
1218
1219         if (s->chip_rev == DRXD_FW_A2) {
1220                 rc = write_fw(s, DRXD_ResetCEFR);
1221                 if (rc < 0)
1222                         goto error;
1223         }
1224         rc = write_fw(s, DRXD_microcode);
1225         if (rc < 0)
1226                 goto error;
1227
1228         s->config.w9C = 0x0e;
1229         if (s->flags & F_SET_0D0h) {
1230                 s->config.w9C = 0;
1231                 rc = RD16(s, 0x0c20010);
1232                 if (rc < 0)
1233                         goto write_DRXD_InitFE_1;
1234
1235                 rc &= ~0x1000;
1236                 rc = WR16(s, 0x0c20010, rc);
1237                 if (rc < 0)
1238                         goto write_DRXD_InitFE_1;
1239
1240                 rc = RD16(s, 0x0c20011);
1241                 if (rc < 0)
1242                         goto write_DRXD_InitFE_1;
1243
1244                 rc &= ~0x8;
1245                 rc = WR16(s, 0x0c20011, rc);
1246                 if (rc < 0)
1247                         goto write_DRXD_InitFE_1;
1248
1249                 rc = WR16(s, 0x0c20012, 1);
1250         }
1251
1252       write_DRXD_InitFE_1:
1253
1254         rc = write_fw(s, DRXD_InitFE_1);
1255         if (rc < 0)
1256                 goto error;
1257
1258         rc = 1;
1259         if (s->chip_rev == DRXD_FW_B1) {
1260                 if (s->flags & F_SET_0D0h)
1261                         rc = 0;
1262         } else {
1263                 if (s->flags & F_SET_0D0h)
1264                         rc = 4;
1265         }
1266
1267         rc = WR16(s, 0x0C20012, rc);
1268         if (rc < 0)
1269                 goto error;
1270
1271         rc = WR16(s, 0x0C20013, s->config.w9E);
1272         if (rc < 0)
1273                 goto error;
1274         rc = WR16(s, 0x0C20015, s->config.w9C);
1275         if (rc < 0)
1276                 goto error;
1277
1278         rc = write_fw(s, DRXD_InitFE_2);
1279         if (rc < 0)
1280                 goto error;
1281         rc = write_fw(s, DRXD_InitFT);
1282         if (rc < 0)
1283                 goto error;
1284         rc = write_fw(s, DRXD_InitCP);
1285         if (rc < 0)
1286                 goto error;
1287         rc = write_fw(s, DRXD_InitCE);
1288         if (rc < 0)
1289                 goto error;
1290         rc = write_fw(s, DRXD_InitEQ);
1291         if (rc < 0)
1292                 goto error;
1293         rc = write_fw(s, DRXD_InitEC);
1294         if (rc < 0)
1295                 goto error;
1296         rc = write_fw(s, DRXD_InitSC);
1297         if (rc < 0)
1298                 goto error;
1299
1300         rc = SetCfgIfAgc(s, &s->config.ifagc);
1301         if (rc < 0)
1302                 goto error;
1303
1304         rc = SetCfgRfAgc(s, &s->config.rfagc);
1305         if (rc < 0)
1306                 goto error;
1307
1308         rc = ConfigureMPEGOutput(s, 1);
1309         rc = WR16(s, 0x08201fe, 0x0017);
1310         rc = WR16(s, 0x08201ff, 0x0101);
1311
1312         s->config.d5C = 0;
1313         s->config.d60 = 1;
1314         s->config.d48 = 1;
1315       error:
1316         return rc;
1317 }
1318
1319 static int drx397x_get_frontend(struct dvb_frontend *fe,
1320                                 struct dvb_frontend_parameters *params)
1321 {
1322         return 0;
1323 }
1324
1325 static int drx397x_set_frontend(struct dvb_frontend *fe,
1326                                 struct dvb_frontend_parameters *params)
1327 {
1328         struct drx397xD_state *s = fe->demodulator_priv;
1329
1330         s->config.s20d24 = 1;   // 0;
1331         return drx_tune(s, params);
1332 }
1333
1334 static int drx397x_get_tune_settings(struct dvb_frontend *fe,
1335                                      struct dvb_frontend_tune_settings
1336                                      *fe_tune_settings)
1337 {
1338         fe_tune_settings->min_delay_ms = 10000;
1339         fe_tune_settings->step_size = 0;
1340         fe_tune_settings->max_drift = 0;
1341         return 0;
1342 }
1343
1344 static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
1345 {
1346         struct drx397xD_state *s = fe->demodulator_priv;
1347         int lockstat;
1348
1349         GetLockStatus(s, &lockstat);
1350         /* TODO */
1351 //      if (lockstat & 1)
1352 //      CorrectSysClockDeviation(s);
1353
1354         *status = 0;
1355         if (lockstat & 2) {
1356                 CorrectSysClockDeviation(s);
1357                 ConfigureMPEGOutput(s, 1);
1358                 *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
1359         }
1360         if (lockstat & 4) {
1361                 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
1362         }
1363
1364         return 0;
1365 }
1366
1367 static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
1368 {
1369         *ber = 0;
1370         return 0;
1371 }
1372
1373 static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr)
1374 {
1375         *snr = 0;
1376         return 0;
1377 }
1378
1379 static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
1380 {
1381         struct drx397xD_state *s = fe->demodulator_priv;
1382         int rc;
1383
1384         if (s->config.ifagc.d00 == 2) {
1385                 *strength = 0xffff;
1386                 return 0;
1387         }
1388         rc = RD16(s, 0x0c20035);
1389         if (rc < 0) {
1390                 *strength = 0;
1391                 return 0;
1392         }
1393         rc &= 0x3ff;
1394         /* Signal strength is calculated using the following formula:
1395          *
1396          * a = 2200 * 150 / (2200 + 150);
1397          * a = a * 3300 /  (a + 820);
1398          * b = 2200 * 3300 / (2200 + 820);
1399          * c = (((b-a) * rc) >> 10  + a) << 4;
1400          * strength = ~c & 0xffff;
1401          *
1402          * The following does the same but with less rounding errors:
1403          */
1404         *strength = ~(7720 + (rc * 30744 >> 10));
1405         return 0;
1406 }
1407
1408 static int drx397x_read_ucblocks(struct dvb_frontend *fe,
1409                                  unsigned int *ucblocks)
1410 {
1411         *ucblocks = 0;
1412         return 0;
1413 }
1414
1415 static int drx397x_sleep(struct dvb_frontend *fe)
1416 {
1417         return 0;
1418 }
1419
1420 static void drx397x_release(struct dvb_frontend *fe)
1421 {
1422         struct drx397xD_state *s = fe->demodulator_priv;
1423         printk(KERN_INFO "%s: release demodulator\n", mod_name);
1424         if (s) {
1425                 drx_release_fw(s);
1426                 kfree(s);
1427         }
1428
1429 }
1430
1431 static struct dvb_frontend_ops drx397x_ops = {
1432
1433         .info = {
1434                  .name                  = "Micronas DRX397xD DVB-T Frontend",
1435                  .type                  = FE_OFDM,
1436                  .frequency_min         = 47125000,
1437                  .frequency_max         = 855250000,
1438                  .frequency_stepsize    = 166667,
1439                  .frequency_tolerance   = 0,
1440                  .caps =                                        /* 0x0C01B2EAE */
1441                          FE_CAN_FEC_1_2                 |       // = 0x2,
1442                          FE_CAN_FEC_2_3                 |       // = 0x4,
1443                          FE_CAN_FEC_3_4                 |       // = 0x8,
1444                          FE_CAN_FEC_5_6                 |       // = 0x20,
1445                          FE_CAN_FEC_7_8                 |       // = 0x80,
1446                          FE_CAN_FEC_AUTO                |       // = 0x200,
1447                          FE_CAN_QPSK                    |       // = 0x400,
1448                          FE_CAN_QAM_16                  |       // = 0x800,
1449                          FE_CAN_QAM_64                  |       // = 0x2000,
1450                          FE_CAN_QAM_AUTO                |       // = 0x10000,
1451                          FE_CAN_TRANSMISSION_MODE_AUTO  |       // = 0x20000,
1452                          FE_CAN_GUARD_INTERVAL_AUTO     |       // = 0x80000,
1453                          FE_CAN_HIERARCHY_AUTO          |       // = 0x100000,
1454                          FE_CAN_RECOVER                 |       // = 0x40000000,
1455                          FE_CAN_MUTE_TS                         // = 0x80000000
1456          },
1457
1458         .release = drx397x_release,
1459         .init = drx397x_init,
1460         .sleep = drx397x_sleep,
1461
1462         .set_frontend = drx397x_set_frontend,
1463         .get_tune_settings = drx397x_get_tune_settings,
1464         .get_frontend = drx397x_get_frontend,
1465
1466         .read_status = drx397x_read_status,
1467         .read_snr = drx397x_read_snr,
1468         .read_signal_strength = drx397x_read_signal_strength,
1469         .read_ber = drx397x_read_ber,
1470         .read_ucblocks = drx397x_read_ucblocks,
1471 };
1472
1473 struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
1474                                      struct i2c_adapter *i2c)
1475 {
1476         struct drx397xD_state *s = NULL;
1477
1478         /* allocate memory for the internal state */
1479         s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
1480         if (s == NULL)
1481                 goto error;
1482
1483         /* setup the state */
1484         s->i2c = i2c;
1485         memcpy(&s->config, config, sizeof(struct drx397xD_config));
1486
1487         /* check if the demod is there */
1488         if (RD16(s, 0x2410019) < 0)
1489                 goto error;
1490
1491         /* create dvb_frontend */
1492         memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops));
1493         s->frontend.demodulator_priv = s;
1494
1495         return &s->frontend;
1496       error:
1497         kfree(s);
1498         return NULL;
1499 }
1500
1501 MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
1502 MODULE_AUTHOR("Henk Vergonet");
1503 MODULE_LICENSE("GPL");
1504
1505 EXPORT_SYMBOL(drx397xD_attach);