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