tda1004x.c revision f4546e702a89d2e483570f0f16c5155bb781cc38
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  /*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Driver for Philips tda1004xh OFDM Demodulator
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     it under the terms of the GNU General Public License as published by
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     the Free Software Foundation; either version 2 of the License, or
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     This program is distributed in the hope that it will be useful,
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     but WITHOUT ANY WARRANTY; without even the implied warranty of
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     GNU General Public License for more details.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     You should have received a copy of the GNU General Public License
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     along with this program; if not, write to the Free Software
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   */
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver needs external firmware. Please use the commands
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
2612e66f6573beda52a434b757df5b7a5a05b9ebd2Ville Skytt\� * download/extract them, and then copy them to /usr/lib/hotplug/firmware
2712e66f6573beda52a434b757df5b7a5a05b9ebd2Ville Skytt\� * or /lib/firmware (depending on configuration of firmware hotplug).
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
364e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/jiffies.h>
374e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/string.h>
384e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/slab.h>
394e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvb_frontend.h"
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tda1004x.h"
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(args...) \
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do { \
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (debug) printk(KERN_DEBUG "tda1004x: " args); \
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (0)
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CHIPID		 0x00
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_AUTO		 0x01
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_IN_CONF1	 0x02
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_IN_CONF2	 0x03
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_OUT_CONF1	 0x04
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_OUT_CONF2	 0x05
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_STATUS_CD	 0x06
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFC4		 0x07
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSSPARE2	 0x0C
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CODE_IN	 0x0D
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_FWPAGE	 0x0E
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_SCAN_CPT	 0x10
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_CMD	 0x11
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_ARG	 0x12
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_DATA1	 0x13
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_DATA2	 0x14
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFADC1	 0x15
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFC1		 0x16
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_S_AGC		 0x1a
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_TUN_LEVEL	 0x1a
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_SNR		 0x1c
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONF_TS1	 0x1e
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONF_TS2	 0x1f
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CBER_RESET	 0x20
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CBER_MSB	 0x21
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CBER_LSB	 0x22
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CVBER_LUT	 0x23
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_VBER_MSB	 0x24
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_VBER_MID	 0x25
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_VBER_LSB	 0x26
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_UNCOR		 0x27
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_P	 0x2D
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_M_MSB	 0x2E
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_M_LSB	 0x2F
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_N	 0x30
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONFPLL1	 0x2D
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONFPLL2	 0x2F
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONFPLL3	 0x30
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF1	 0x31
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF2	 0x32
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF3	 0x33
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF4	 0x34
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF5	 0x35
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_UNSURW_MSB	 0x31
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_UNSURW_LSB	 0x32
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_WREF_MSB	 0x33
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_WREF_MID	 0x34
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_WREF_LSB	 0x35
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_MUXOUT	 0x36
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFADC2	 0x37
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_IOFFSET	 0x38
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONF_TRISTATE1 0x3B
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONF_TRISTATE2 0x3C
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONF_POLARITY	 0x3D
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_FREQ_OFFSET	 0x3E
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_GPIO_OUT_SEL	 0x41
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_GPIO_SELECT	 0x42
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_CONF	 0x43
112f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann#define TDA10046H_AGC_THR	 0x44
113f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann#define TDA10046H_AGC_RENORM	 0x45
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_GAINS	 0x46
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_TUN_MIN	 0x47
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_TUN_MAX	 0x48
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_IF_MIN	 0x49
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_IF_MAX	 0x4A
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_FREQ_PHY2_MSB	 0x4D
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_FREQ_PHY2_LSB	 0x4E
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CVBER_CTRL	 0x4F
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_IF_LEVEL	 0x52
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CODE_CPT	 0x57
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CODE_IN	 0x58
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[] = { reg, data };
1337f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg.addr = state->config->demod_address;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = i2c_transfer(state->i2c, &msg, 1);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 1)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			__FUNCTION__, reg, data, ret);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg, data, ret);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (ret != 1) ? -1 : 0;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_byte(struct tda1004x_state *state, int reg)
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b0[] = { reg };
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b1[] = { 0 };
1547f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
1557f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[0].addr = state->config->demod_address;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[1].addr = state->config->demod_address;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = i2c_transfer(state->i2c, msg, 2);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 2) {
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg, b1[0], ret);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return b1[0];
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask, data);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read a byte and check
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = tda1004x_read_byte(state, reg);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < 0)
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return val;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// mask if off
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = val & ~mask;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= data & 0xff;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// write it out again
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tda1004x_write_byteI(state, reg, val);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: reg=0x%x, len=0x%x\n", __FUNCTION__, reg, len);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = 0;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < len; i++) {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = tda1004x_write_byteI(state, reg + i, buf[i]);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result != 0)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
2160eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	msleep(20);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10045h_set_bandwidth(struct tda1004x_state *state,
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   fe_bandwidth_t bandwidth)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (bandwidth) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_6_MHZ:
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_7_MHZ:
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_8_MHZ:
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10046h_set_bandwidth(struct tda1004x_state *state,
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   fe_bandwidth_t bandwidth)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2598a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
2608a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
2618a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
2628a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
2638a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
2648a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
2658a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
2668a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	int tda10046_clk53m;
2678a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
2688a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if ((state->config->if_freq == TDA10046_FREQ_045) ||
2698a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	    (state->config->if_freq == TDA10046_FREQ_052))
2708a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 0;
2718a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	else
2728a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 1;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (bandwidth) {
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_6_MHZ:
2758a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		if (tda10046_clk53m)
2768a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
27750c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_6mhz_53M));
2788a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		else
2798a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
28050c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_6mhz_48M));
281f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		if (state->config->if_freq == TDA10046_FREQ_045) {
2828a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
2838a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
284f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_7_MHZ:
2888a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		if (tda10046_clk53m)
2898a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
29050c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_7mhz_53M));
2918a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		else
2928a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
29350c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_7mhz_48M));
294f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		if (state->config->if_freq == TDA10046_FREQ_045) {
2958a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
2968a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
297f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_8_MHZ:
3018a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		if (tda10046_clk53m)
3028a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
30350c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_8mhz_53M));
3048a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		else
3058a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
30650c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_8mhz_48M));
307f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		if (state->config->if_freq == TDA10046_FREQ_045) {
3088a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
3098a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
310f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_do_upload(struct tda1004x_state *state,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unsigned char *mem, unsigned int len,
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      u8 dspCodeCounterReg, u8 dspCodeInReg)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[65];
3257f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tx_size;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pos = 0;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear code counter */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, dspCodeCounterReg, 0);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fw_msg.addr = state->config->demod_address;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = dspCodeInReg;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (pos != len) {
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// work out how much to send this time
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_size = len - pos;
3377f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (tx_size > 0x10)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tx_size = 0x10;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// send the chunk
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(buf + 1, mem + pos, tx_size);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fw_msg.len = tx_size + 1;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
344ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			printk(KERN_ERR "tda1004x: Error during firmware upload\n");
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pos += tx_size;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
351ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	// give the DSP a chance to settle 03/10/05 Hac
352ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	msleep(100);
3537f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
357ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmannstatic int tda1004x_check_upload_ok(struct tda1004x_state *state)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 data1, data2;
360ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	unsigned long timeout;
361ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann
362ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
363ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		timeout = jiffies + 2 * HZ;
364ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
365ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			if (time_after(jiffies, timeout)) {
366ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann				printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
367ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann				break;
368ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			}
369ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			msleep(1);
370ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		}
371ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	} else
372ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		msleep(100);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// check upload was OK
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
3803faadbb0fde3c53e1c4f13eabb478c0c7cb1e4ddHartmut Hackmann	if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
381ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
383ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
384ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10045_fwupload(struct dvb_frontend* fe)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct firmware *fw;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* don't re-upload unless necessary */
395ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (tda1004x_check_upload_ok(state) == 0)
3967f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return 0;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* request the firmware, this will block until someone uploads it */
399ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
402ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset chip */
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msleep(10);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set parameters */
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
4160c744b010078bd65724477e75261e51712d290a0Anssi Hannula	release_firmware(fw);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
419ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	printk(KERN_INFO "tda1004x: firmware upload complete\n");
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait for DSP to initialise */
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DSPREADY doesn't seem to work on the TDA10045H */
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msleep(100);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
425ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	return tda1004x_check_upload_ok(state);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
428ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmannstatic void tda10046_init_plls(struct dvb_frontend* fe)
42971e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach{
430ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	struct tda1004x_state* state = fe->demodulator_priv;
4318a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	int tda10046_clk53m;
4328a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
4338a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if ((state->config->if_freq == TDA10046_FREQ_045) ||
4348a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	    (state->config->if_freq == TDA10046_FREQ_052))
4358a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 0;
4368a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	else
4378a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 1;
43871e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach
439ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
4408a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if(tda10046_clk53m) {
4418a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
4428a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
4438a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	} else {
4448a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
4458a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
4468a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	}
447ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
448ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
449ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
450ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	} else {
451ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
452ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
453ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
4548a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if(tda10046_clk53m)
4558a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
4568a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	else
4578a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
4588a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	/* Note clock frequency is handled implicitly */
459ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	switch (state->config->if_freq) {
460f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	case TDA10046_FREQ_045:
4618a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
4628a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
463f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		break;
464f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	case TDA10046_FREQ_052:
4658a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
4668a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
4678a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		break;
4688a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	case TDA10046_FREQ_3617:
4698a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4708a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
4718a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		break;
4728a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	case TDA10046_FREQ_3613:
4738a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4748a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
475f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		break;
476ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
477ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
4788a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	/* let the PLLs settle */
4798a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	msleep(120);
48071e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach}
48171e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10046_fwupload(struct dvb_frontend* fe)
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct firmware *fw;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset + wake up chip */
4890eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	if (state->config->xtal_freq == TDA10046_XTAL_4M) {
4900eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
4910eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	} else {
4920eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __FUNCTION__);
4930eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
4940eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	}
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
4961bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	/* set GPIO 1 and 3 */
4971bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	if (state->config->gpio_config != TDA10046_GPTRI) {
4981bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
4991bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
5001bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	}
501ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	/* let the clocks recover from sleep */
5021bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	msleep(10);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5048a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	/* The PLLs need to be reprogrammed after sleep */
5058a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda10046_init_plls(fe);
5068a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* don't re-upload unless necessary */
508ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (tda1004x_check_upload_ok(state) == 0)
5097f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return 0;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
5121bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
5131bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	msleep(300);
5141bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	/* don't re-upload unless necessary */
5151bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	if (tda1004x_check_upload_ok(state) == 0)
5161bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		return 0;
5171bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann
518f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann	if (state->config->request_firmware != NULL) {
519f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		/* request the firmware, this will block until someone uploads it */
520f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
521f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
522ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		if (ret) {
523f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			/* remain compatible to old bug: try to load with tda10045 image name */
524f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
525f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			if (ret) {
526f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann				printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
527f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann				return ret;
528f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			} else {
529f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann				printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
530f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann						  TDA10046_DEFAULT_FIRMWARE);
531f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			}
532f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		}
533f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann	} else {
534f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
535f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		return -EIO;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5371bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
5381bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
5391bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	release_firmware(fw);
540ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	return tda1004x_check_upload_ok(state);
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_encode_fec(int fec)
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// convert known FEC values
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fec) {
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_1_2:
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_2_3:
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_3_4:
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 2;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_5_6:
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 3;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_7_8:
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 4;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// unsupported
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_decode_fec(int tdafec)
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// convert known FEC values
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (tdafec) {
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_1_2;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_2_3;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_3_4;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_5_6;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_7_8;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// unsupported
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
583346304097b47a6e1376d99af80dbffb759fa55f4Adrian Bunkstatic int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
587c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	if (len != 2)
588c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey		return -EINVAL;
589c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey
590c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	return tda1004x_write_byteI(state, buf[0], buf[1]);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10045_init(struct dvb_frontend* fe)
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tda10045_fwupload(fe)) {
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("tda1004x: firmware upload failed\n");
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// tda setup
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10046_init(struct dvb_frontend* fe)
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tda10046_fwupload(fe)) {
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("tda1004x: firmware upload failed\n");
631ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			return -EIO;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// tda setup
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6368a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
6370eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
638ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann
639ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	switch (state->config->agc_config) {
640ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	case TDA10046_AGC_DEFAULT:
641ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
6421bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
643ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		break;
644ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	case TDA10046_AGC_IFO_AUTO_NEG:
645ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6461bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
647ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		break;
648f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	case TDA10046_AGC_IFO_AUTO_POS:
649f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6501bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00);  // set AGC polarities
6510eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		break;
6521bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	case TDA10046_AGC_TDA827X:
653550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
654550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
655550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
6561bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
657550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		break;
658ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
6598a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
6601bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x79); // Turn IF AGC output on
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
6658a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
666ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
668ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
6690eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	// tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
670ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
671ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_set_fe(struct dvb_frontend* fe,
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct dvb_frontend_parameters *fe_params)
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int inversion;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// setup auto offset
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// disable agc_conf[2]
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set frequency
695dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	if (fe->ops.tuner_ops.set_params) {
696dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher		fe->ops.tuner_ops.set_params(fe, fe_params);
697dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
698634623d3ba6146e13d06d3f36188c189c8a58a23Hartmut Hackmann	}
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Hardcoded to use auto as much as possible on the TDA10045 as it
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// is very unreliable if AUTO mode is _not_ used.
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Set standard params.. or put them to auto
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
7108a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		(fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
7118a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		(fe_params->u.ofdm.constellation == QAM_AUTO) ||
7128a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		(fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);	// enable auto
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0);	// turn off constellation bits
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0);	// turn off hierarchy bits
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0);	// turn off FEC bits
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0);	// disable auto
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set HP FEC
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
7227f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (tmp < 0)
7237f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return tmp;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set LP FEC
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
7287f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (tmp < 0)
7297f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return tmp;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set constellation
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fe_params->u.ofdm.constellation) {
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case QPSK:
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case QAM_16:
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case QAM_64:
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set hierarchy
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fe_params->u.ofdm.hierarchy_information) {
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_NONE:
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_1:
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_2:
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_4:
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set bandwidth
7747f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set inversion
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inversion = fe_params->inversion;
7867f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (state->config->invert)
7877f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		inversion = inversion ? INVERSION_OFF : INVERSION_ON;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (inversion) {
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case INVERSION_OFF:
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case INVERSION_ON:
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set guard interval
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fe_params->u.ofdm.guard_interval) {
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_32:
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_16:
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_8:
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_4:
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_AUTO:
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set transmission mode
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fe_params->u.ofdm.transmission_mode) {
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TRANSMISSION_MODE_2K:
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TRANSMISSION_MODE_8K:
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TRANSMISSION_MODE_AUTO:
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// start the lock
8547f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
862634623d3ba6146e13d06d3f36188c189c8a58a23Hartmut Hackmann		msleep(1);
863634623d3ba6146e13d06d3f36188c189c8a58a23Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8677f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	msleep(10);
8687f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
8758a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// inversion status
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->inversion = INVERSION_OFF;
8807f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->inversion = INVERSION_ON;
8827f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (state->config->invert)
8837f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// bandwidth
8867f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x14:
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xdb:
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x4f:
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
9028a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x5c:
9038a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x54:
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9068a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x6a:
9078a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x60:
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9108a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x7b:
9118a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x70:
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// FEC
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->u.ofdm.code_rate_HP =
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->u.ofdm.code_rate_LP =
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// constellation
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.constellation = QPSK;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.constellation = QAM_16;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.constellation = QAM_64;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// transmission mode
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
9397f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// guard interval
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// hierarchy
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_1;
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_2;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_4;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status)
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cber;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int vber;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read status
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
9887f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status == -1)
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// decode
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fe_status = 0;
9937f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status & 4)
9947f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		*fe_status |= FE_HAS_SIGNAL;
9957f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status & 2)
9967f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		*fe_status |= FE_HAS_CARRIER;
9977f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status & 8)
9987f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// is getting anything valid
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(*fe_status & FE_HAS_VITERBI)) {
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// read the CBER
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
10057f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (cber == -1)
10067f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
10087f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (status == -1)
10097f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cber |= (status << 8);
10110eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		// The address 0x20 should be read to cope with a TDA10046 bug
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_read_byte(state, TDA1004X_CBER_RESET);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10147f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (cber != 65535)
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*fe_status |= FE_HAS_VITERBI;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// if we DO have some valid VITERBI output, but don't already have SYNC
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// read the VBER
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
10237f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (vber == -1)
10247f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
10267f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (status == -1)
10277f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vber |= (status << 8);
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
10307f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (status == -1)
10317f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10320eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		vber |= (status & 0x0f) << 16;
10330eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		// The CVBER_LUT should be read to cope with TDA10046 hardware bug
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// if RS has passed some valid TS packets, then we must be
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// getting some SYNC bytes
10387f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (vber < 16632)
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*fe_status |= FE_HAS_SYNC;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// success
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg = 0;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// determine the register to use
10567f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = TDA10045H_S_AGC;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = TDA10046H_AGC_IF_LEVEL;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read it
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, reg);
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp < 0)
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*signal = (tmp << 8) | tmp;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal);
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read it
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_SNR);
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp < 0)
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
1087c2026b3af0c8ad33ef253a950c271f2d0da111b6Andrew de Quincey	tmp = 255 - tmp;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*snr = ((tmp << 8) | tmp);
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp2;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int counter;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read the UCBLOCKS and reset
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	counter = 0;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_UNCOR);
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp < 0)
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp &= 0x7f;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (counter++ < 5) {
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tmp2 < 0)
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp2 &= 0x7f;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tmp2 < tmp) || (tmp2 == 0))
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11227f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tmp != 0x7f)
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*ucblocks = tmp;
11247f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	else
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*ucblocks = 0xffffffff;
11267f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks);
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s\n", __FUNCTION__);
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read it in
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
11407f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tmp < 0)
11417f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return -EIO;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ber = tmp << 1;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
11447f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tmp < 0)
11457f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return -EIO;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ber |= (tmp << 9);
11470eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	// The address 0x20 should be read to cope with a TDA10046 bug
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_read_byte(state, TDA1004X_CBER_RESET);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_sleep(struct dvb_frontend* fe)
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
11571bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	int gpio_conf;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11597f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
11650eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		/* set outputs to tristate */
11660eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
11671bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		/* invert GPIO 1 and 3 if desired*/
11681bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		gpio_conf = state->config->gpio_config;
11691bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		if (gpio_conf >= TDA10046_GP00_I)
11701bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann			tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
11711bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann							(gpio_conf & 0x0f) ^ 0x0a);
11721bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann
1173f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
118074349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quinceystatic int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
118174349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey{
118274349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	struct tda1004x_state* state = fe->demodulator_priv;
118374349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey
118474349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	if (enable) {
118574349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey		return tda1004x_enable_tuner_i2c(state);
118674349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	} else {
118774349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey		return tda1004x_disable_tuner_i2c(state);
118874349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	}
118974349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey}
119074349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fesettings->min_delay_ms = 800;
1194f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	/* Drift compensation makes no sense for DVB-T */
1195f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	fesettings->step_size = 0;
1196f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	fesettings->max_drift = 0;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12002a514dea5fda67958c79f5137d4dcb272f8561e8Andrew de Quinceystatic void tda1004x_release(struct dvb_frontend* fe)
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12027f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct tda1004x_state *state = fe->demodulator_priv;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(state);
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dvb_frontend_ops tda10045_ops = {
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = {
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name = "Philips TDA10045H DVB-T",
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.type = FE_OFDM,
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_min = 51000000,
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_max = 858000000,
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_stepsize = 166667,
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.caps =
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12202a514dea5fda67958c79f5137d4dcb272f8561e8Andrew de Quincey	.release = tda1004x_release,
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init = tda10045_init,
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sleep = tda1004x_sleep,
1224c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	.write = tda1004x_write,
122574349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_frontend = tda1004x_set_fe,
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frontend = tda1004x_get_fe,
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_tune_settings = tda1004x_get_tune_settings,
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_status = tda1004x_read_status,
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ber = tda1004x_read_ber,
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_signal_strength = tda1004x_read_signal_strength,
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_snr = tda1004x_read_snr,
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ucblocks = tda1004x_read_ucblocks,
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12387f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbachstruct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
12397f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach				     struct i2c_adapter* i2c)
12407f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach{
12417f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct tda1004x_state *state;
12427f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12437f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* allocate memory for the internal state */
12447f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
12457f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (!state)
12467f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
12477f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12487f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* setup the state */
12497f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->config = config;
12507f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->i2c = i2c;
12517f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->demod_type = TDA1004X_DEMOD_TDA10045;
12527f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12537f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* check if the demod is there */
12547f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) {
12557f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		kfree(state);
12567f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
12577f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	}
12587f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12597f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* create dvb_frontend */
1260dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
12617f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->frontend.demodulator_priv = state;
12627f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	return &state->frontend;
12637f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach}
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12657f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbachstatic struct dvb_frontend_ops tda10046_ops = {
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = {
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name = "Philips TDA10046H DVB-T",
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.type = FE_OFDM,
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_min = 51000000,
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_max = 858000000,
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_stepsize = 166667,
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.caps =
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12792a514dea5fda67958c79f5137d4dcb272f8561e8Andrew de Quincey	.release = tda1004x_release,
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init = tda10046_init,
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sleep = tda1004x_sleep,
1283c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	.write = tda1004x_write,
1284159f8a6eda8c2ee359bb87bf62be70da2da14918Andrew de Quincey	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_frontend = tda1004x_set_fe,
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frontend = tda1004x_get_fe,
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_tune_settings = tda1004x_get_tune_settings,
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_status = tda1004x_read_status,
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ber = tda1004x_read_ber,
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_signal_strength = tda1004x_read_signal_strength,
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_snr = tda1004x_read_snr,
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ucblocks = tda1004x_read_ucblocks,
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12977f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbachstruct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
12987f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach				     struct i2c_adapter* i2c)
12997f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach{
13007f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct tda1004x_state *state;
13017f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13027f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* allocate memory for the internal state */
13037f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
13047f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (!state)
13057f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
13067f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13077f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* setup the state */
13087f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->config = config;
13097f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->i2c = i2c;
13107f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->demod_type = TDA1004X_DEMOD_TDA10046;
13117f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13127f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* check if the demod is there */
13137f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
13147f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		kfree(state);
13157f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
13167f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	}
13177f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13187f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* create dvb_frontend */
1319dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
13207f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->frontend.demodulator_priv = state;
13217f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	return &state->frontend;
13227f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach}
13237f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, int, 0644);
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(tda10045_attach);
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(tda10046_attach);
1333