tda1004x.c revision 517efa89acef3ac440e6e1ca10252d407ba51abf
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/device.h>
354e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/jiffies.h>
364e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/string.h>
374e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/slab.h>
384e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvb_frontend.h"
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tda1004x.h"
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(args...) \
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do { \
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (debug) printk(KERN_DEBUG "tda1004x: " args); \
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (0)
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CHIPID		 0x00
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_AUTO		 0x01
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_IN_CONF1	 0x02
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_IN_CONF2	 0x03
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_OUT_CONF1	 0x04
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_OUT_CONF2	 0x05
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_STATUS_CD	 0x06
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFC4		 0x07
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSSPARE2	 0x0C
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CODE_IN	 0x0D
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_FWPAGE	 0x0E
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_SCAN_CPT	 0x10
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_CMD	 0x11
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_ARG	 0x12
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_DATA1	 0x13
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_DSP_DATA2	 0x14
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFADC1	 0x15
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFC1		 0x16
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_S_AGC		 0x1a
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_TUN_LEVEL	 0x1a
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_SNR		 0x1c
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONF_TS1	 0x1e
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONF_TS2	 0x1f
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CBER_RESET	 0x20
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CBER_MSB	 0x21
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CBER_LSB	 0x22
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CVBER_LUT	 0x23
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_VBER_MSB	 0x24
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_VBER_MID	 0x25
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_VBER_LSB	 0x26
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_UNCOR		 0x27
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_P	 0x2D
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_M_MSB	 0x2E
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_M_LSB	 0x2F
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_CONFPLL_N	 0x30
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONFPLL1	 0x2D
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONFPLL2	 0x2F
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONFPLL3	 0x30
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF1	 0x31
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF2	 0x32
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF3	 0x33
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF4	 0x34
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_TIME_WREF5	 0x35
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_UNSURW_MSB	 0x31
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_UNSURW_LSB	 0x32
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_WREF_MSB	 0x33
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_WREF_MID	 0x34
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_WREF_LSB	 0x35
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_MUXOUT	 0x36
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA1004X_CONFADC2	 0x37
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10045H_IOFFSET	 0x38
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONF_TRISTATE1 0x3B
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONF_TRISTATE2 0x3C
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CONF_POLARITY	 0x3D
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_FREQ_OFFSET	 0x3E
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_GPIO_OUT_SEL	 0x41
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_GPIO_SELECT	 0x42
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_CONF	 0x43
111f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann#define TDA10046H_AGC_THR	 0x44
112f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann#define TDA10046H_AGC_RENORM	 0x45
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_GAINS	 0x46
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_TUN_MIN	 0x47
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_TUN_MAX	 0x48
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_IF_MIN	 0x49
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_IF_MAX	 0x4A
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_FREQ_PHY2_MSB	 0x4D
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_FREQ_PHY2_LSB	 0x4E
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CVBER_CTRL	 0x4F
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_AGC_IF_LEVEL	 0x52
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CODE_CPT	 0x57
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TDA10046H_CODE_IN	 0x58
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[] = { reg, data };
1327f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg.addr = state->config->demod_address;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = i2c_transfer(state->i2c, &msg, 1);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 1)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
141271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison			__func__, reg, data, ret);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg, data, ret);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (ret != 1) ? -1 : 0;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_byte(struct tda1004x_state *state, int reg)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b0[] = { reg };
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b1[] = { 0 };
1537f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
1547f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: reg=0x%x\n", __func__, reg);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[0].addr = state->config->demod_address;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg[1].addr = state->config->demod_address;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = i2c_transfer(state->i2c, msg, 2);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 2) {
163271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret);
165517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab		return -EINVAL;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
168271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg, b1[0], ret);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return b1[0];
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val;
176271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg,
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask, data);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read a byte and check
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = tda1004x_read_byte(state, reg);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < 0)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return val;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// mask if off
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = val & ~mask;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= data & 0xff;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// write it out again
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tda1004x_write_byteI(state, reg, val);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = 0;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < len; i++) {
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = tda1004x_write_byteI(state, reg + i, buf[i]);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result != 0)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
212271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
2150eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	msleep(20);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
221271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10045h_set_bandwidth(struct tda1004x_state *state,
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   fe_bandwidth_t bandwidth)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (bandwidth) {
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_6_MHZ:
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_7_MHZ:
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_8_MHZ:
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10046h_set_bandwidth(struct tda1004x_state *state,
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   fe_bandwidth_t bandwidth)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2588a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
2598a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
2608a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
2618a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
2628a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
2638a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
2648a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
2658a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	int tda10046_clk53m;
2668a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
2678a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if ((state->config->if_freq == TDA10046_FREQ_045) ||
2688a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	    (state->config->if_freq == TDA10046_FREQ_052))
2698a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 0;
2708a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	else
2718a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 1;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (bandwidth) {
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_6_MHZ:
2748a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		if (tda10046_clk53m)
2758a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
27650c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_6mhz_53M));
2778a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		else
2788a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
27950c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_6mhz_48M));
280f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		if (state->config->if_freq == TDA10046_FREQ_045) {
2818a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
2828a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
283f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_7_MHZ:
2878a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		if (tda10046_clk53m)
2888a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
28950c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_7mhz_53M));
2908a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		else
2918a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
29250c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_7mhz_48M));
293f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		if (state->config->if_freq == TDA10046_FREQ_045) {
2948a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
2958a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
296f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BANDWIDTH_8_MHZ:
3008a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		if (tda10046_clk53m)
3018a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
30250c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_8mhz_53M));
3038a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		else
3048a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
30550c25fff5385c6baf3114f7c369b0f75a29ac1e8Michael Krufky						  sizeof(bandwidth_8mhz_48M));
306f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		if (state->config->if_freq == TDA10046_FREQ_045) {
3078a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
3088a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
309f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_do_upload(struct tda1004x_state *state,
320bc179153ae2334efe28cf4f3300e024da7d83753David Woodhouse			      const unsigned char *mem, unsigned int len,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      u8 dspCodeCounterReg, u8 dspCodeInReg)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[65];
3247f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tx_size;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pos = 0;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear code counter */
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, dspCodeCounterReg, 0);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fw_msg.addr = state->config->demod_address;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = dspCodeInReg;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (pos != len) {
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// work out how much to send this time
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_size = len - pos;
3367f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (tx_size > 0x10)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tx_size = 0x10;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// send the chunk
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(buf + 1, mem + pos, tx_size);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fw_msg.len = tx_size + 1;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
343ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			printk(KERN_ERR "tda1004x: Error during firmware upload\n");
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pos += tx_size;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
348271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison		dprintk("%s: fw_pos=0x%x\n", __func__, pos);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
350ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	// give the DSP a chance to settle 03/10/05 Hac
351ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	msleep(100);
3527f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
356ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmannstatic int tda1004x_check_upload_ok(struct tda1004x_state *state)
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 data1, data2;
359ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	unsigned long timeout;
360ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann
361ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
362ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		timeout = jiffies + 2 * HZ;
363ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
364ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			if (time_after(jiffies, timeout)) {
365ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann				printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
366ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann				break;
367ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			}
368ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			msleep(1);
369ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		}
370ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	} else
371ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		msleep(100);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// check upload was OK
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
3793faadbb0fde3c53e1c4f13eabb478c0c7cb1e4ddHartmut Hackmann	if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
380ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
382ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
383ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10045_fwupload(struct dvb_frontend* fe)
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct firmware *fw;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* don't re-upload unless necessary */
394ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (tda1004x_check_upload_ok(state) == 0)
3957f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return 0;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* request the firmware, this will block until someone uploads it */
398ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
401ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset chip */
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msleep(10);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set parameters */
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
4150c744b010078bd65724477e75261e51712d290a0Anssi Hannula	release_firmware(fw);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
418ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	printk(KERN_INFO "tda1004x: firmware upload complete\n");
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait for DSP to initialise */
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DSPREADY doesn't seem to work on the TDA10045H */
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msleep(100);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
424ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	return tda1004x_check_upload_ok(state);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
427ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmannstatic void tda10046_init_plls(struct dvb_frontend* fe)
42871e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach{
429ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	struct tda1004x_state* state = fe->demodulator_priv;
4308a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	int tda10046_clk53m;
4318a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
4328a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if ((state->config->if_freq == TDA10046_FREQ_045) ||
4338a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	    (state->config->if_freq == TDA10046_FREQ_052))
4348a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 0;
4358a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	else
4368a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda10046_clk53m = 1;
43771e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach
438ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
4398a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if(tda10046_clk53m) {
4408a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
4418a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
4428a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	} else {
4438a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
4448a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
4458a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	}
446ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
447271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__);
448ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
449ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	} else {
450271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__);
451ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
452ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
4538a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	if(tda10046_clk53m)
4548a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
4558a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	else
4568a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
4578a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	/* Note clock frequency is handled implicitly */
458ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	switch (state->config->if_freq) {
459f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	case TDA10046_FREQ_045:
4608a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
4618a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
462f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		break;
463f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	case TDA10046_FREQ_052:
4648a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
4658a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
4668a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		break;
4678a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	case TDA10046_FREQ_3617:
4688a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4698a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
4708a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		break;
4718a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	case TDA10046_FREQ_3613:
4728a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4738a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
474f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		break;
475ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
476ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
4778a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	/* let the PLLs settle */
4788a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	msleep(120);
47971e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach}
48071e3420111530273f2b26fabfac4d021c2a2b79fJohannes Stezenbach
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10046_fwupload(struct dvb_frontend* fe)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
484517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	int ret, confc4;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct firmware *fw;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset + wake up chip */
4880eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	if (state->config->xtal_freq == TDA10046_XTAL_4M) {
489517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab		confc4 = 0;
4900eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	} else {
491271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison		dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
492517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab		confc4 = 0x80;
4930eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	}
494517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
495517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
4971bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	/* set GPIO 1 and 3 */
4981bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	if (state->config->gpio_config != TDA10046_GPTRI) {
4991bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
5001bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
5011bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	}
502ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	/* let the clocks recover from sleep */
5031bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	msleep(10);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5058a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	/* The PLLs need to be reprogrammed after sleep */
5068a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda10046_init_plls(fe);
50768717583557341874b2eea4dea36635256e932b6Hartmut Hackmann	tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0);
5088a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* don't re-upload unless necessary */
510ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	if (tda1004x_check_upload_ok(state) == 0)
5117f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return 0;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
513517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	/*
514517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   For i2c normal work, we need to slow down the bus speed.
515517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   However, the slow down breaks the eeprom firmware load.
516517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   So, use normal speed for eeprom booting and then restore the
517517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   i2c speed after that. Tested with MSI TV @nyware A/D board,
518517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   that comes with firmware version 29 inside their eeprom.
519517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab
520517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   It should also be noticed that no other I2C transfer should
521517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   be in course while booting from eeprom, otherwise, tda10046
522517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   goes into an instable state. So, proper locking are needed
523517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	   at the i2c bus master.
524517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	 */
5251bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
526517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
5271bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	msleep(300);
528517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
529517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab
530517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	/* Checks if eeprom firmware went without troubles */
5311bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	if (tda1004x_check_upload_ok(state) == 0)
5321bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		return 0;
5331bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann
534517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab	/* eeprom firmware didn't work. Load one manually. */
535517efa89acef3ac440e6e1ca10252d407ba51abfMauro Carvalho Chehab
536f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann	if (state->config->request_firmware != NULL) {
537f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		/* request the firmware, this will block until someone uploads it */
538f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
539f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
540ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		if (ret) {
541f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			/* remain compatible to old bug: try to load with tda10045 image name */
542f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
543f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			if (ret) {
544f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann				printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
545f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann				return ret;
546f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			} else {
547f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann				printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
548f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann						  TDA10046_DEFAULT_FIRMWARE);
549f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann			}
550f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		}
551f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann	} else {
552f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
553f4546e702a89d2e483570f0f16c5155bb781cc38Hartmut Hackmann		return -EIO;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5551bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
5561bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
5571bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	release_firmware(fw);
558ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	return tda1004x_check_upload_ok(state);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_encode_fec(int fec)
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// convert known FEC values
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fec) {
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_1_2:
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_2_3:
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_3_4:
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 2;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_5_6:
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 3;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FEC_7_8:
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 4;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// unsupported
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_decode_fec(int tdafec)
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// convert known FEC values
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (tdafec) {
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_1_2;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_2_3;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_3_4;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_5_6;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FEC_7_8;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// unsupported
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601346304097b47a6e1376d99af80dbffb759fa55f4Adrian Bunkstatic int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
605c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	if (len != 2)
606c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey		return -EINVAL;
607c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey
608c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	return tda1004x_write_byteI(state, buf[0], buf[1]);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10045_init(struct dvb_frontend* fe)
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
615271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tda10045_fwupload(fe)) {
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("tda1004x: firmware upload failed\n");
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// tda setup
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda10046_init(struct dvb_frontend* fe)
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
645271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tda10046_fwupload(fe)) {
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("tda1004x: firmware upload failed\n");
649ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann			return -EIO;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// tda setup
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6548a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
6550eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
656ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann
657ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	switch (state->config->agc_config) {
658ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	case TDA10046_AGC_DEFAULT:
659ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
6601bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
661ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		break;
662ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	case TDA10046_AGC_IFO_AUTO_NEG:
663ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6641bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
665ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann		break;
666f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	case TDA10046_AGC_IFO_AUTO_POS:
667f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6681bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00);  // set AGC polarities
6690eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		break;
6701bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	case TDA10046_AGC_TDA827X:
671550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
672550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
673550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
6741bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
675550a9a5e5f8086ae410832f134a5d80b9bd7fdb6Hartmut Hackmann		break;
676ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	}
67708cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann	if (state->config->ts_mode == 0) {
67808cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40);
67908cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann		tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
68008cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann	} else {
68108cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80);
68208cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10,
68308cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann							state->config->invert_oclk << 4);
68408cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann	}
6858a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
68608cdf94c076121cd0214ef9ea18ae3fbb9ace684Hartmut Hackmann	tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
6918a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
692ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
694ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
6950eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	// tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
696ecb60deb9d5bbcbab6c87ee5fde6f8368197fcacHartmut Hackmann
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_set_fe(struct dvb_frontend* fe,
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct dvb_frontend_parameters *fe_params)
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int inversion;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
707271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// setup auto offset
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// disable agc_conf[2]
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set frequency
720dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	if (fe->ops.tuner_ops.set_params) {
721dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher		fe->ops.tuner_ops.set_params(fe, fe_params);
722ede2200d79777d461cf2f0fd19cf7a17f633d3a4Hartmut Hackmann		if (fe->ops.i2c_gate_ctrl)
723ede2200d79777d461cf2f0fd19cf7a17f633d3a4Hartmut Hackmann			fe->ops.i2c_gate_ctrl(fe, 0);
724634623d3ba6146e13d06d3f36188c189c8a58a23Hartmut Hackmann	}
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Hardcoded to use auto as much as possible on the TDA10045 as it
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// is very unreliable if AUTO mode is _not_ used.
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Set standard params.. or put them to auto
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
7368a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		(fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
7378a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		(fe_params->u.ofdm.constellation == QAM_AUTO) ||
7388a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		(fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);	// enable auto
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0);	// turn off constellation bits
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0);	// turn off hierarchy bits
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0);	// turn off FEC bits
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0);	// disable auto
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set HP FEC
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
7487f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (tmp < 0)
7497f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return tmp;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set LP FEC
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
7547f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (tmp < 0)
7557f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return tmp;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set constellation
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fe_params->u.ofdm.constellation) {
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case QPSK:
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case QAM_16:
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case QAM_64:
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set hierarchy
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (fe_params->u.ofdm.hierarchy_information) {
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_NONE:
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_1:
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_2:
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case HIERARCHY_4:
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set bandwidth
8007f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set inversion
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inversion = fe_params->inversion;
8127f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (state->config->invert)
8137f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		inversion = inversion ? INVERSION_OFF : INVERSION_ON;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (inversion) {
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case INVERSION_OFF:
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case INVERSION_ON:
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set guard interval
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fe_params->u.ofdm.guard_interval) {
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_32:
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_16:
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_8:
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_1_4:
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GUARD_INTERVAL_AUTO:
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// set transmission mode
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fe_params->u.ofdm.transmission_mode) {
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TRANSMISSION_MODE_2K:
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TRANSMISSION_MODE_8K:
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TRANSMISSION_MODE_AUTO:
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// start the lock
8807f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
888634623d3ba6146e13d06d3f36188c189c8a58a23Hartmut Hackmann		msleep(1);
889634623d3ba6146e13d06d3f36188c189c8a58a23Hartmut Hackmann		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8937f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	msleep(10);
8947f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
9018a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann
902271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// inversion status
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->inversion = INVERSION_OFF;
9067f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->inversion = INVERSION_ON;
9087f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (state->config->invert)
9097f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// bandwidth
9127f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x14:
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xdb:
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x4f:
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
9288a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x5c:
9298a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x54:
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9328a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x6a:
9338a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x60:
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9368a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x7b:
9378a8e9c281de5dd63cdcbbafc0252fe0d8c758294Hartmut Hackmann		case 0x70:
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// FEC
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->u.ofdm.code_rate_HP =
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->u.ofdm.code_rate_LP =
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// constellation
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.constellation = QPSK;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.constellation = QAM_16;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.constellation = QAM_64;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// transmission mode
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
9657f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// guard interval
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// hierarchy
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_1;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_2;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 3:
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fe_params->u.ofdm.hierarchy_information = HIERARCHY_4;
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status)
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cber;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int vber;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1010271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read status
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
10147f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status == -1)
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// decode
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fe_status = 0;
10197f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status & 4)
10207f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		*fe_status |= FE_HAS_SIGNAL;
10217f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status & 2)
10227f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		*fe_status |= FE_HAS_CARRIER;
10237f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (status & 8)
10247f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// is getting anything valid
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(*fe_status & FE_HAS_VITERBI)) {
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// read the CBER
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
10317f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (cber == -1)
10327f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
10347f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (status == -1)
10357f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cber |= (status << 8);
10370eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		// The address 0x20 should be read to cope with a TDA10046 bug
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_read_byte(state, TDA1004X_CBER_RESET);
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10407f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (cber != 65535)
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*fe_status |= FE_HAS_VITERBI;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// if we DO have some valid VITERBI output, but don't already have SYNC
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// read the VBER
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
10497f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (vber == -1)
10507f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
10527f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (status == -1)
10537f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vber |= (status << 8);
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
10567f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (status == -1)
10577f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach			return -EIO;
10580eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		vber |= (status & 0x0f) << 16;
10590eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		// The CVBER_LUT should be read to cope with TDA10046 hardware bug
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// if RS has passed some valid TS packets, then we must be
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// getting some SYNC bytes
10647f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		if (vber < 16632)
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*fe_status |= FE_HAS_SYNC;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// success
1069271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int reg = 0;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1079271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// determine the register to use
10827f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = TDA10045H_S_AGC;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = TDA10046H_AGC_IF_LEVEL;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read it
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, reg);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp < 0)
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*signal = (tmp << 8) | tmp;
1098271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: signal=0x%x\n", __func__, *signal);
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1107271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read it
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_SNR);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp < 0)
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
1113c2026b3af0c8ad33ef253a950c271f2d0da111b6Andrew de Quincey	tmp = 255 - tmp;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*snr = ((tmp << 8) | tmp);
1116271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: snr=0x%x\n", __func__, *snr);
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp2;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int counter;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1127271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read the UCBLOCKS and reset
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	counter = 0;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_UNCOR);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp < 0)
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp &= 0x7f;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (counter++ < 5) {
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tmp2 < 0)
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp2 &= 0x7f;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tmp2 < tmp) || (tmp2 == 0))
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11487f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tmp != 0x7f)
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*ucblocks = tmp;
11507f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	else
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*ucblocks = 0xffffffff;
11527f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
1153271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1162271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s\n", __func__);
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read it in
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
11667f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tmp < 0)
11677f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return -EIO;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ber = tmp << 1;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
11707f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	if (tmp < 0)
11717f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return -EIO;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ber |= (tmp << 9);
11730eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann	// The address 0x20 should be read to cope with a TDA10046 bug
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tda1004x_read_byte(state, TDA1004X_CBER_RESET);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1176271ddbf702c3a4e6b18f6464180eda0f62efd9a5Harvey Harrison	dprintk("%s: ber=0x%x\n", __func__, *ber);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_sleep(struct dvb_frontend* fe)
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tda1004x_state* state = fe->demodulator_priv;
11831bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann	int gpio_conf;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11857f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	switch (state->demod_type) {
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10045:
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TDA1004X_DEMOD_TDA10046:
11910eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		/* set outputs to tristate */
11920eb3de20a1cec67547951cebc4fcddc701e7428bHartmut Hackmann		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
11931bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		/* invert GPIO 1 and 3 if desired*/
11941bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		gpio_conf = state->config->gpio_config;
11951bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann		if (gpio_conf >= TDA10046_GP00_I)
11961bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann			tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
11971bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann							(gpio_conf & 0x0f) ^ 0x0a);
11981bb0e8667fab773d6c5a3d7caf506001deaeb7f5Hartmut Hackmann
119968717583557341874b2eea4dea36635256e932b6Hartmut Hackmann		tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0);
1200f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120774349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quinceystatic int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
120874349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey{
120974349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	struct tda1004x_state* state = fe->demodulator_priv;
121074349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey
121174349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	if (enable) {
121274349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey		return tda1004x_enable_tuner_i2c(state);
121374349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	} else {
121474349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey		return tda1004x_disable_tuner_i2c(state);
121574349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	}
121674349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey}
121774349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fesettings->min_delay_ms = 800;
1221f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	/* Drift compensation makes no sense for DVB-T */
1222f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	fesettings->step_size = 0;
1223f03cbea36ab9412dcea58e953be4933b36c9b7beHartmut Hackmann	fesettings->max_drift = 0;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12272a514dea5fda67958c79f5137d4dcb272f8561e8Andrew de Quinceystatic void tda1004x_release(struct dvb_frontend* fe)
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12297f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct tda1004x_state *state = fe->demodulator_priv;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(state);
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dvb_frontend_ops tda10045_ops = {
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = {
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name = "Philips TDA10045H DVB-T",
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.type = FE_OFDM,
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_min = 51000000,
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_max = 858000000,
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_stepsize = 166667,
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.caps =
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12472a514dea5fda67958c79f5137d4dcb272f8561e8Andrew de Quincey	.release = tda1004x_release,
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init = tda10045_init,
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sleep = tda1004x_sleep,
1251c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	.write = tda1004x_write,
125274349bef1a5b5a287721a42bec08c226b095e8b0Andrew de Quincey	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_frontend = tda1004x_set_fe,
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frontend = tda1004x_get_fe,
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_tune_settings = tda1004x_get_tune_settings,
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_status = tda1004x_read_status,
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ber = tda1004x_read_ber,
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_signal_strength = tda1004x_read_signal_strength,
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_snr = tda1004x_read_snr,
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ucblocks = tda1004x_read_ucblocks,
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12657f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbachstruct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
12667f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach				     struct i2c_adapter* i2c)
12677f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach{
12687f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct tda1004x_state *state;
12690e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab	int id;
12707f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12717f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* allocate memory for the internal state */
12727f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
1273bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	if (!state) {
1274bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab		printk(KERN_ERR "Can't alocate memory for tda10045 state\n");
12757f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
1276bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	}
12777f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12787f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* setup the state */
12797f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->config = config;
12807f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->i2c = i2c;
12817f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->demod_type = TDA1004X_DEMOD_TDA10045;
12827f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12837f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* check if the demod is there */
1284bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
12850e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab	if (id < 0) {
12860e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab		printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
12870e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab		kfree(state);
12880e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab		return NULL;
12890e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab	}
12900e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab
1291bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	if (id != 0x25) {
1292bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
12937f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		kfree(state);
12947f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
12957f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	}
12967f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
12977f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* create dvb_frontend */
1298dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
12997f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->frontend.demodulator_priv = state;
13007f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	return &state->frontend;
13017f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach}
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13037f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbachstatic struct dvb_frontend_ops tda10046_ops = {
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = {
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name = "Philips TDA10046H DVB-T",
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.type = FE_OFDM,
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_min = 51000000,
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_max = 858000000,
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.frequency_stepsize = 166667,
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.caps =
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13172a514dea5fda67958c79f5137d4dcb272f8561e8Andrew de Quincey	.release = tda1004x_release,
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init = tda10046_init,
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sleep = tda1004x_sleep,
1321c10d14d62d7b7596fd5c7bb8aad3f2b56f8640e6Andrew de Quincey	.write = tda1004x_write,
1322159f8a6eda8c2ee359bb87bf62be70da2da14918Andrew de Quincey	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_frontend = tda1004x_set_fe,
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frontend = tda1004x_get_fe,
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_tune_settings = tda1004x_get_tune_settings,
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_status = tda1004x_read_status,
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ber = tda1004x_read_ber,
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_signal_strength = tda1004x_read_signal_strength,
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_snr = tda1004x_read_snr,
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_ucblocks = tda1004x_read_ucblocks,
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13357f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbachstruct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
13367f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach				     struct i2c_adapter* i2c)
13377f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach{
13387f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	struct tda1004x_state *state;
13390e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab	int id;
13407f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13417f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* allocate memory for the internal state */
13427f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
1343bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	if (!state) {
1344bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab		printk(KERN_ERR "Can't alocate memory for tda10046 state\n");
13457f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
1346bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	}
13477f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13487f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* setup the state */
13497f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->config = config;
13507f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->i2c = i2c;
13517f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->demod_type = TDA1004X_DEMOD_TDA10046;
13527f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13537f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* check if the demod is there */
1354bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
13550e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab	if (id < 0) {
13560e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab		printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
13570e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab		kfree(state);
13580e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab		return NULL;
13590e7830b50b20fcc25f21f79b7734102284d7c8f9Mauro Carvalho Chehab	}
1360bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab	if (id != 0x46) {
1361bc36ec746409e4e4719b94a86dc0d8cbeb6f439fMauro Carvalho Chehab		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
13627f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		kfree(state);
13637f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach		return NULL;
13647f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	}
13657f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13667f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	/* create dvb_frontend */
1367dea74869f3c62b0b7addd67017b22b394e942aacPatrick Boettcher	memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
13687f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	state->frontend.demodulator_priv = state;
13697f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach	return &state->frontend;
13707f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach}
13717f5e02db4a39c36e68878a14fae1fe7ee6dd6fcfJohannes Stezenbach
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, int, 0644);
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(tda10045_attach);
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(tda10046_attach);
1381