19a0bf528SMauro Carvalho Chehab   /*
29a0bf528SMauro Carvalho Chehab      Driver for Philips tda1004xh OFDM Demodulator
39a0bf528SMauro Carvalho Chehab 
49a0bf528SMauro Carvalho Chehab      (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach
59a0bf528SMauro Carvalho Chehab 
69a0bf528SMauro Carvalho Chehab      This program is free software; you can redistribute it and/or modify
79a0bf528SMauro Carvalho Chehab      it under the terms of the GNU General Public License as published by
89a0bf528SMauro Carvalho Chehab      the Free Software Foundation; either version 2 of the License, or
99a0bf528SMauro Carvalho Chehab      (at your option) any later version.
109a0bf528SMauro Carvalho Chehab 
119a0bf528SMauro Carvalho Chehab      This program is distributed in the hope that it will be useful,
129a0bf528SMauro Carvalho Chehab      but WITHOUT ANY WARRANTY; without even the implied warranty of
139a0bf528SMauro Carvalho Chehab      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149a0bf528SMauro Carvalho Chehab 
159a0bf528SMauro Carvalho Chehab      GNU General Public License for more details.
169a0bf528SMauro Carvalho Chehab 
179a0bf528SMauro Carvalho Chehab      You should have received a copy of the GNU General Public License
189a0bf528SMauro Carvalho Chehab      along with this program; if not, write to the Free Software
199a0bf528SMauro Carvalho Chehab      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab    */
229a0bf528SMauro Carvalho Chehab /*
239a0bf528SMauro Carvalho Chehab  * This driver needs external firmware. Please use the commands
249a0bf528SMauro Carvalho Chehab  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
259a0bf528SMauro Carvalho Chehab  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
269a0bf528SMauro Carvalho Chehab  * download/extract them, and then copy them to /usr/lib/hotplug/firmware
279a0bf528SMauro Carvalho Chehab  * or /lib/firmware (depending on configuration of firmware hotplug).
289a0bf528SMauro Carvalho Chehab  */
299a0bf528SMauro Carvalho Chehab #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
309a0bf528SMauro Carvalho Chehab #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
319a0bf528SMauro Carvalho Chehab 
329a0bf528SMauro Carvalho Chehab #include <linux/init.h>
339a0bf528SMauro Carvalho Chehab #include <linux/module.h>
349a0bf528SMauro Carvalho Chehab #include <linux/device.h>
359a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h>
369a0bf528SMauro Carvalho Chehab #include <linux/string.h>
379a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
389a0bf528SMauro Carvalho Chehab 
39fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
409a0bf528SMauro Carvalho Chehab #include "tda1004x.h"
419a0bf528SMauro Carvalho Chehab 
429a0bf528SMauro Carvalho Chehab static int debug;
439a0bf528SMauro Carvalho Chehab #define dprintk(args...) \
449a0bf528SMauro Carvalho Chehab 	do { \
459a0bf528SMauro Carvalho Chehab 		if (debug) printk(KERN_DEBUG "tda1004x: " args); \
469a0bf528SMauro Carvalho Chehab 	} while (0)
479a0bf528SMauro Carvalho Chehab 
489a0bf528SMauro Carvalho Chehab #define TDA1004X_CHIPID		 0x00
499a0bf528SMauro Carvalho Chehab #define TDA1004X_AUTO		 0x01
509a0bf528SMauro Carvalho Chehab #define TDA1004X_IN_CONF1	 0x02
519a0bf528SMauro Carvalho Chehab #define TDA1004X_IN_CONF2	 0x03
529a0bf528SMauro Carvalho Chehab #define TDA1004X_OUT_CONF1	 0x04
539a0bf528SMauro Carvalho Chehab #define TDA1004X_OUT_CONF2	 0x05
549a0bf528SMauro Carvalho Chehab #define TDA1004X_STATUS_CD	 0x06
559a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFC4		 0x07
569a0bf528SMauro Carvalho Chehab #define TDA1004X_DSSPARE2	 0x0C
579a0bf528SMauro Carvalho Chehab #define TDA10045H_CODE_IN	 0x0D
589a0bf528SMauro Carvalho Chehab #define TDA10045H_FWPAGE	 0x0E
599a0bf528SMauro Carvalho Chehab #define TDA1004X_SCAN_CPT	 0x10
609a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_CMD	 0x11
619a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_ARG	 0x12
629a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_DATA1	 0x13
639a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_DATA2	 0x14
649a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFADC1	 0x15
659a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFC1		 0x16
669a0bf528SMauro Carvalho Chehab #define TDA10045H_S_AGC		 0x1a
679a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_TUN_LEVEL	 0x1a
689a0bf528SMauro Carvalho Chehab #define TDA1004X_SNR		 0x1c
699a0bf528SMauro Carvalho Chehab #define TDA1004X_CONF_TS1	 0x1e
709a0bf528SMauro Carvalho Chehab #define TDA1004X_CONF_TS2	 0x1f
719a0bf528SMauro Carvalho Chehab #define TDA1004X_CBER_RESET	 0x20
729a0bf528SMauro Carvalho Chehab #define TDA1004X_CBER_MSB	 0x21
739a0bf528SMauro Carvalho Chehab #define TDA1004X_CBER_LSB	 0x22
749a0bf528SMauro Carvalho Chehab #define TDA1004X_CVBER_LUT	 0x23
759a0bf528SMauro Carvalho Chehab #define TDA1004X_VBER_MSB	 0x24
769a0bf528SMauro Carvalho Chehab #define TDA1004X_VBER_MID	 0x25
779a0bf528SMauro Carvalho Chehab #define TDA1004X_VBER_LSB	 0x26
789a0bf528SMauro Carvalho Chehab #define TDA1004X_UNCOR		 0x27
799a0bf528SMauro Carvalho Chehab 
809a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_P	 0x2D
819a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_M_MSB	 0x2E
829a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_M_LSB	 0x2F
839a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_N	 0x30
849a0bf528SMauro Carvalho Chehab 
859a0bf528SMauro Carvalho Chehab #define TDA10046H_CONFPLL1	 0x2D
869a0bf528SMauro Carvalho Chehab #define TDA10046H_CONFPLL2	 0x2F
879a0bf528SMauro Carvalho Chehab #define TDA10046H_CONFPLL3	 0x30
889a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF1	 0x31
899a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF2	 0x32
909a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF3	 0x33
919a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF4	 0x34
929a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF5	 0x35
939a0bf528SMauro Carvalho Chehab 
949a0bf528SMauro Carvalho Chehab #define TDA10045H_UNSURW_MSB	 0x31
959a0bf528SMauro Carvalho Chehab #define TDA10045H_UNSURW_LSB	 0x32
969a0bf528SMauro Carvalho Chehab #define TDA10045H_WREF_MSB	 0x33
979a0bf528SMauro Carvalho Chehab #define TDA10045H_WREF_MID	 0x34
989a0bf528SMauro Carvalho Chehab #define TDA10045H_WREF_LSB	 0x35
999a0bf528SMauro Carvalho Chehab #define TDA10045H_MUXOUT	 0x36
1009a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFADC2	 0x37
1019a0bf528SMauro Carvalho Chehab 
1029a0bf528SMauro Carvalho Chehab #define TDA10045H_IOFFSET	 0x38
1039a0bf528SMauro Carvalho Chehab 
1049a0bf528SMauro Carvalho Chehab #define TDA10046H_CONF_TRISTATE1 0x3B
1059a0bf528SMauro Carvalho Chehab #define TDA10046H_CONF_TRISTATE2 0x3C
1069a0bf528SMauro Carvalho Chehab #define TDA10046H_CONF_POLARITY	 0x3D
1079a0bf528SMauro Carvalho Chehab #define TDA10046H_FREQ_OFFSET	 0x3E
1089a0bf528SMauro Carvalho Chehab #define TDA10046H_GPIO_OUT_SEL	 0x41
1099a0bf528SMauro Carvalho Chehab #define TDA10046H_GPIO_SELECT	 0x42
1109a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_CONF	 0x43
1119a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_THR	 0x44
1129a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_RENORM	 0x45
1139a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_GAINS	 0x46
1149a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_TUN_MIN	 0x47
1159a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_TUN_MAX	 0x48
1169a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_IF_MIN	 0x49
1179a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_IF_MAX	 0x4A
1189a0bf528SMauro Carvalho Chehab 
1199a0bf528SMauro Carvalho Chehab #define TDA10046H_FREQ_PHY2_MSB	 0x4D
1209a0bf528SMauro Carvalho Chehab #define TDA10046H_FREQ_PHY2_LSB	 0x4E
1219a0bf528SMauro Carvalho Chehab 
1229a0bf528SMauro Carvalho Chehab #define TDA10046H_CVBER_CTRL	 0x4F
1239a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_IF_LEVEL	 0x52
1249a0bf528SMauro Carvalho Chehab #define TDA10046H_CODE_CPT	 0x57
1259a0bf528SMauro Carvalho Chehab #define TDA10046H_CODE_IN	 0x58
1269a0bf528SMauro Carvalho Chehab 
1279a0bf528SMauro Carvalho Chehab 
1289a0bf528SMauro Carvalho Chehab static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
1299a0bf528SMauro Carvalho Chehab {
1309a0bf528SMauro Carvalho Chehab 	int ret;
1319a0bf528SMauro Carvalho Chehab 	u8 buf[] = { reg, data };
1329a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
1339a0bf528SMauro Carvalho Chehab 
1349a0bf528SMauro Carvalho Chehab 	dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data);
1359a0bf528SMauro Carvalho Chehab 
1369a0bf528SMauro Carvalho Chehab 	msg.addr = state->config->demod_address;
1379a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, &msg, 1);
1389a0bf528SMauro Carvalho Chehab 
1399a0bf528SMauro Carvalho Chehab 	if (ret != 1)
1409a0bf528SMauro Carvalho Chehab 		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
1419a0bf528SMauro Carvalho Chehab 			__func__, reg, data, ret);
1429a0bf528SMauro Carvalho Chehab 
1439a0bf528SMauro Carvalho Chehab 	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
1449a0bf528SMauro Carvalho Chehab 		reg, data, ret);
1459a0bf528SMauro Carvalho Chehab 	return (ret != 1) ? -1 : 0;
1469a0bf528SMauro Carvalho Chehab }
1479a0bf528SMauro Carvalho Chehab 
1489a0bf528SMauro Carvalho Chehab static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
1499a0bf528SMauro Carvalho Chehab {
1509a0bf528SMauro Carvalho Chehab 	int ret;
1519a0bf528SMauro Carvalho Chehab 	u8 b0[] = { reg };
1529a0bf528SMauro Carvalho Chehab 	u8 b1[] = { 0 };
1539a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
1549a0bf528SMauro Carvalho Chehab 				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
1559a0bf528SMauro Carvalho Chehab 
1569a0bf528SMauro Carvalho Chehab 	dprintk("%s: reg=0x%x\n", __func__, reg);
1579a0bf528SMauro Carvalho Chehab 
1589a0bf528SMauro Carvalho Chehab 	msg[0].addr = state->config->demod_address;
1599a0bf528SMauro Carvalho Chehab 	msg[1].addr = state->config->demod_address;
1609a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, msg, 2);
1619a0bf528SMauro Carvalho Chehab 
1629a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
1639a0bf528SMauro Carvalho Chehab 		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
1649a0bf528SMauro Carvalho Chehab 			ret);
1659a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1669a0bf528SMauro Carvalho Chehab 	}
1679a0bf528SMauro Carvalho Chehab 
1689a0bf528SMauro Carvalho Chehab 	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
1699a0bf528SMauro Carvalho Chehab 		reg, b1[0], ret);
1709a0bf528SMauro Carvalho Chehab 	return b1[0];
1719a0bf528SMauro Carvalho Chehab }
1729a0bf528SMauro Carvalho Chehab 
1739a0bf528SMauro Carvalho Chehab static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
1749a0bf528SMauro Carvalho Chehab {
1759a0bf528SMauro Carvalho Chehab 	int val;
1769a0bf528SMauro Carvalho Chehab 	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg,
1779a0bf528SMauro Carvalho Chehab 		mask, data);
1789a0bf528SMauro Carvalho Chehab 
1799a0bf528SMauro Carvalho Chehab 	// read a byte and check
1809a0bf528SMauro Carvalho Chehab 	val = tda1004x_read_byte(state, reg);
1819a0bf528SMauro Carvalho Chehab 	if (val < 0)
1829a0bf528SMauro Carvalho Chehab 		return val;
1839a0bf528SMauro Carvalho Chehab 
1849a0bf528SMauro Carvalho Chehab 	// mask if off
1859a0bf528SMauro Carvalho Chehab 	val = val & ~mask;
1869a0bf528SMauro Carvalho Chehab 	val |= data & 0xff;
1879a0bf528SMauro Carvalho Chehab 
1889a0bf528SMauro Carvalho Chehab 	// write it out again
1899a0bf528SMauro Carvalho Chehab 	return tda1004x_write_byteI(state, reg, val);
1909a0bf528SMauro Carvalho Chehab }
1919a0bf528SMauro Carvalho Chehab 
1929a0bf528SMauro Carvalho Chehab static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len)
1939a0bf528SMauro Carvalho Chehab {
1949a0bf528SMauro Carvalho Chehab 	int i;
1959a0bf528SMauro Carvalho Chehab 	int result;
1969a0bf528SMauro Carvalho Chehab 
1979a0bf528SMauro Carvalho Chehab 	dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len);
1989a0bf528SMauro Carvalho Chehab 
1999a0bf528SMauro Carvalho Chehab 	result = 0;
2009a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len; i++) {
2019a0bf528SMauro Carvalho Chehab 		result = tda1004x_write_byteI(state, reg + i, buf[i]);
2029a0bf528SMauro Carvalho Chehab 		if (result != 0)
2039a0bf528SMauro Carvalho Chehab 			break;
2049a0bf528SMauro Carvalho Chehab 	}
2059a0bf528SMauro Carvalho Chehab 
2069a0bf528SMauro Carvalho Chehab 	return result;
2079a0bf528SMauro Carvalho Chehab }
2089a0bf528SMauro Carvalho Chehab 
2099a0bf528SMauro Carvalho Chehab static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
2109a0bf528SMauro Carvalho Chehab {
2119a0bf528SMauro Carvalho Chehab 	int result;
2129a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
2139a0bf528SMauro Carvalho Chehab 
2149a0bf528SMauro Carvalho Chehab 	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
2159a0bf528SMauro Carvalho Chehab 	msleep(20);
2169a0bf528SMauro Carvalho Chehab 	return result;
2179a0bf528SMauro Carvalho Chehab }
2189a0bf528SMauro Carvalho Chehab 
2199a0bf528SMauro Carvalho Chehab static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
2209a0bf528SMauro Carvalho Chehab {
2219a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
2229a0bf528SMauro Carvalho Chehab 
2239a0bf528SMauro Carvalho Chehab 	return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
2249a0bf528SMauro Carvalho Chehab }
2259a0bf528SMauro Carvalho Chehab 
2269a0bf528SMauro Carvalho Chehab static int tda10045h_set_bandwidth(struct tda1004x_state *state,
2279a0bf528SMauro Carvalho Chehab 				   u32 bandwidth)
2289a0bf528SMauro Carvalho Chehab {
2299a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
2309a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
2319a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
2329a0bf528SMauro Carvalho Chehab 
2339a0bf528SMauro Carvalho Chehab 	switch (bandwidth) {
2349a0bf528SMauro Carvalho Chehab 	case 6000000:
2359a0bf528SMauro Carvalho Chehab 		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
2369a0bf528SMauro Carvalho Chehab 		break;
2379a0bf528SMauro Carvalho Chehab 
2389a0bf528SMauro Carvalho Chehab 	case 7000000:
2399a0bf528SMauro Carvalho Chehab 		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
2409a0bf528SMauro Carvalho Chehab 		break;
2419a0bf528SMauro Carvalho Chehab 
2429a0bf528SMauro Carvalho Chehab 	case 8000000:
2439a0bf528SMauro Carvalho Chehab 		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
2449a0bf528SMauro Carvalho Chehab 		break;
2459a0bf528SMauro Carvalho Chehab 
2469a0bf528SMauro Carvalho Chehab 	default:
2479a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2489a0bf528SMauro Carvalho Chehab 	}
2499a0bf528SMauro Carvalho Chehab 
2509a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);
2519a0bf528SMauro Carvalho Chehab 
2529a0bf528SMauro Carvalho Chehab 	return 0;
2539a0bf528SMauro Carvalho Chehab }
2549a0bf528SMauro Carvalho Chehab 
2559a0bf528SMauro Carvalho Chehab static int tda10046h_set_bandwidth(struct tda1004x_state *state,
2569a0bf528SMauro Carvalho Chehab 				   u32 bandwidth)
2579a0bf528SMauro Carvalho Chehab {
2589a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
2599a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
2609a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
2619a0bf528SMauro Carvalho Chehab 
2629a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
2639a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
2649a0bf528SMauro Carvalho Chehab 	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
2659a0bf528SMauro Carvalho Chehab 	int tda10046_clk53m;
2669a0bf528SMauro Carvalho Chehab 
2679a0bf528SMauro Carvalho Chehab 	if ((state->config->if_freq == TDA10046_FREQ_045) ||
2689a0bf528SMauro Carvalho Chehab 	    (state->config->if_freq == TDA10046_FREQ_052))
2699a0bf528SMauro Carvalho Chehab 		tda10046_clk53m = 0;
2709a0bf528SMauro Carvalho Chehab 	else
2719a0bf528SMauro Carvalho Chehab 		tda10046_clk53m = 1;
2729a0bf528SMauro Carvalho Chehab 	switch (bandwidth) {
2739a0bf528SMauro Carvalho Chehab 	case 6000000:
2749a0bf528SMauro Carvalho Chehab 		if (tda10046_clk53m)
2759a0bf528SMauro Carvalho Chehab 			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
2769a0bf528SMauro Carvalho Chehab 						  sizeof(bandwidth_6mhz_53M));
2779a0bf528SMauro Carvalho Chehab 		else
2789a0bf528SMauro Carvalho Chehab 			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
2799a0bf528SMauro Carvalho Chehab 						  sizeof(bandwidth_6mhz_48M));
2809a0bf528SMauro Carvalho Chehab 		if (state->config->if_freq == TDA10046_FREQ_045) {
2819a0bf528SMauro Carvalho Chehab 			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
2829a0bf528SMauro Carvalho Chehab 			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
2839a0bf528SMauro Carvalho Chehab 		}
2849a0bf528SMauro Carvalho Chehab 		break;
2859a0bf528SMauro Carvalho Chehab 
2869a0bf528SMauro Carvalho Chehab 	case 7000000:
2879a0bf528SMauro Carvalho Chehab 		if (tda10046_clk53m)
2889a0bf528SMauro Carvalho Chehab 			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
2899a0bf528SMauro Carvalho Chehab 						  sizeof(bandwidth_7mhz_53M));
2909a0bf528SMauro Carvalho Chehab 		else
2919a0bf528SMauro Carvalho Chehab 			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
2929a0bf528SMauro Carvalho Chehab 						  sizeof(bandwidth_7mhz_48M));
2939a0bf528SMauro Carvalho Chehab 		if (state->config->if_freq == TDA10046_FREQ_045) {
2949a0bf528SMauro Carvalho Chehab 			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
2959a0bf528SMauro Carvalho Chehab 			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
2969a0bf528SMauro Carvalho Chehab 		}
2979a0bf528SMauro Carvalho Chehab 		break;
2989a0bf528SMauro Carvalho Chehab 
2999a0bf528SMauro Carvalho Chehab 	case 8000000:
3009a0bf528SMauro Carvalho Chehab 		if (tda10046_clk53m)
3019a0bf528SMauro Carvalho Chehab 			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
3029a0bf528SMauro Carvalho Chehab 						  sizeof(bandwidth_8mhz_53M));
3039a0bf528SMauro Carvalho Chehab 		else
3049a0bf528SMauro Carvalho Chehab 			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
3059a0bf528SMauro Carvalho Chehab 						  sizeof(bandwidth_8mhz_48M));
3069a0bf528SMauro Carvalho Chehab 		if (state->config->if_freq == TDA10046_FREQ_045) {
3079a0bf528SMauro Carvalho Chehab 			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
3089a0bf528SMauro Carvalho Chehab 			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
3099a0bf528SMauro Carvalho Chehab 		}
3109a0bf528SMauro Carvalho Chehab 		break;
3119a0bf528SMauro Carvalho Chehab 
3129a0bf528SMauro Carvalho Chehab 	default:
3139a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3149a0bf528SMauro Carvalho Chehab 	}
3159a0bf528SMauro Carvalho Chehab 
3169a0bf528SMauro Carvalho Chehab 	return 0;
3179a0bf528SMauro Carvalho Chehab }
3189a0bf528SMauro Carvalho Chehab 
3199a0bf528SMauro Carvalho Chehab static int tda1004x_do_upload(struct tda1004x_state *state,
3209a0bf528SMauro Carvalho Chehab 			      const unsigned char *mem, unsigned int len,
3219a0bf528SMauro Carvalho Chehab 			      u8 dspCodeCounterReg, u8 dspCodeInReg)
3229a0bf528SMauro Carvalho Chehab {
3239a0bf528SMauro Carvalho Chehab 	u8 buf[65];
3249a0bf528SMauro Carvalho Chehab 	struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
3259a0bf528SMauro Carvalho Chehab 	int tx_size;
3269a0bf528SMauro Carvalho Chehab 	int pos = 0;
3279a0bf528SMauro Carvalho Chehab 
3289a0bf528SMauro Carvalho Chehab 	/* clear code counter */
3299a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, dspCodeCounterReg, 0);
3309a0bf528SMauro Carvalho Chehab 	fw_msg.addr = state->config->demod_address;
3319a0bf528SMauro Carvalho Chehab 
332347c4e95SMauro Carvalho Chehab 	i2c_lock_adapter(state->i2c);
3339a0bf528SMauro Carvalho Chehab 	buf[0] = dspCodeInReg;
3349a0bf528SMauro Carvalho Chehab 	while (pos != len) {
3359a0bf528SMauro Carvalho Chehab 		// work out how much to send this time
3369a0bf528SMauro Carvalho Chehab 		tx_size = len - pos;
3379a0bf528SMauro Carvalho Chehab 		if (tx_size > 0x10)
3389a0bf528SMauro Carvalho Chehab 			tx_size = 0x10;
3399a0bf528SMauro Carvalho Chehab 
3409a0bf528SMauro Carvalho Chehab 		// send the chunk
3419a0bf528SMauro Carvalho Chehab 		memcpy(buf + 1, mem + pos, tx_size);
3429a0bf528SMauro Carvalho Chehab 		fw_msg.len = tx_size + 1;
343347c4e95SMauro Carvalho Chehab 		if (__i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
3449a0bf528SMauro Carvalho Chehab 			printk(KERN_ERR "tda1004x: Error during firmware upload\n");
345347c4e95SMauro Carvalho Chehab 			i2c_unlock_adapter(state->i2c);
3469a0bf528SMauro Carvalho Chehab 			return -EIO;
3479a0bf528SMauro Carvalho Chehab 		}
3489a0bf528SMauro Carvalho Chehab 		pos += tx_size;
3499a0bf528SMauro Carvalho Chehab 
3509a0bf528SMauro Carvalho Chehab 		dprintk("%s: fw_pos=0x%x\n", __func__, pos);
3519a0bf528SMauro Carvalho Chehab 	}
352347c4e95SMauro Carvalho Chehab 	i2c_unlock_adapter(state->i2c);
353347c4e95SMauro Carvalho Chehab 
354347c4e95SMauro Carvalho Chehab 	/* give the DSP a chance to settle 03/10/05 Hac */
3559a0bf528SMauro Carvalho Chehab 	msleep(100);
3569a0bf528SMauro Carvalho Chehab 
3579a0bf528SMauro Carvalho Chehab 	return 0;
3589a0bf528SMauro Carvalho Chehab }
3599a0bf528SMauro Carvalho Chehab 
3609a0bf528SMauro Carvalho Chehab static int tda1004x_check_upload_ok(struct tda1004x_state *state)
3619a0bf528SMauro Carvalho Chehab {
3629a0bf528SMauro Carvalho Chehab 	u8 data1, data2;
3639a0bf528SMauro Carvalho Chehab 	unsigned long timeout;
3649a0bf528SMauro Carvalho Chehab 
3659a0bf528SMauro Carvalho Chehab 	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
3669a0bf528SMauro Carvalho Chehab 		timeout = jiffies + 2 * HZ;
3679a0bf528SMauro Carvalho Chehab 		while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
3689a0bf528SMauro Carvalho Chehab 			if (time_after(jiffies, timeout)) {
3699a0bf528SMauro Carvalho Chehab 				printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
3709a0bf528SMauro Carvalho Chehab 				break;
3719a0bf528SMauro Carvalho Chehab 			}
3729a0bf528SMauro Carvalho Chehab 			msleep(1);
3739a0bf528SMauro Carvalho Chehab 		}
3749a0bf528SMauro Carvalho Chehab 	} else
3759a0bf528SMauro Carvalho Chehab 		msleep(100);
3769a0bf528SMauro Carvalho Chehab 
3779a0bf528SMauro Carvalho Chehab 	// check upload was OK
3789a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
3799a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
3809a0bf528SMauro Carvalho Chehab 
3819a0bf528SMauro Carvalho Chehab 	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
3829a0bf528SMauro Carvalho Chehab 	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
3839a0bf528SMauro Carvalho Chehab 	if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
3849a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
3859a0bf528SMauro Carvalho Chehab 		return -EIO;
3869a0bf528SMauro Carvalho Chehab 	}
3879a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
3889a0bf528SMauro Carvalho Chehab 	return 0;
3899a0bf528SMauro Carvalho Chehab }
3909a0bf528SMauro Carvalho Chehab 
3919a0bf528SMauro Carvalho Chehab static int tda10045_fwupload(struct dvb_frontend* fe)
3929a0bf528SMauro Carvalho Chehab {
3939a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
3949a0bf528SMauro Carvalho Chehab 	int ret;
3959a0bf528SMauro Carvalho Chehab 	const struct firmware *fw;
3969a0bf528SMauro Carvalho Chehab 
3979a0bf528SMauro Carvalho Chehab 	/* don't re-upload unless necessary */
3989a0bf528SMauro Carvalho Chehab 	if (tda1004x_check_upload_ok(state) == 0)
3999a0bf528SMauro Carvalho Chehab 		return 0;
4009a0bf528SMauro Carvalho Chehab 
4019a0bf528SMauro Carvalho Chehab 	/* request the firmware, this will block until someone uploads it */
4029a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
4039a0bf528SMauro Carvalho Chehab 	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
4049a0bf528SMauro Carvalho Chehab 	if (ret) {
4059a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
4069a0bf528SMauro Carvalho Chehab 		return ret;
4079a0bf528SMauro Carvalho Chehab 	}
4089a0bf528SMauro Carvalho Chehab 
4099a0bf528SMauro Carvalho Chehab 	/* reset chip */
4109a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);
4119a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
4129a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
4139a0bf528SMauro Carvalho Chehab 	msleep(10);
4149a0bf528SMauro Carvalho Chehab 
4159a0bf528SMauro Carvalho Chehab 	/* set parameters */
4169a0bf528SMauro Carvalho Chehab 	tda10045h_set_bandwidth(state, 8000000);
4179a0bf528SMauro Carvalho Chehab 
4189a0bf528SMauro Carvalho Chehab 	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
4199a0bf528SMauro Carvalho Chehab 	release_firmware(fw);
4209a0bf528SMauro Carvalho Chehab 	if (ret)
4219a0bf528SMauro Carvalho Chehab 		return ret;
4229a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "tda1004x: firmware upload complete\n");
4239a0bf528SMauro Carvalho Chehab 
4249a0bf528SMauro Carvalho Chehab 	/* wait for DSP to initialise */
4259a0bf528SMauro Carvalho Chehab 	/* DSPREADY doesn't seem to work on the TDA10045H */
4269a0bf528SMauro Carvalho Chehab 	msleep(100);
4279a0bf528SMauro Carvalho Chehab 
4289a0bf528SMauro Carvalho Chehab 	return tda1004x_check_upload_ok(state);
4299a0bf528SMauro Carvalho Chehab }
4309a0bf528SMauro Carvalho Chehab 
4319a0bf528SMauro Carvalho Chehab static void tda10046_init_plls(struct dvb_frontend* fe)
4329a0bf528SMauro Carvalho Chehab {
4339a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
4349a0bf528SMauro Carvalho Chehab 	int tda10046_clk53m;
4359a0bf528SMauro Carvalho Chehab 
4369a0bf528SMauro Carvalho Chehab 	if ((state->config->if_freq == TDA10046_FREQ_045) ||
4379a0bf528SMauro Carvalho Chehab 	    (state->config->if_freq == TDA10046_FREQ_052))
4389a0bf528SMauro Carvalho Chehab 		tda10046_clk53m = 0;
4399a0bf528SMauro Carvalho Chehab 	else
4409a0bf528SMauro Carvalho Chehab 		tda10046_clk53m = 1;
4419a0bf528SMauro Carvalho Chehab 
4429a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
4439a0bf528SMauro Carvalho Chehab 	if(tda10046_clk53m) {
4449a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
4459a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
4469a0bf528SMauro Carvalho Chehab 	} else {
4479a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
4489a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
4499a0bf528SMauro Carvalho Chehab 	}
4509a0bf528SMauro Carvalho Chehab 	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
4519a0bf528SMauro Carvalho Chehab 		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__);
4529a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
4539a0bf528SMauro Carvalho Chehab 	} else {
4549a0bf528SMauro Carvalho Chehab 		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__);
4559a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
4569a0bf528SMauro Carvalho Chehab 	}
4579a0bf528SMauro Carvalho Chehab 	if(tda10046_clk53m)
4589a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
4599a0bf528SMauro Carvalho Chehab 	else
4609a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
4619a0bf528SMauro Carvalho Chehab 	/* Note clock frequency is handled implicitly */
4629a0bf528SMauro Carvalho Chehab 	switch (state->config->if_freq) {
4639a0bf528SMauro Carvalho Chehab 	case TDA10046_FREQ_045:
4649a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
4659a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
4669a0bf528SMauro Carvalho Chehab 		break;
4679a0bf528SMauro Carvalho Chehab 	case TDA10046_FREQ_052:
4689a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
4699a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
4709a0bf528SMauro Carvalho Chehab 		break;
4719a0bf528SMauro Carvalho Chehab 	case TDA10046_FREQ_3617:
4729a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4739a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
4749a0bf528SMauro Carvalho Chehab 		break;
4759a0bf528SMauro Carvalho Chehab 	case TDA10046_FREQ_3613:
4769a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4779a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
4789a0bf528SMauro Carvalho Chehab 		break;
4799a0bf528SMauro Carvalho Chehab 	}
4809a0bf528SMauro Carvalho Chehab 	tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */
4819a0bf528SMauro Carvalho Chehab 	/* let the PLLs settle */
4829a0bf528SMauro Carvalho Chehab 	msleep(120);
4839a0bf528SMauro Carvalho Chehab }
4849a0bf528SMauro Carvalho Chehab 
4859a0bf528SMauro Carvalho Chehab static int tda10046_fwupload(struct dvb_frontend* fe)
4869a0bf528SMauro Carvalho Chehab {
4879a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
4889a0bf528SMauro Carvalho Chehab 	int ret, confc4;
4899a0bf528SMauro Carvalho Chehab 	const struct firmware *fw;
4909a0bf528SMauro Carvalho Chehab 
4919a0bf528SMauro Carvalho Chehab 	/* reset + wake up chip */
4929a0bf528SMauro Carvalho Chehab 	if (state->config->xtal_freq == TDA10046_XTAL_4M) {
4939a0bf528SMauro Carvalho Chehab 		confc4 = 0;
4949a0bf528SMauro Carvalho Chehab 	} else {
4959a0bf528SMauro Carvalho Chehab 		dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
4969a0bf528SMauro Carvalho Chehab 		confc4 = 0x80;
4979a0bf528SMauro Carvalho Chehab 	}
4989a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
4999a0bf528SMauro Carvalho Chehab 
5009a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
5019a0bf528SMauro Carvalho Chehab 	/* set GPIO 1 and 3 */
5029a0bf528SMauro Carvalho Chehab 	if (state->config->gpio_config != TDA10046_GPTRI) {
5039a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
5049a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
5059a0bf528SMauro Carvalho Chehab 	}
5069a0bf528SMauro Carvalho Chehab 	/* let the clocks recover from sleep */
5079a0bf528SMauro Carvalho Chehab 	msleep(10);
5089a0bf528SMauro Carvalho Chehab 
5099a0bf528SMauro Carvalho Chehab 	/* The PLLs need to be reprogrammed after sleep */
5109a0bf528SMauro Carvalho Chehab 	tda10046_init_plls(fe);
5119a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0);
5129a0bf528SMauro Carvalho Chehab 
5139a0bf528SMauro Carvalho Chehab 	/* don't re-upload unless necessary */
5149a0bf528SMauro Carvalho Chehab 	if (tda1004x_check_upload_ok(state) == 0)
5159a0bf528SMauro Carvalho Chehab 		return 0;
5169a0bf528SMauro Carvalho Chehab 
5179a0bf528SMauro Carvalho Chehab 	/*
5189a0bf528SMauro Carvalho Chehab 	   For i2c normal work, we need to slow down the bus speed.
5199a0bf528SMauro Carvalho Chehab 	   However, the slow down breaks the eeprom firmware load.
5209a0bf528SMauro Carvalho Chehab 	   So, use normal speed for eeprom booting and then restore the
5219a0bf528SMauro Carvalho Chehab 	   i2c speed after that. Tested with MSI TV @nyware A/D board,
5229a0bf528SMauro Carvalho Chehab 	   that comes with firmware version 29 inside their eeprom.
5239a0bf528SMauro Carvalho Chehab 
5249a0bf528SMauro Carvalho Chehab 	   It should also be noticed that no other I2C transfer should
5259a0bf528SMauro Carvalho Chehab 	   be in course while booting from eeprom, otherwise, tda10046
5269a0bf528SMauro Carvalho Chehab 	   goes into an instable state. So, proper locking are needed
5279a0bf528SMauro Carvalho Chehab 	   at the i2c bus master.
5289a0bf528SMauro Carvalho Chehab 	 */
5299a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
5309a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
5319a0bf528SMauro Carvalho Chehab 	msleep(300);
5329a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
5339a0bf528SMauro Carvalho Chehab 
5349a0bf528SMauro Carvalho Chehab 	/* Checks if eeprom firmware went without troubles */
5359a0bf528SMauro Carvalho Chehab 	if (tda1004x_check_upload_ok(state) == 0)
5369a0bf528SMauro Carvalho Chehab 		return 0;
5379a0bf528SMauro Carvalho Chehab 
5389a0bf528SMauro Carvalho Chehab 	/* eeprom firmware didn't work. Load one manually. */
5399a0bf528SMauro Carvalho Chehab 
5409a0bf528SMauro Carvalho Chehab 	if (state->config->request_firmware != NULL) {
5419a0bf528SMauro Carvalho Chehab 		/* request the firmware, this will block until someone uploads it */
5429a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
5439a0bf528SMauro Carvalho Chehab 		ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
5449a0bf528SMauro Carvalho Chehab 		if (ret) {
5459a0bf528SMauro Carvalho Chehab 			/* remain compatible to old bug: try to load with tda10045 image name */
5469a0bf528SMauro Carvalho Chehab 			ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
5479a0bf528SMauro Carvalho Chehab 			if (ret) {
5489a0bf528SMauro Carvalho Chehab 				printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
5499a0bf528SMauro Carvalho Chehab 				return ret;
5509a0bf528SMauro Carvalho Chehab 			} else {
5519a0bf528SMauro Carvalho Chehab 				printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
5529a0bf528SMauro Carvalho Chehab 						  TDA10046_DEFAULT_FIRMWARE);
5539a0bf528SMauro Carvalho Chehab 			}
5549a0bf528SMauro Carvalho Chehab 		}
5559a0bf528SMauro Carvalho Chehab 	} else {
5569a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
5579a0bf528SMauro Carvalho Chehab 		return -EIO;
5589a0bf528SMauro Carvalho Chehab 	}
5599a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
5609a0bf528SMauro Carvalho Chehab 	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
5619a0bf528SMauro Carvalho Chehab 	release_firmware(fw);
5629a0bf528SMauro Carvalho Chehab 	return tda1004x_check_upload_ok(state);
5639a0bf528SMauro Carvalho Chehab }
5649a0bf528SMauro Carvalho Chehab 
5659a0bf528SMauro Carvalho Chehab static int tda1004x_encode_fec(int fec)
5669a0bf528SMauro Carvalho Chehab {
5679a0bf528SMauro Carvalho Chehab 	// convert known FEC values
5689a0bf528SMauro Carvalho Chehab 	switch (fec) {
5699a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
5709a0bf528SMauro Carvalho Chehab 		return 0;
5719a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
5729a0bf528SMauro Carvalho Chehab 		return 1;
5739a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
5749a0bf528SMauro Carvalho Chehab 		return 2;
5759a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
5769a0bf528SMauro Carvalho Chehab 		return 3;
5779a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
5789a0bf528SMauro Carvalho Chehab 		return 4;
5799a0bf528SMauro Carvalho Chehab 	}
5809a0bf528SMauro Carvalho Chehab 
5819a0bf528SMauro Carvalho Chehab 	// unsupported
5829a0bf528SMauro Carvalho Chehab 	return -EINVAL;
5839a0bf528SMauro Carvalho Chehab }
5849a0bf528SMauro Carvalho Chehab 
5859a0bf528SMauro Carvalho Chehab static int tda1004x_decode_fec(int tdafec)
5869a0bf528SMauro Carvalho Chehab {
5879a0bf528SMauro Carvalho Chehab 	// convert known FEC values
5889a0bf528SMauro Carvalho Chehab 	switch (tdafec) {
5899a0bf528SMauro Carvalho Chehab 	case 0:
5909a0bf528SMauro Carvalho Chehab 		return FEC_1_2;
5919a0bf528SMauro Carvalho Chehab 	case 1:
5929a0bf528SMauro Carvalho Chehab 		return FEC_2_3;
5939a0bf528SMauro Carvalho Chehab 	case 2:
5949a0bf528SMauro Carvalho Chehab 		return FEC_3_4;
5959a0bf528SMauro Carvalho Chehab 	case 3:
5969a0bf528SMauro Carvalho Chehab 		return FEC_5_6;
5979a0bf528SMauro Carvalho Chehab 	case 4:
5989a0bf528SMauro Carvalho Chehab 		return FEC_7_8;
5999a0bf528SMauro Carvalho Chehab 	}
6009a0bf528SMauro Carvalho Chehab 
6019a0bf528SMauro Carvalho Chehab 	// unsupported
6029a0bf528SMauro Carvalho Chehab 	return -1;
6039a0bf528SMauro Carvalho Chehab }
6049a0bf528SMauro Carvalho Chehab 
6059a0bf528SMauro Carvalho Chehab static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
6069a0bf528SMauro Carvalho Chehab {
6079a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
6089a0bf528SMauro Carvalho Chehab 
6099a0bf528SMauro Carvalho Chehab 	if (len != 2)
6109a0bf528SMauro Carvalho Chehab 		return -EINVAL;
6119a0bf528SMauro Carvalho Chehab 
6129a0bf528SMauro Carvalho Chehab 	return tda1004x_write_byteI(state, buf[0], buf[1]);
6139a0bf528SMauro Carvalho Chehab }
6149a0bf528SMauro Carvalho Chehab 
6159a0bf528SMauro Carvalho Chehab static int tda10045_init(struct dvb_frontend* fe)
6169a0bf528SMauro Carvalho Chehab {
6179a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
6189a0bf528SMauro Carvalho Chehab 
6199a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
6209a0bf528SMauro Carvalho Chehab 
6219a0bf528SMauro Carvalho Chehab 	if (tda10045_fwupload(fe)) {
6229a0bf528SMauro Carvalho Chehab 		printk("tda1004x: firmware upload failed\n");
6239a0bf528SMauro Carvalho Chehab 		return -EIO;
6249a0bf528SMauro Carvalho Chehab 	}
6259a0bf528SMauro Carvalho Chehab 
6269a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
6279a0bf528SMauro Carvalho Chehab 
6289a0bf528SMauro Carvalho Chehab 	// tda setup
6299a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6309a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
6319a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal
6329a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
6339a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
6349a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
6359a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
6369a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
6379a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
6389a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
6399a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e);
6409a0bf528SMauro Carvalho Chehab 
6419a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk);
6429a0bf528SMauro Carvalho Chehab 
6439a0bf528SMauro Carvalho Chehab 	return 0;
6449a0bf528SMauro Carvalho Chehab }
6459a0bf528SMauro Carvalho Chehab 
6469a0bf528SMauro Carvalho Chehab static int tda10046_init(struct dvb_frontend* fe)
6479a0bf528SMauro Carvalho Chehab {
6489a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
6499a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
6509a0bf528SMauro Carvalho Chehab 
6519a0bf528SMauro Carvalho Chehab 	if (tda10046_fwupload(fe)) {
6529a0bf528SMauro Carvalho Chehab 		printk("tda1004x: firmware upload failed\n");
6539a0bf528SMauro Carvalho Chehab 		return -EIO;
6549a0bf528SMauro Carvalho Chehab 	}
6559a0bf528SMauro Carvalho Chehab 
6569a0bf528SMauro Carvalho Chehab 	// tda setup
6579a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6589a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
6599a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
6609a0bf528SMauro Carvalho Chehab 
6619a0bf528SMauro Carvalho Chehab 	switch (state->config->agc_config) {
6629a0bf528SMauro Carvalho Chehab 	case TDA10046_AGC_DEFAULT:
6639a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
6649a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
6659a0bf528SMauro Carvalho Chehab 		break;
6669a0bf528SMauro Carvalho Chehab 	case TDA10046_AGC_IFO_AUTO_NEG:
6679a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6689a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
6699a0bf528SMauro Carvalho Chehab 		break;
6709a0bf528SMauro Carvalho Chehab 	case TDA10046_AGC_IFO_AUTO_POS:
6719a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6729a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00);  // set AGC polarities
6739a0bf528SMauro Carvalho Chehab 		break;
6749a0bf528SMauro Carvalho Chehab 	case TDA10046_AGC_TDA827X:
6759a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
6769a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
6779a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
6789a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
6799a0bf528SMauro Carvalho Chehab 		break;
6809a0bf528SMauro Carvalho Chehab 	}
6819a0bf528SMauro Carvalho Chehab 	if (state->config->ts_mode == 0) {
6829a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40);
6839a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
6849a0bf528SMauro Carvalho Chehab 	} else {
6859a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80);
6869a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10,
6879a0bf528SMauro Carvalho Chehab 							state->config->invert_oclk << 4);
6889a0bf528SMauro Carvalho Chehab 	}
6899a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
6909a0bf528SMauro Carvalho Chehab 	tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on
6919a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
6929a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
6939a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
6949a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
6959a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
6969a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
6979a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
6989a0bf528SMauro Carvalho Chehab 	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
6999a0bf528SMauro Carvalho Chehab 	// tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
7009a0bf528SMauro Carvalho Chehab 
7019a0bf528SMauro Carvalho Chehab 	return 0;
7029a0bf528SMauro Carvalho Chehab }
7039a0bf528SMauro Carvalho Chehab 
7049a0bf528SMauro Carvalho Chehab static int tda1004x_set_fe(struct dvb_frontend *fe)
7059a0bf528SMauro Carvalho Chehab {
7069a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
7079a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
7089a0bf528SMauro Carvalho Chehab 	int tmp;
7099a0bf528SMauro Carvalho Chehab 	int inversion;
7109a0bf528SMauro Carvalho Chehab 
7119a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
7129a0bf528SMauro Carvalho Chehab 
7139a0bf528SMauro Carvalho Chehab 	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
7149a0bf528SMauro Carvalho Chehab 		// setup auto offset
7159a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10);
7169a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0);
7179a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0);
7189a0bf528SMauro Carvalho Chehab 
7199a0bf528SMauro Carvalho Chehab 		// disable agc_conf[2]
7209a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0);
7219a0bf528SMauro Carvalho Chehab 	}
7229a0bf528SMauro Carvalho Chehab 
7239a0bf528SMauro Carvalho Chehab 	// set frequency
7249a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
7259a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
7269a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
7279a0bf528SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
7289a0bf528SMauro Carvalho Chehab 	}
7299a0bf528SMauro Carvalho Chehab 
7309a0bf528SMauro Carvalho Chehab 	// Hardcoded to use auto as much as possible on the TDA10045 as it
7319a0bf528SMauro Carvalho Chehab 	// is very unreliable if AUTO mode is _not_ used.
7329a0bf528SMauro Carvalho Chehab 	if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
7339a0bf528SMauro Carvalho Chehab 		fe_params->code_rate_HP = FEC_AUTO;
7349a0bf528SMauro Carvalho Chehab 		fe_params->guard_interval = GUARD_INTERVAL_AUTO;
7359a0bf528SMauro Carvalho Chehab 		fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
7369a0bf528SMauro Carvalho Chehab 	}
7379a0bf528SMauro Carvalho Chehab 
7389a0bf528SMauro Carvalho Chehab 	// Set standard params.. or put them to auto
7399a0bf528SMauro Carvalho Chehab 	if ((fe_params->code_rate_HP == FEC_AUTO) ||
7409a0bf528SMauro Carvalho Chehab 		(fe_params->code_rate_LP == FEC_AUTO) ||
7419a0bf528SMauro Carvalho Chehab 		(fe_params->modulation == QAM_AUTO) ||
7429a0bf528SMauro Carvalho Chehab 		(fe_params->hierarchy == HIERARCHY_AUTO)) {
7439a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);	// enable auto
7449a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0);	/* turn off modulation bits */
7459a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0);	// turn off hierarchy bits
7469a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0);	// turn off FEC bits
7479a0bf528SMauro Carvalho Chehab 	} else {
7489a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0);	// disable auto
7499a0bf528SMauro Carvalho Chehab 
7509a0bf528SMauro Carvalho Chehab 		// set HP FEC
7519a0bf528SMauro Carvalho Chehab 		tmp = tda1004x_encode_fec(fe_params->code_rate_HP);
7529a0bf528SMauro Carvalho Chehab 		if (tmp < 0)
7539a0bf528SMauro Carvalho Chehab 			return tmp;
7549a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
7559a0bf528SMauro Carvalho Chehab 
7569a0bf528SMauro Carvalho Chehab 		// set LP FEC
7579a0bf528SMauro Carvalho Chehab 		tmp = tda1004x_encode_fec(fe_params->code_rate_LP);
7589a0bf528SMauro Carvalho Chehab 		if (tmp < 0)
7599a0bf528SMauro Carvalho Chehab 			return tmp;
7609a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
7619a0bf528SMauro Carvalho Chehab 
7629a0bf528SMauro Carvalho Chehab 		/* set modulation */
7639a0bf528SMauro Carvalho Chehab 		switch (fe_params->modulation) {
7649a0bf528SMauro Carvalho Chehab 		case QPSK:
7659a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
7669a0bf528SMauro Carvalho Chehab 			break;
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 		case QAM_16:
7699a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1);
7709a0bf528SMauro Carvalho Chehab 			break;
7719a0bf528SMauro Carvalho Chehab 
7729a0bf528SMauro Carvalho Chehab 		case QAM_64:
7739a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2);
7749a0bf528SMauro Carvalho Chehab 			break;
7759a0bf528SMauro Carvalho Chehab 
7769a0bf528SMauro Carvalho Chehab 		default:
7779a0bf528SMauro Carvalho Chehab 			return -EINVAL;
7789a0bf528SMauro Carvalho Chehab 		}
7799a0bf528SMauro Carvalho Chehab 
7809a0bf528SMauro Carvalho Chehab 		// set hierarchy
7819a0bf528SMauro Carvalho Chehab 		switch (fe_params->hierarchy) {
7829a0bf528SMauro Carvalho Chehab 		case HIERARCHY_NONE:
7839a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
7849a0bf528SMauro Carvalho Chehab 			break;
7859a0bf528SMauro Carvalho Chehab 
7869a0bf528SMauro Carvalho Chehab 		case HIERARCHY_1:
7879a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
7889a0bf528SMauro Carvalho Chehab 			break;
7899a0bf528SMauro Carvalho Chehab 
7909a0bf528SMauro Carvalho Chehab 		case HIERARCHY_2:
7919a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
7929a0bf528SMauro Carvalho Chehab 			break;
7939a0bf528SMauro Carvalho Chehab 
7949a0bf528SMauro Carvalho Chehab 		case HIERARCHY_4:
7959a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
7969a0bf528SMauro Carvalho Chehab 			break;
7979a0bf528SMauro Carvalho Chehab 
7989a0bf528SMauro Carvalho Chehab 		default:
7999a0bf528SMauro Carvalho Chehab 			return -EINVAL;
8009a0bf528SMauro Carvalho Chehab 		}
8019a0bf528SMauro Carvalho Chehab 	}
8029a0bf528SMauro Carvalho Chehab 
8039a0bf528SMauro Carvalho Chehab 	// set bandwidth
8049a0bf528SMauro Carvalho Chehab 	switch (state->demod_type) {
8059a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10045:
8069a0bf528SMauro Carvalho Chehab 		tda10045h_set_bandwidth(state, fe_params->bandwidth_hz);
8079a0bf528SMauro Carvalho Chehab 		break;
8089a0bf528SMauro Carvalho Chehab 
8099a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10046:
8109a0bf528SMauro Carvalho Chehab 		tda10046h_set_bandwidth(state, fe_params->bandwidth_hz);
8119a0bf528SMauro Carvalho Chehab 		break;
8129a0bf528SMauro Carvalho Chehab 	}
8139a0bf528SMauro Carvalho Chehab 
8149a0bf528SMauro Carvalho Chehab 	// set inversion
8159a0bf528SMauro Carvalho Chehab 	inversion = fe_params->inversion;
8169a0bf528SMauro Carvalho Chehab 	if (state->config->invert)
8179a0bf528SMauro Carvalho Chehab 		inversion = inversion ? INVERSION_OFF : INVERSION_ON;
8189a0bf528SMauro Carvalho Chehab 	switch (inversion) {
8199a0bf528SMauro Carvalho Chehab 	case INVERSION_OFF:
8209a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
8219a0bf528SMauro Carvalho Chehab 		break;
8229a0bf528SMauro Carvalho Chehab 
8239a0bf528SMauro Carvalho Chehab 	case INVERSION_ON:
8249a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20);
8259a0bf528SMauro Carvalho Chehab 		break;
8269a0bf528SMauro Carvalho Chehab 
8279a0bf528SMauro Carvalho Chehab 	default:
8289a0bf528SMauro Carvalho Chehab 		return -EINVAL;
8299a0bf528SMauro Carvalho Chehab 	}
8309a0bf528SMauro Carvalho Chehab 
8319a0bf528SMauro Carvalho Chehab 	// set guard interval
8329a0bf528SMauro Carvalho Chehab 	switch (fe_params->guard_interval) {
8339a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
8349a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8359a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8369a0bf528SMauro Carvalho Chehab 		break;
8379a0bf528SMauro Carvalho Chehab 
8389a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
8399a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8409a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
8419a0bf528SMauro Carvalho Chehab 		break;
8429a0bf528SMauro Carvalho Chehab 
8439a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
8449a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8459a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
8469a0bf528SMauro Carvalho Chehab 		break;
8479a0bf528SMauro Carvalho Chehab 
8489a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
8499a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8509a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
8519a0bf528SMauro Carvalho Chehab 		break;
8529a0bf528SMauro Carvalho Chehab 
8539a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_AUTO:
8549a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2);
8559a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8569a0bf528SMauro Carvalho Chehab 		break;
8579a0bf528SMauro Carvalho Chehab 
8589a0bf528SMauro Carvalho Chehab 	default:
8599a0bf528SMauro Carvalho Chehab 		return -EINVAL;
8609a0bf528SMauro Carvalho Chehab 	}
8619a0bf528SMauro Carvalho Chehab 
8629a0bf528SMauro Carvalho Chehab 	// set transmission mode
8639a0bf528SMauro Carvalho Chehab 	switch (fe_params->transmission_mode) {
8649a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
8659a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8669a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
8679a0bf528SMauro Carvalho Chehab 		break;
8689a0bf528SMauro Carvalho Chehab 
8699a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
8709a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8719a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
8729a0bf528SMauro Carvalho Chehab 		break;
8739a0bf528SMauro Carvalho Chehab 
8749a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_AUTO:
8759a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4);
8769a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0);
8779a0bf528SMauro Carvalho Chehab 		break;
8789a0bf528SMauro Carvalho Chehab 
8799a0bf528SMauro Carvalho Chehab 	default:
8809a0bf528SMauro Carvalho Chehab 		return -EINVAL;
8819a0bf528SMauro Carvalho Chehab 	}
8829a0bf528SMauro Carvalho Chehab 
8839a0bf528SMauro Carvalho Chehab 	// start the lock
8849a0bf528SMauro Carvalho Chehab 	switch (state->demod_type) {
8859a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10045:
8869a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
8879a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
8889a0bf528SMauro Carvalho Chehab 		break;
8899a0bf528SMauro Carvalho Chehab 
8909a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10046:
8919a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
8929a0bf528SMauro Carvalho Chehab 		msleep(1);
8939a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
8949a0bf528SMauro Carvalho Chehab 		break;
8959a0bf528SMauro Carvalho Chehab 	}
8969a0bf528SMauro Carvalho Chehab 
8979a0bf528SMauro Carvalho Chehab 	msleep(10);
8989a0bf528SMauro Carvalho Chehab 
8999a0bf528SMauro Carvalho Chehab 	return 0;
9009a0bf528SMauro Carvalho Chehab }
9019a0bf528SMauro Carvalho Chehab 
9027e3e68bcSMauro Carvalho Chehab static int tda1004x_get_fe(struct dvb_frontend *fe,
9037e3e68bcSMauro Carvalho Chehab 			   struct dtv_frontend_properties *fe_params)
9049a0bf528SMauro Carvalho Chehab {
9059a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
906e8beb023SMauro Carvalho Chehab 	int status;
9079a0bf528SMauro Carvalho Chehab 
9089a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
9099a0bf528SMauro Carvalho Chehab 
910e8beb023SMauro Carvalho Chehab 	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
911e8beb023SMauro Carvalho Chehab 	if (status == -1)
912e8beb023SMauro Carvalho Chehab 		return -EIO;
913e8beb023SMauro Carvalho Chehab 
914e8beb023SMauro Carvalho Chehab 	/* Only update the properties cache if device is locked */
915e8beb023SMauro Carvalho Chehab 	if (!(status & 8))
916e8beb023SMauro Carvalho Chehab 		return 0;
917e8beb023SMauro Carvalho Chehab 
9189a0bf528SMauro Carvalho Chehab 	// inversion status
9199a0bf528SMauro Carvalho Chehab 	fe_params->inversion = INVERSION_OFF;
9209a0bf528SMauro Carvalho Chehab 	if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
9219a0bf528SMauro Carvalho Chehab 		fe_params->inversion = INVERSION_ON;
9229a0bf528SMauro Carvalho Chehab 	if (state->config->invert)
9239a0bf528SMauro Carvalho Chehab 		fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
9249a0bf528SMauro Carvalho Chehab 
9259a0bf528SMauro Carvalho Chehab 	// bandwidth
9269a0bf528SMauro Carvalho Chehab 	switch (state->demod_type) {
9279a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10045:
9289a0bf528SMauro Carvalho Chehab 		switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
9299a0bf528SMauro Carvalho Chehab 		case 0x14:
9309a0bf528SMauro Carvalho Chehab 			fe_params->bandwidth_hz = 8000000;
9319a0bf528SMauro Carvalho Chehab 			break;
9329a0bf528SMauro Carvalho Chehab 		case 0xdb:
9339a0bf528SMauro Carvalho Chehab 			fe_params->bandwidth_hz = 7000000;
9349a0bf528SMauro Carvalho Chehab 			break;
9359a0bf528SMauro Carvalho Chehab 		case 0x4f:
9369a0bf528SMauro Carvalho Chehab 			fe_params->bandwidth_hz = 6000000;
9379a0bf528SMauro Carvalho Chehab 			break;
9389a0bf528SMauro Carvalho Chehab 		}
9399a0bf528SMauro Carvalho Chehab 		break;
9409a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10046:
9419a0bf528SMauro Carvalho Chehab 		switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
9429a0bf528SMauro Carvalho Chehab 		case 0x5c:
9439a0bf528SMauro Carvalho Chehab 		case 0x54:
9449a0bf528SMauro Carvalho Chehab 			fe_params->bandwidth_hz = 8000000;
9459a0bf528SMauro Carvalho Chehab 			break;
9469a0bf528SMauro Carvalho Chehab 		case 0x6a:
9479a0bf528SMauro Carvalho Chehab 		case 0x60:
9489a0bf528SMauro Carvalho Chehab 			fe_params->bandwidth_hz = 7000000;
9499a0bf528SMauro Carvalho Chehab 			break;
9509a0bf528SMauro Carvalho Chehab 		case 0x7b:
9519a0bf528SMauro Carvalho Chehab 		case 0x70:
9529a0bf528SMauro Carvalho Chehab 			fe_params->bandwidth_hz = 6000000;
9539a0bf528SMauro Carvalho Chehab 			break;
9549a0bf528SMauro Carvalho Chehab 		}
9559a0bf528SMauro Carvalho Chehab 		break;
9569a0bf528SMauro Carvalho Chehab 	}
9579a0bf528SMauro Carvalho Chehab 
9589a0bf528SMauro Carvalho Chehab 	// FEC
9599a0bf528SMauro Carvalho Chehab 	fe_params->code_rate_HP =
9609a0bf528SMauro Carvalho Chehab 	    tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
9619a0bf528SMauro Carvalho Chehab 	fe_params->code_rate_LP =
9629a0bf528SMauro Carvalho Chehab 	    tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
9639a0bf528SMauro Carvalho Chehab 
9649a0bf528SMauro Carvalho Chehab 	/* modulation */
9659a0bf528SMauro Carvalho Chehab 	switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
9669a0bf528SMauro Carvalho Chehab 	case 0:
9679a0bf528SMauro Carvalho Chehab 		fe_params->modulation = QPSK;
9689a0bf528SMauro Carvalho Chehab 		break;
9699a0bf528SMauro Carvalho Chehab 	case 1:
9709a0bf528SMauro Carvalho Chehab 		fe_params->modulation = QAM_16;
9719a0bf528SMauro Carvalho Chehab 		break;
9729a0bf528SMauro Carvalho Chehab 	case 2:
9739a0bf528SMauro Carvalho Chehab 		fe_params->modulation = QAM_64;
9749a0bf528SMauro Carvalho Chehab 		break;
9759a0bf528SMauro Carvalho Chehab 	}
9769a0bf528SMauro Carvalho Chehab 
9779a0bf528SMauro Carvalho Chehab 	// transmission mode
9789a0bf528SMauro Carvalho Chehab 	fe_params->transmission_mode = TRANSMISSION_MODE_2K;
9799a0bf528SMauro Carvalho Chehab 	if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
9809a0bf528SMauro Carvalho Chehab 		fe_params->transmission_mode = TRANSMISSION_MODE_8K;
9819a0bf528SMauro Carvalho Chehab 
9829a0bf528SMauro Carvalho Chehab 	// guard interval
9839a0bf528SMauro Carvalho Chehab 	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
9849a0bf528SMauro Carvalho Chehab 	case 0:
9859a0bf528SMauro Carvalho Chehab 		fe_params->guard_interval = GUARD_INTERVAL_1_32;
9869a0bf528SMauro Carvalho Chehab 		break;
9879a0bf528SMauro Carvalho Chehab 	case 1:
9889a0bf528SMauro Carvalho Chehab 		fe_params->guard_interval = GUARD_INTERVAL_1_16;
9899a0bf528SMauro Carvalho Chehab 		break;
9909a0bf528SMauro Carvalho Chehab 	case 2:
9919a0bf528SMauro Carvalho Chehab 		fe_params->guard_interval = GUARD_INTERVAL_1_8;
9929a0bf528SMauro Carvalho Chehab 		break;
9939a0bf528SMauro Carvalho Chehab 	case 3:
9949a0bf528SMauro Carvalho Chehab 		fe_params->guard_interval = GUARD_INTERVAL_1_4;
9959a0bf528SMauro Carvalho Chehab 		break;
9969a0bf528SMauro Carvalho Chehab 	}
9979a0bf528SMauro Carvalho Chehab 
9989a0bf528SMauro Carvalho Chehab 	// hierarchy
9999a0bf528SMauro Carvalho Chehab 	switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
10009a0bf528SMauro Carvalho Chehab 	case 0:
10019a0bf528SMauro Carvalho Chehab 		fe_params->hierarchy = HIERARCHY_NONE;
10029a0bf528SMauro Carvalho Chehab 		break;
10039a0bf528SMauro Carvalho Chehab 	case 1:
10049a0bf528SMauro Carvalho Chehab 		fe_params->hierarchy = HIERARCHY_1;
10059a0bf528SMauro Carvalho Chehab 		break;
10069a0bf528SMauro Carvalho Chehab 	case 2:
10079a0bf528SMauro Carvalho Chehab 		fe_params->hierarchy = HIERARCHY_2;
10089a0bf528SMauro Carvalho Chehab 		break;
10099a0bf528SMauro Carvalho Chehab 	case 3:
10109a0bf528SMauro Carvalho Chehab 		fe_params->hierarchy = HIERARCHY_4;
10119a0bf528SMauro Carvalho Chehab 		break;
10129a0bf528SMauro Carvalho Chehab 	}
10139a0bf528SMauro Carvalho Chehab 
10149a0bf528SMauro Carvalho Chehab 	return 0;
10159a0bf528SMauro Carvalho Chehab }
10169a0bf528SMauro Carvalho Chehab 
10170df289a2SMauro Carvalho Chehab static int tda1004x_read_status(struct dvb_frontend *fe,
10180df289a2SMauro Carvalho Chehab 				enum fe_status *fe_status)
10199a0bf528SMauro Carvalho Chehab {
10209a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
10219a0bf528SMauro Carvalho Chehab 	int status;
10229a0bf528SMauro Carvalho Chehab 	int cber;
10239a0bf528SMauro Carvalho Chehab 	int vber;
10249a0bf528SMauro Carvalho Chehab 
10259a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
10269a0bf528SMauro Carvalho Chehab 
10279a0bf528SMauro Carvalho Chehab 	// read status
10289a0bf528SMauro Carvalho Chehab 	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
10299a0bf528SMauro Carvalho Chehab 	if (status == -1)
10309a0bf528SMauro Carvalho Chehab 		return -EIO;
10319a0bf528SMauro Carvalho Chehab 
10329a0bf528SMauro Carvalho Chehab 	// decode
10339a0bf528SMauro Carvalho Chehab 	*fe_status = 0;
10349a0bf528SMauro Carvalho Chehab 	if (status & 4)
10359a0bf528SMauro Carvalho Chehab 		*fe_status |= FE_HAS_SIGNAL;
10369a0bf528SMauro Carvalho Chehab 	if (status & 2)
10379a0bf528SMauro Carvalho Chehab 		*fe_status |= FE_HAS_CARRIER;
10389a0bf528SMauro Carvalho Chehab 	if (status & 8)
10399a0bf528SMauro Carvalho Chehab 		*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
10409a0bf528SMauro Carvalho Chehab 
10419a0bf528SMauro Carvalho Chehab 	// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
10429a0bf528SMauro Carvalho Chehab 	// is getting anything valid
10439a0bf528SMauro Carvalho Chehab 	if (!(*fe_status & FE_HAS_VITERBI)) {
10449a0bf528SMauro Carvalho Chehab 		// read the CBER
10459a0bf528SMauro Carvalho Chehab 		cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
10469a0bf528SMauro Carvalho Chehab 		if (cber == -1)
10479a0bf528SMauro Carvalho Chehab 			return -EIO;
10489a0bf528SMauro Carvalho Chehab 		status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
10499a0bf528SMauro Carvalho Chehab 		if (status == -1)
10509a0bf528SMauro Carvalho Chehab 			return -EIO;
10519a0bf528SMauro Carvalho Chehab 		cber |= (status << 8);
10529a0bf528SMauro Carvalho Chehab 		// The address 0x20 should be read to cope with a TDA10046 bug
10539a0bf528SMauro Carvalho Chehab 		tda1004x_read_byte(state, TDA1004X_CBER_RESET);
10549a0bf528SMauro Carvalho Chehab 
10559a0bf528SMauro Carvalho Chehab 		if (cber != 65535)
10569a0bf528SMauro Carvalho Chehab 			*fe_status |= FE_HAS_VITERBI;
10579a0bf528SMauro Carvalho Chehab 	}
10589a0bf528SMauro Carvalho Chehab 
10599a0bf528SMauro Carvalho Chehab 	// if we DO have some valid VITERBI output, but don't already have SYNC
10609a0bf528SMauro Carvalho Chehab 	// bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
10619a0bf528SMauro Carvalho Chehab 	if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
10629a0bf528SMauro Carvalho Chehab 		// read the VBER
10639a0bf528SMauro Carvalho Chehab 		vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
10649a0bf528SMauro Carvalho Chehab 		if (vber == -1)
10659a0bf528SMauro Carvalho Chehab 			return -EIO;
10669a0bf528SMauro Carvalho Chehab 		status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
10679a0bf528SMauro Carvalho Chehab 		if (status == -1)
10689a0bf528SMauro Carvalho Chehab 			return -EIO;
10699a0bf528SMauro Carvalho Chehab 		vber |= (status << 8);
10709a0bf528SMauro Carvalho Chehab 		status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
10719a0bf528SMauro Carvalho Chehab 		if (status == -1)
10729a0bf528SMauro Carvalho Chehab 			return -EIO;
10739a0bf528SMauro Carvalho Chehab 		vber |= (status & 0x0f) << 16;
10749a0bf528SMauro Carvalho Chehab 		// The CVBER_LUT should be read to cope with TDA10046 hardware bug
10759a0bf528SMauro Carvalho Chehab 		tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
10769a0bf528SMauro Carvalho Chehab 
10779a0bf528SMauro Carvalho Chehab 		// if RS has passed some valid TS packets, then we must be
10789a0bf528SMauro Carvalho Chehab 		// getting some SYNC bytes
10799a0bf528SMauro Carvalho Chehab 		if (vber < 16632)
10809a0bf528SMauro Carvalho Chehab 			*fe_status |= FE_HAS_SYNC;
10819a0bf528SMauro Carvalho Chehab 	}
10829a0bf528SMauro Carvalho Chehab 
10839a0bf528SMauro Carvalho Chehab 	// success
10849a0bf528SMauro Carvalho Chehab 	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
10859a0bf528SMauro Carvalho Chehab 	return 0;
10869a0bf528SMauro Carvalho Chehab }
10879a0bf528SMauro Carvalho Chehab 
10889a0bf528SMauro Carvalho Chehab static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
10899a0bf528SMauro Carvalho Chehab {
10909a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
10919a0bf528SMauro Carvalho Chehab 	int tmp;
10929a0bf528SMauro Carvalho Chehab 	int reg = 0;
10939a0bf528SMauro Carvalho Chehab 
10949a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
10959a0bf528SMauro Carvalho Chehab 
10969a0bf528SMauro Carvalho Chehab 	// determine the register to use
10979a0bf528SMauro Carvalho Chehab 	switch (state->demod_type) {
10989a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10045:
10999a0bf528SMauro Carvalho Chehab 		reg = TDA10045H_S_AGC;
11009a0bf528SMauro Carvalho Chehab 		break;
11019a0bf528SMauro Carvalho Chehab 
11029a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10046:
11039a0bf528SMauro Carvalho Chehab 		reg = TDA10046H_AGC_IF_LEVEL;
11049a0bf528SMauro Carvalho Chehab 		break;
11059a0bf528SMauro Carvalho Chehab 	}
11069a0bf528SMauro Carvalho Chehab 
11079a0bf528SMauro Carvalho Chehab 	// read it
11089a0bf528SMauro Carvalho Chehab 	tmp = tda1004x_read_byte(state, reg);
11099a0bf528SMauro Carvalho Chehab 	if (tmp < 0)
11109a0bf528SMauro Carvalho Chehab 		return -EIO;
11119a0bf528SMauro Carvalho Chehab 
11129a0bf528SMauro Carvalho Chehab 	*signal = (tmp << 8) | tmp;
11139a0bf528SMauro Carvalho Chehab 	dprintk("%s: signal=0x%x\n", __func__, *signal);
11149a0bf528SMauro Carvalho Chehab 	return 0;
11159a0bf528SMauro Carvalho Chehab }
11169a0bf528SMauro Carvalho Chehab 
11179a0bf528SMauro Carvalho Chehab static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
11189a0bf528SMauro Carvalho Chehab {
11199a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
11209a0bf528SMauro Carvalho Chehab 	int tmp;
11219a0bf528SMauro Carvalho Chehab 
11229a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
11239a0bf528SMauro Carvalho Chehab 
11249a0bf528SMauro Carvalho Chehab 	// read it
11259a0bf528SMauro Carvalho Chehab 	tmp = tda1004x_read_byte(state, TDA1004X_SNR);
11269a0bf528SMauro Carvalho Chehab 	if (tmp < 0)
11279a0bf528SMauro Carvalho Chehab 		return -EIO;
11289a0bf528SMauro Carvalho Chehab 	tmp = 255 - tmp;
11299a0bf528SMauro Carvalho Chehab 
11309a0bf528SMauro Carvalho Chehab 	*snr = ((tmp << 8) | tmp);
11319a0bf528SMauro Carvalho Chehab 	dprintk("%s: snr=0x%x\n", __func__, *snr);
11329a0bf528SMauro Carvalho Chehab 	return 0;
11339a0bf528SMauro Carvalho Chehab }
11349a0bf528SMauro Carvalho Chehab 
11359a0bf528SMauro Carvalho Chehab static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
11369a0bf528SMauro Carvalho Chehab {
11379a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
11389a0bf528SMauro Carvalho Chehab 	int tmp;
11399a0bf528SMauro Carvalho Chehab 	int tmp2;
11409a0bf528SMauro Carvalho Chehab 	int counter;
11419a0bf528SMauro Carvalho Chehab 
11429a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
11439a0bf528SMauro Carvalho Chehab 
11449a0bf528SMauro Carvalho Chehab 	// read the UCBLOCKS and reset
11459a0bf528SMauro Carvalho Chehab 	counter = 0;
11469a0bf528SMauro Carvalho Chehab 	tmp = tda1004x_read_byte(state, TDA1004X_UNCOR);
11479a0bf528SMauro Carvalho Chehab 	if (tmp < 0)
11489a0bf528SMauro Carvalho Chehab 		return -EIO;
11499a0bf528SMauro Carvalho Chehab 	tmp &= 0x7f;
11509a0bf528SMauro Carvalho Chehab 	while (counter++ < 5) {
11519a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11529a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11539a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11549a0bf528SMauro Carvalho Chehab 
11559a0bf528SMauro Carvalho Chehab 		tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR);
11569a0bf528SMauro Carvalho Chehab 		if (tmp2 < 0)
11579a0bf528SMauro Carvalho Chehab 			return -EIO;
11589a0bf528SMauro Carvalho Chehab 		tmp2 &= 0x7f;
11599a0bf528SMauro Carvalho Chehab 		if ((tmp2 < tmp) || (tmp2 == 0))
11609a0bf528SMauro Carvalho Chehab 			break;
11619a0bf528SMauro Carvalho Chehab 	}
11629a0bf528SMauro Carvalho Chehab 
11639a0bf528SMauro Carvalho Chehab 	if (tmp != 0x7f)
11649a0bf528SMauro Carvalho Chehab 		*ucblocks = tmp;
11659a0bf528SMauro Carvalho Chehab 	else
11669a0bf528SMauro Carvalho Chehab 		*ucblocks = 0xffffffff;
11679a0bf528SMauro Carvalho Chehab 
11689a0bf528SMauro Carvalho Chehab 	dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
11699a0bf528SMauro Carvalho Chehab 	return 0;
11709a0bf528SMauro Carvalho Chehab }
11719a0bf528SMauro Carvalho Chehab 
11729a0bf528SMauro Carvalho Chehab static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
11739a0bf528SMauro Carvalho Chehab {
11749a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
11759a0bf528SMauro Carvalho Chehab 	int tmp;
11769a0bf528SMauro Carvalho Chehab 
11779a0bf528SMauro Carvalho Chehab 	dprintk("%s\n", __func__);
11789a0bf528SMauro Carvalho Chehab 
11799a0bf528SMauro Carvalho Chehab 	// read it in
11809a0bf528SMauro Carvalho Chehab 	tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
11819a0bf528SMauro Carvalho Chehab 	if (tmp < 0)
11829a0bf528SMauro Carvalho Chehab 		return -EIO;
11839a0bf528SMauro Carvalho Chehab 	*ber = tmp << 1;
11849a0bf528SMauro Carvalho Chehab 	tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
11859a0bf528SMauro Carvalho Chehab 	if (tmp < 0)
11869a0bf528SMauro Carvalho Chehab 		return -EIO;
11879a0bf528SMauro Carvalho Chehab 	*ber |= (tmp << 9);
11889a0bf528SMauro Carvalho Chehab 	// The address 0x20 should be read to cope with a TDA10046 bug
11899a0bf528SMauro Carvalho Chehab 	tda1004x_read_byte(state, TDA1004X_CBER_RESET);
11909a0bf528SMauro Carvalho Chehab 
11919a0bf528SMauro Carvalho Chehab 	dprintk("%s: ber=0x%x\n", __func__, *ber);
11929a0bf528SMauro Carvalho Chehab 	return 0;
11939a0bf528SMauro Carvalho Chehab }
11949a0bf528SMauro Carvalho Chehab 
11959a0bf528SMauro Carvalho Chehab static int tda1004x_sleep(struct dvb_frontend* fe)
11969a0bf528SMauro Carvalho Chehab {
11979a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
11989a0bf528SMauro Carvalho Chehab 	int gpio_conf;
11999a0bf528SMauro Carvalho Chehab 
12009a0bf528SMauro Carvalho Chehab 	switch (state->demod_type) {
12019a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10045:
12029a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
12039a0bf528SMauro Carvalho Chehab 		break;
12049a0bf528SMauro Carvalho Chehab 
12059a0bf528SMauro Carvalho Chehab 	case TDA1004X_DEMOD_TDA10046:
12069a0bf528SMauro Carvalho Chehab 		/* set outputs to tristate */
12079a0bf528SMauro Carvalho Chehab 		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
12089a0bf528SMauro Carvalho Chehab 		/* invert GPIO 1 and 3 if desired*/
12099a0bf528SMauro Carvalho Chehab 		gpio_conf = state->config->gpio_config;
12109a0bf528SMauro Carvalho Chehab 		if (gpio_conf >= TDA10046_GP00_I)
12119a0bf528SMauro Carvalho Chehab 			tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
12129a0bf528SMauro Carvalho Chehab 							(gpio_conf & 0x0f) ^ 0x0a);
12139a0bf528SMauro Carvalho Chehab 
12149a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0);
12159a0bf528SMauro Carvalho Chehab 		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
12169a0bf528SMauro Carvalho Chehab 		break;
12179a0bf528SMauro Carvalho Chehab 	}
12189a0bf528SMauro Carvalho Chehab 
12199a0bf528SMauro Carvalho Chehab 	return 0;
12209a0bf528SMauro Carvalho Chehab }
12219a0bf528SMauro Carvalho Chehab 
12229a0bf528SMauro Carvalho Chehab static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
12239a0bf528SMauro Carvalho Chehab {
12249a0bf528SMauro Carvalho Chehab 	struct tda1004x_state* state = fe->demodulator_priv;
12259a0bf528SMauro Carvalho Chehab 
12269a0bf528SMauro Carvalho Chehab 	if (enable) {
12279a0bf528SMauro Carvalho Chehab 		return tda1004x_enable_tuner_i2c(state);
12289a0bf528SMauro Carvalho Chehab 	} else {
12299a0bf528SMauro Carvalho Chehab 		return tda1004x_disable_tuner_i2c(state);
12309a0bf528SMauro Carvalho Chehab 	}
12319a0bf528SMauro Carvalho Chehab }
12329a0bf528SMauro Carvalho Chehab 
12339a0bf528SMauro Carvalho Chehab static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
12349a0bf528SMauro Carvalho Chehab {
12359a0bf528SMauro Carvalho Chehab 	fesettings->min_delay_ms = 800;
12369a0bf528SMauro Carvalho Chehab 	/* Drift compensation makes no sense for DVB-T */
12379a0bf528SMauro Carvalho Chehab 	fesettings->step_size = 0;
12389a0bf528SMauro Carvalho Chehab 	fesettings->max_drift = 0;
12399a0bf528SMauro Carvalho Chehab 	return 0;
12409a0bf528SMauro Carvalho Chehab }
12419a0bf528SMauro Carvalho Chehab 
12429a0bf528SMauro Carvalho Chehab static void tda1004x_release(struct dvb_frontend* fe)
12439a0bf528SMauro Carvalho Chehab {
12449a0bf528SMauro Carvalho Chehab 	struct tda1004x_state *state = fe->demodulator_priv;
12459a0bf528SMauro Carvalho Chehab 	kfree(state);
12469a0bf528SMauro Carvalho Chehab }
12479a0bf528SMauro Carvalho Chehab 
1248bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10045_ops = {
12499a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
12509a0bf528SMauro Carvalho Chehab 	.info = {
12519a0bf528SMauro Carvalho Chehab 		.name = "Philips TDA10045H DVB-T",
12529a0bf528SMauro Carvalho Chehab 		.frequency_min = 51000000,
12539a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
12549a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 166667,
12559a0bf528SMauro Carvalho Chehab 		.caps =
12569a0bf528SMauro Carvalho Chehab 		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
12579a0bf528SMauro Carvalho Chehab 		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
12589a0bf528SMauro Carvalho Chehab 		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
12599a0bf528SMauro Carvalho Chehab 		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
12609a0bf528SMauro Carvalho Chehab 	},
12619a0bf528SMauro Carvalho Chehab 
12629a0bf528SMauro Carvalho Chehab 	.release = tda1004x_release,
12639a0bf528SMauro Carvalho Chehab 
12649a0bf528SMauro Carvalho Chehab 	.init = tda10045_init,
12659a0bf528SMauro Carvalho Chehab 	.sleep = tda1004x_sleep,
12669a0bf528SMauro Carvalho Chehab 	.write = tda1004x_write,
12679a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
12689a0bf528SMauro Carvalho Chehab 
12699a0bf528SMauro Carvalho Chehab 	.set_frontend = tda1004x_set_fe,
12709a0bf528SMauro Carvalho Chehab 	.get_frontend = tda1004x_get_fe,
12719a0bf528SMauro Carvalho Chehab 	.get_tune_settings = tda1004x_get_tune_settings,
12729a0bf528SMauro Carvalho Chehab 
12739a0bf528SMauro Carvalho Chehab 	.read_status = tda1004x_read_status,
12749a0bf528SMauro Carvalho Chehab 	.read_ber = tda1004x_read_ber,
12759a0bf528SMauro Carvalho Chehab 	.read_signal_strength = tda1004x_read_signal_strength,
12769a0bf528SMauro Carvalho Chehab 	.read_snr = tda1004x_read_snr,
12779a0bf528SMauro Carvalho Chehab 	.read_ucblocks = tda1004x_read_ucblocks,
12789a0bf528SMauro Carvalho Chehab };
12799a0bf528SMauro Carvalho Chehab 
12809a0bf528SMauro Carvalho Chehab struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
12819a0bf528SMauro Carvalho Chehab 				     struct i2c_adapter* i2c)
12829a0bf528SMauro Carvalho Chehab {
12839a0bf528SMauro Carvalho Chehab 	struct tda1004x_state *state;
12849a0bf528SMauro Carvalho Chehab 	int id;
12859a0bf528SMauro Carvalho Chehab 
12869a0bf528SMauro Carvalho Chehab 	/* allocate memory for the internal state */
12879a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
12889a0bf528SMauro Carvalho Chehab 	if (!state) {
12899a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "Can't allocate memory for tda10045 state\n");
12909a0bf528SMauro Carvalho Chehab 		return NULL;
12919a0bf528SMauro Carvalho Chehab 	}
12929a0bf528SMauro Carvalho Chehab 
12939a0bf528SMauro Carvalho Chehab 	/* setup the state */
12949a0bf528SMauro Carvalho Chehab 	state->config = config;
12959a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
12969a0bf528SMauro Carvalho Chehab 	state->demod_type = TDA1004X_DEMOD_TDA10045;
12979a0bf528SMauro Carvalho Chehab 
12989a0bf528SMauro Carvalho Chehab 	/* check if the demod is there */
12999a0bf528SMauro Carvalho Chehab 	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
13009a0bf528SMauro Carvalho Chehab 	if (id < 0) {
13019a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
13029a0bf528SMauro Carvalho Chehab 		kfree(state);
13039a0bf528SMauro Carvalho Chehab 		return NULL;
13049a0bf528SMauro Carvalho Chehab 	}
13059a0bf528SMauro Carvalho Chehab 
13069a0bf528SMauro Carvalho Chehab 	if (id != 0x25) {
13079a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
13089a0bf528SMauro Carvalho Chehab 		kfree(state);
13099a0bf528SMauro Carvalho Chehab 		return NULL;
13109a0bf528SMauro Carvalho Chehab 	}
13119a0bf528SMauro Carvalho Chehab 
13129a0bf528SMauro Carvalho Chehab 	/* create dvb_frontend */
13139a0bf528SMauro Carvalho Chehab 	memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
13149a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
13159a0bf528SMauro Carvalho Chehab 	return &state->frontend;
13169a0bf528SMauro Carvalho Chehab }
13179a0bf528SMauro Carvalho Chehab 
1318bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10046_ops = {
13199a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
13209a0bf528SMauro Carvalho Chehab 	.info = {
13219a0bf528SMauro Carvalho Chehab 		.name = "Philips TDA10046H DVB-T",
13229a0bf528SMauro Carvalho Chehab 		.frequency_min = 51000000,
13239a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
13249a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 166667,
13259a0bf528SMauro Carvalho Chehab 		.caps =
13269a0bf528SMauro Carvalho Chehab 		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
13279a0bf528SMauro Carvalho Chehab 		    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
13289a0bf528SMauro Carvalho Chehab 		    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
13299a0bf528SMauro Carvalho Chehab 		    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
13309a0bf528SMauro Carvalho Chehab 	},
13319a0bf528SMauro Carvalho Chehab 
13329a0bf528SMauro Carvalho Chehab 	.release = tda1004x_release,
13339a0bf528SMauro Carvalho Chehab 
13349a0bf528SMauro Carvalho Chehab 	.init = tda10046_init,
13359a0bf528SMauro Carvalho Chehab 	.sleep = tda1004x_sleep,
13369a0bf528SMauro Carvalho Chehab 	.write = tda1004x_write,
13379a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
13389a0bf528SMauro Carvalho Chehab 
13399a0bf528SMauro Carvalho Chehab 	.set_frontend = tda1004x_set_fe,
13409a0bf528SMauro Carvalho Chehab 	.get_frontend = tda1004x_get_fe,
13419a0bf528SMauro Carvalho Chehab 	.get_tune_settings = tda1004x_get_tune_settings,
13429a0bf528SMauro Carvalho Chehab 
13439a0bf528SMauro Carvalho Chehab 	.read_status = tda1004x_read_status,
13449a0bf528SMauro Carvalho Chehab 	.read_ber = tda1004x_read_ber,
13459a0bf528SMauro Carvalho Chehab 	.read_signal_strength = tda1004x_read_signal_strength,
13469a0bf528SMauro Carvalho Chehab 	.read_snr = tda1004x_read_snr,
13479a0bf528SMauro Carvalho Chehab 	.read_ucblocks = tda1004x_read_ucblocks,
13489a0bf528SMauro Carvalho Chehab };
13499a0bf528SMauro Carvalho Chehab 
13509a0bf528SMauro Carvalho Chehab struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
13519a0bf528SMauro Carvalho Chehab 				     struct i2c_adapter* i2c)
13529a0bf528SMauro Carvalho Chehab {
13539a0bf528SMauro Carvalho Chehab 	struct tda1004x_state *state;
13549a0bf528SMauro Carvalho Chehab 	int id;
13559a0bf528SMauro Carvalho Chehab 
13569a0bf528SMauro Carvalho Chehab 	/* allocate memory for the internal state */
13579a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
13589a0bf528SMauro Carvalho Chehab 	if (!state) {
13599a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "Can't allocate memory for tda10046 state\n");
13609a0bf528SMauro Carvalho Chehab 		return NULL;
13619a0bf528SMauro Carvalho Chehab 	}
13629a0bf528SMauro Carvalho Chehab 
13639a0bf528SMauro Carvalho Chehab 	/* setup the state */
13649a0bf528SMauro Carvalho Chehab 	state->config = config;
13659a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
13669a0bf528SMauro Carvalho Chehab 	state->demod_type = TDA1004X_DEMOD_TDA10046;
13679a0bf528SMauro Carvalho Chehab 
13689a0bf528SMauro Carvalho Chehab 	/* check if the demod is there */
13699a0bf528SMauro Carvalho Chehab 	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
13709a0bf528SMauro Carvalho Chehab 	if (id < 0) {
13719a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
13729a0bf528SMauro Carvalho Chehab 		kfree(state);
13739a0bf528SMauro Carvalho Chehab 		return NULL;
13749a0bf528SMauro Carvalho Chehab 	}
13759a0bf528SMauro Carvalho Chehab 	if (id != 0x46) {
13769a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
13779a0bf528SMauro Carvalho Chehab 		kfree(state);
13789a0bf528SMauro Carvalho Chehab 		return NULL;
13799a0bf528SMauro Carvalho Chehab 	}
13809a0bf528SMauro Carvalho Chehab 
13819a0bf528SMauro Carvalho Chehab 	/* create dvb_frontend */
13829a0bf528SMauro Carvalho Chehab 	memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
13839a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
13849a0bf528SMauro Carvalho Chehab 	return &state->frontend;
13859a0bf528SMauro Carvalho Chehab }
13869a0bf528SMauro Carvalho Chehab 
13879a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
13889a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
13899a0bf528SMauro Carvalho Chehab 
13909a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");
13919a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
13929a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
13939a0bf528SMauro Carvalho Chehab 
13949a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(tda10045_attach);
13959a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(tda10046_attach);
1396