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