xref: /linux/drivers/media/dvb-frontends/tda10048.c (revision fada1935590f66dc6784981e0d557ca09013c847)
19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab     NXP TDA10048HN DVB OFDM demodulator driver
39a0bf528SMauro Carvalho Chehab 
49a0bf528SMauro Carvalho Chehab     Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
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     GNU General Public License for more details.
159a0bf528SMauro Carvalho Chehab 
169a0bf528SMauro Carvalho Chehab     You should have received a copy of the GNU General Public License
179a0bf528SMauro Carvalho Chehab     along with this program; if not, write to the Free Software
189a0bf528SMauro Carvalho Chehab     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
199a0bf528SMauro Carvalho Chehab 
209a0bf528SMauro Carvalho Chehab */
219a0bf528SMauro Carvalho Chehab 
229a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
239a0bf528SMauro Carvalho Chehab #include <linux/init.h>
249a0bf528SMauro Carvalho Chehab #include <linux/module.h>
259a0bf528SMauro Carvalho Chehab #include <linux/string.h>
269a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
279a0bf528SMauro Carvalho Chehab #include <linux/delay.h>
289a0bf528SMauro Carvalho Chehab #include <linux/math64.h>
299a0bf528SMauro Carvalho Chehab #include <asm/div64.h>
30*fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
31*fada1935SMauro Carvalho Chehab #include <media/dvb_math.h>
329a0bf528SMauro Carvalho Chehab #include "tda10048.h"
339a0bf528SMauro Carvalho Chehab 
349a0bf528SMauro Carvalho Chehab #define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
359a0bf528SMauro Carvalho Chehab #define TDA10048_DEFAULT_FIRMWARE_SIZE 24878
369a0bf528SMauro Carvalho Chehab 
379a0bf528SMauro Carvalho Chehab /* Register name definitions */
389a0bf528SMauro Carvalho Chehab #define TDA10048_IDENTITY          0x00
399a0bf528SMauro Carvalho Chehab #define TDA10048_VERSION           0x01
409a0bf528SMauro Carvalho Chehab #define TDA10048_DSP_CODE_CPT      0x0C
419a0bf528SMauro Carvalho Chehab #define TDA10048_DSP_CODE_IN       0x0E
429a0bf528SMauro Carvalho Chehab #define TDA10048_IN_CONF1          0x10
439a0bf528SMauro Carvalho Chehab #define TDA10048_IN_CONF2          0x11
449a0bf528SMauro Carvalho Chehab #define TDA10048_IN_CONF3          0x12
459a0bf528SMauro Carvalho Chehab #define TDA10048_OUT_CONF1         0x14
469a0bf528SMauro Carvalho Chehab #define TDA10048_OUT_CONF2         0x15
479a0bf528SMauro Carvalho Chehab #define TDA10048_OUT_CONF3         0x16
489a0bf528SMauro Carvalho Chehab #define TDA10048_AUTO              0x18
499a0bf528SMauro Carvalho Chehab #define TDA10048_SYNC_STATUS       0x1A
509a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_C4_1         0x1E
519a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_C4_2         0x1F
529a0bf528SMauro Carvalho Chehab #define TDA10048_CODE_IN_RAM       0x20
539a0bf528SMauro Carvalho Chehab #define TDA10048_CHANNEL_INFO1_R   0x22
549a0bf528SMauro Carvalho Chehab #define TDA10048_CHANNEL_INFO2_R   0x23
559a0bf528SMauro Carvalho Chehab #define TDA10048_CHANNEL_INFO1     0x24
569a0bf528SMauro Carvalho Chehab #define TDA10048_CHANNEL_INFO2     0x25
579a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_ERROR_R      0x26
589a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_ERROR        0x27
599a0bf528SMauro Carvalho Chehab #define TDA10048_FREQ_ERROR_LSB_R  0x28
609a0bf528SMauro Carvalho Chehab #define TDA10048_FREQ_ERROR_MSB_R  0x29
619a0bf528SMauro Carvalho Chehab #define TDA10048_FREQ_ERROR_LSB    0x2A
629a0bf528SMauro Carvalho Chehab #define TDA10048_FREQ_ERROR_MSB    0x2B
639a0bf528SMauro Carvalho Chehab #define TDA10048_IT_SEL            0x30
649a0bf528SMauro Carvalho Chehab #define TDA10048_IT_STAT           0x32
659a0bf528SMauro Carvalho Chehab #define TDA10048_DSP_AD_LSB        0x3C
669a0bf528SMauro Carvalho Chehab #define TDA10048_DSP_AD_MSB        0x3D
679a0bf528SMauro Carvalho Chehab #define TDA10048_DSP_REG_LSB       0x3E
689a0bf528SMauro Carvalho Chehab #define TDA10048_DSP_REG_MSB       0x3F
699a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_TRISTATE1    0x44
709a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_TRISTATE2    0x45
719a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_POLARITY     0x46
729a0bf528SMauro Carvalho Chehab #define TDA10048_GPIO_SP_DS0       0x48
739a0bf528SMauro Carvalho Chehab #define TDA10048_GPIO_SP_DS1       0x49
749a0bf528SMauro Carvalho Chehab #define TDA10048_GPIO_SP_DS2       0x4A
759a0bf528SMauro Carvalho Chehab #define TDA10048_GPIO_SP_DS3       0x4B
769a0bf528SMauro Carvalho Chehab #define TDA10048_GPIO_OUT_SEL      0x4C
779a0bf528SMauro Carvalho Chehab #define TDA10048_GPIO_SELECT       0x4D
789a0bf528SMauro Carvalho Chehab #define TDA10048_IC_MODE           0x4E
799a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_XO           0x50
809a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_PLL1         0x51
819a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_PLL2         0x52
829a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_PLL3         0x53
839a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_ADC          0x54
849a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_ADC_2        0x55
859a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_C1_1         0x60
869a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_C1_3         0x62
879a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_CONF          0x70
889a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_THRESHOLD_LSB 0x72
899a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_THRESHOLD_MSB 0x73
909a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_RENORM        0x74
919a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_GAINS         0x76
929a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_TUN_MIN       0x78
939a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_TUN_MAX       0x79
949a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_IF_MIN        0x7A
959a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_IF_MAX        0x7B
969a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_TUN_LEVEL     0x7E
979a0bf528SMauro Carvalho Chehab #define TDA10048_AGC_IF_LEVEL      0x7F
989a0bf528SMauro Carvalho Chehab #define TDA10048_DIG_AGC_LEVEL     0x81
999a0bf528SMauro Carvalho Chehab #define TDA10048_FREQ_PHY2_LSB     0x86
1009a0bf528SMauro Carvalho Chehab #define TDA10048_FREQ_PHY2_MSB     0x87
1019a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_INVWREF_LSB  0x88
1029a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_INVWREF_MSB  0x89
1039a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_WREF_LSB     0x8A
1049a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_WREF_MID1    0x8B
1059a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_WREF_MID2    0x8C
1069a0bf528SMauro Carvalho Chehab #define TDA10048_TIME_WREF_MSB     0x8D
1079a0bf528SMauro Carvalho Chehab #define TDA10048_NP_OUT            0xA2
1089a0bf528SMauro Carvalho Chehab #define TDA10048_CELL_ID_LSB       0xA4
1099a0bf528SMauro Carvalho Chehab #define TDA10048_CELL_ID_MSB       0xA5
1109a0bf528SMauro Carvalho Chehab #define TDA10048_EXTTPS_ODD        0xAA
1119a0bf528SMauro Carvalho Chehab #define TDA10048_EXTTPS_EVEN       0xAB
1129a0bf528SMauro Carvalho Chehab #define TDA10048_TPS_LENGTH        0xAC
1139a0bf528SMauro Carvalho Chehab #define TDA10048_FREE_REG_1        0xB2
1149a0bf528SMauro Carvalho Chehab #define TDA10048_FREE_REG_2        0xB3
1159a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_C3_1         0xC0
1169a0bf528SMauro Carvalho Chehab #define TDA10048_CVBER_CTRL        0xC2
1179a0bf528SMauro Carvalho Chehab #define TDA10048_CBER_NMAX_LSB     0xC4
1189a0bf528SMauro Carvalho Chehab #define TDA10048_CBER_NMAX_MSB     0xC5
1199a0bf528SMauro Carvalho Chehab #define TDA10048_CBER_LSB          0xC6
1209a0bf528SMauro Carvalho Chehab #define TDA10048_CBER_MSB          0xC7
1219a0bf528SMauro Carvalho Chehab #define TDA10048_VBER_LSB          0xC8
1229a0bf528SMauro Carvalho Chehab #define TDA10048_VBER_MID          0xC9
1239a0bf528SMauro Carvalho Chehab #define TDA10048_VBER_MSB          0xCA
1249a0bf528SMauro Carvalho Chehab #define TDA10048_CVBER_LUT         0xCC
1259a0bf528SMauro Carvalho Chehab #define TDA10048_UNCOR_CTRL        0xCD
1269a0bf528SMauro Carvalho Chehab #define TDA10048_UNCOR_CPT_LSB     0xCE
1279a0bf528SMauro Carvalho Chehab #define TDA10048_UNCOR_CPT_MSB     0xCF
1289a0bf528SMauro Carvalho Chehab #define TDA10048_SOFT_IT_C3        0xD6
1299a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_TS2          0xE0
1309a0bf528SMauro Carvalho Chehab #define TDA10048_CONF_TS1          0xE1
1319a0bf528SMauro Carvalho Chehab 
1329a0bf528SMauro Carvalho Chehab static unsigned int debug;
1339a0bf528SMauro Carvalho Chehab 
1349a0bf528SMauro Carvalho Chehab #define dprintk(level, fmt, arg...)\
1359a0bf528SMauro Carvalho Chehab 	do { if (debug >= level)\
1369a0bf528SMauro Carvalho Chehab 		printk(KERN_DEBUG "tda10048: " fmt, ## arg);\
1379a0bf528SMauro Carvalho Chehab 	} while (0)
1389a0bf528SMauro Carvalho Chehab 
1399a0bf528SMauro Carvalho Chehab struct tda10048_state {
1409a0bf528SMauro Carvalho Chehab 
1419a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c;
1429a0bf528SMauro Carvalho Chehab 
1439a0bf528SMauro Carvalho Chehab 	/* We'll cache and update the attach config settings */
1449a0bf528SMauro Carvalho Chehab 	struct tda10048_config config;
1459a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
1469a0bf528SMauro Carvalho Chehab 
1479a0bf528SMauro Carvalho Chehab 	int fwloaded;
1489a0bf528SMauro Carvalho Chehab 
1499a0bf528SMauro Carvalho Chehab 	u32 freq_if_hz;
1509a0bf528SMauro Carvalho Chehab 	u32 xtal_hz;
1519a0bf528SMauro Carvalho Chehab 	u32 pll_mfactor;
1529a0bf528SMauro Carvalho Chehab 	u32 pll_nfactor;
1539a0bf528SMauro Carvalho Chehab 	u32 pll_pfactor;
1549a0bf528SMauro Carvalho Chehab 	u32 sample_freq;
1559a0bf528SMauro Carvalho Chehab 
1569a0bf528SMauro Carvalho Chehab 	u32 bandwidth;
1579a0bf528SMauro Carvalho Chehab };
1589a0bf528SMauro Carvalho Chehab 
1599a0bf528SMauro Carvalho Chehab static struct init_tab {
1609a0bf528SMauro Carvalho Chehab 	u8	reg;
1619a0bf528SMauro Carvalho Chehab 	u16	data;
1629a0bf528SMauro Carvalho Chehab } init_tab[] = {
1639a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_PLL1, 0x08 },
1649a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_ADC_2, 0x00 },
1659a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_C4_1, 0x00 },
1669a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_PLL1, 0x0f },
1679a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_PLL2, 0x0a },
1689a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_PLL3, 0x43 },
1699a0bf528SMauro Carvalho Chehab 	{ TDA10048_FREQ_PHY2_LSB, 0x02 },
1709a0bf528SMauro Carvalho Chehab 	{ TDA10048_FREQ_PHY2_MSB, 0x0a },
1719a0bf528SMauro Carvalho Chehab 	{ TDA10048_TIME_WREF_LSB, 0xbd },
1729a0bf528SMauro Carvalho Chehab 	{ TDA10048_TIME_WREF_MID1, 0xe4 },
1739a0bf528SMauro Carvalho Chehab 	{ TDA10048_TIME_WREF_MID2, 0xa8 },
1749a0bf528SMauro Carvalho Chehab 	{ TDA10048_TIME_WREF_MSB, 0x02 },
1759a0bf528SMauro Carvalho Chehab 	{ TDA10048_TIME_INVWREF_LSB, 0x04 },
1769a0bf528SMauro Carvalho Chehab 	{ TDA10048_TIME_INVWREF_MSB, 0x06 },
1779a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_C4_1, 0x00 },
1789a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_C1_1, 0xa8 },
1799a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_CONF, 0x16 },
1809a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_C1_3, 0x0b },
1819a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_TUN_MIN, 0x00 },
1829a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_TUN_MAX, 0xff },
1839a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_IF_MIN, 0x00 },
1849a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_IF_MAX, 0xff },
1859a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },
1869a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },
1879a0bf528SMauro Carvalho Chehab 	{ TDA10048_CVBER_CTRL, 0x38 },
1889a0bf528SMauro Carvalho Chehab 	{ TDA10048_AGC_GAINS, 0x12 },
1899a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_XO, 0x00 },
1909a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_TS1, 0x07 },
1919a0bf528SMauro Carvalho Chehab 	{ TDA10048_IC_MODE, 0x00 },
1929a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_TS2, 0xc0 },
1939a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_TRISTATE1, 0x21 },
1949a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_TRISTATE2, 0x00 },
1959a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_POLARITY, 0x00 },
1969a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_C4_2, 0x04 },
1979a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_ADC, 0x60 },
1989a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_ADC_2, 0x10 },
1999a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_ADC, 0x60 },
2009a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_ADC_2, 0x00 },
2019a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_C1_1, 0xa8 },
2029a0bf528SMauro Carvalho Chehab 	{ TDA10048_UNCOR_CTRL, 0x00 },
2039a0bf528SMauro Carvalho Chehab 	{ TDA10048_CONF_C4_2, 0x04 },
2049a0bf528SMauro Carvalho Chehab };
2059a0bf528SMauro Carvalho Chehab 
2069a0bf528SMauro Carvalho Chehab static struct pll_tab {
2079a0bf528SMauro Carvalho Chehab 	u32	clk_freq_khz;
2089a0bf528SMauro Carvalho Chehab 	u32	if_freq_khz;
2099a0bf528SMauro Carvalho Chehab } pll_tab[] = {
2109a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_4000,  TDA10048_IF_36130 },
2119a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_3300 },
2129a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_3500 },
2139a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_3800 },
2149a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_4000 },
2159a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_4300 },
2169a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_4500 },
2179a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_5000 },
2189a0bf528SMauro Carvalho Chehab 	{ TDA10048_CLK_16000, TDA10048_IF_36130 },
2199a0bf528SMauro Carvalho Chehab };
2209a0bf528SMauro Carvalho Chehab 
2219a0bf528SMauro Carvalho Chehab static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
2229a0bf528SMauro Carvalho Chehab {
2239a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
2249a0bf528SMauro Carvalho Chehab 	int ret;
2259a0bf528SMauro Carvalho Chehab 	u8 buf[] = { reg, data };
2269a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {
2279a0bf528SMauro Carvalho Chehab 		.addr = config->demod_address,
2289a0bf528SMauro Carvalho Chehab 		.flags = 0, .buf = buf, .len = 2 };
2299a0bf528SMauro Carvalho Chehab 
2309a0bf528SMauro Carvalho Chehab 	dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
2319a0bf528SMauro Carvalho Chehab 
2329a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, &msg, 1);
2339a0bf528SMauro Carvalho Chehab 
2349a0bf528SMauro Carvalho Chehab 	if (ret != 1)
2359a0bf528SMauro Carvalho Chehab 		printk("%s: writereg error (ret == %i)\n", __func__, ret);
2369a0bf528SMauro Carvalho Chehab 
2379a0bf528SMauro Carvalho Chehab 	return (ret != 1) ? -1 : 0;
2389a0bf528SMauro Carvalho Chehab }
2399a0bf528SMauro Carvalho Chehab 
2409a0bf528SMauro Carvalho Chehab static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
2419a0bf528SMauro Carvalho Chehab {
2429a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
2439a0bf528SMauro Carvalho Chehab 	int ret;
2449a0bf528SMauro Carvalho Chehab 	u8 b0[] = { reg };
2459a0bf528SMauro Carvalho Chehab 	u8 b1[] = { 0 };
2469a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
2479a0bf528SMauro Carvalho Chehab 		{ .addr = config->demod_address,
2489a0bf528SMauro Carvalho Chehab 			.flags = 0, .buf = b0, .len = 1 },
2499a0bf528SMauro Carvalho Chehab 		{ .addr = config->demod_address,
2509a0bf528SMauro Carvalho Chehab 			.flags = I2C_M_RD, .buf = b1, .len = 1 } };
2519a0bf528SMauro Carvalho Chehab 
2529a0bf528SMauro Carvalho Chehab 	dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
2539a0bf528SMauro Carvalho Chehab 
2549a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, msg, 2);
2559a0bf528SMauro Carvalho Chehab 
2569a0bf528SMauro Carvalho Chehab 	if (ret != 2)
2579a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
2589a0bf528SMauro Carvalho Chehab 			__func__, ret);
2599a0bf528SMauro Carvalho Chehab 
2609a0bf528SMauro Carvalho Chehab 	return b1[0];
2619a0bf528SMauro Carvalho Chehab }
2629a0bf528SMauro Carvalho Chehab 
2639a0bf528SMauro Carvalho Chehab static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
2649a0bf528SMauro Carvalho Chehab 				 const u8 *data, u16 len)
2659a0bf528SMauro Carvalho Chehab {
2669a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
2679a0bf528SMauro Carvalho Chehab 	int ret = -EREMOTEIO;
2689a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg;
2699a0bf528SMauro Carvalho Chehab 	u8 *buf;
2709a0bf528SMauro Carvalho Chehab 
2719a0bf528SMauro Carvalho Chehab 	dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len);
2729a0bf528SMauro Carvalho Chehab 
2739a0bf528SMauro Carvalho Chehab 	buf = kmalloc(len + 1, GFP_KERNEL);
2749a0bf528SMauro Carvalho Chehab 	if (buf == NULL) {
2759a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
2769a0bf528SMauro Carvalho Chehab 		goto error;
2779a0bf528SMauro Carvalho Chehab 	}
2789a0bf528SMauro Carvalho Chehab 
2799a0bf528SMauro Carvalho Chehab 	*buf = reg;
2809a0bf528SMauro Carvalho Chehab 	memcpy(buf + 1, data, len);
2819a0bf528SMauro Carvalho Chehab 
2829a0bf528SMauro Carvalho Chehab 	msg.addr = config->demod_address;
2839a0bf528SMauro Carvalho Chehab 	msg.flags = 0;
2849a0bf528SMauro Carvalho Chehab 	msg.buf = buf;
2859a0bf528SMauro Carvalho Chehab 	msg.len = len + 1;
2869a0bf528SMauro Carvalho Chehab 
2879a0bf528SMauro Carvalho Chehab 	dprintk(2, "%s():  write len = %d\n",
2889a0bf528SMauro Carvalho Chehab 		__func__, msg.len);
2899a0bf528SMauro Carvalho Chehab 
2909a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, &msg, 1);
2919a0bf528SMauro Carvalho Chehab 	if (ret != 1) {
2929a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s(): writereg error err %i\n",
2939a0bf528SMauro Carvalho Chehab 			 __func__, ret);
2949a0bf528SMauro Carvalho Chehab 		ret = -EREMOTEIO;
2959a0bf528SMauro Carvalho Chehab 	}
2969a0bf528SMauro Carvalho Chehab 
2979a0bf528SMauro Carvalho Chehab error:
2989a0bf528SMauro Carvalho Chehab 	kfree(buf);
2999a0bf528SMauro Carvalho Chehab 
3009a0bf528SMauro Carvalho Chehab 	return ret;
3019a0bf528SMauro Carvalho Chehab }
3029a0bf528SMauro Carvalho Chehab 
3039a0bf528SMauro Carvalho Chehab static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz,
3049a0bf528SMauro Carvalho Chehab 			     u32 if_hz)
3059a0bf528SMauro Carvalho Chehab {
3069a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
3079a0bf528SMauro Carvalho Chehab 	u64 t;
3089a0bf528SMauro Carvalho Chehab 
3099a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
3109a0bf528SMauro Carvalho Chehab 
3119a0bf528SMauro Carvalho Chehab 	if (sample_freq_hz == 0)
3129a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3139a0bf528SMauro Carvalho Chehab 
3149a0bf528SMauro Carvalho Chehab 	if (if_hz < (sample_freq_hz / 2)) {
3159a0bf528SMauro Carvalho Chehab 		/* PHY2 = (if2/fs) * 2^15 */
3169a0bf528SMauro Carvalho Chehab 		t = if_hz;
3179a0bf528SMauro Carvalho Chehab 		t *= 10;
3189a0bf528SMauro Carvalho Chehab 		t *= 32768;
3199a0bf528SMauro Carvalho Chehab 		do_div(t, sample_freq_hz);
3209a0bf528SMauro Carvalho Chehab 		t += 5;
3219a0bf528SMauro Carvalho Chehab 		do_div(t, 10);
3229a0bf528SMauro Carvalho Chehab 	} else {
3239a0bf528SMauro Carvalho Chehab 		/* PHY2 = ((IF1-fs)/fs) * 2^15 */
3249a0bf528SMauro Carvalho Chehab 		t = sample_freq_hz - if_hz;
3259a0bf528SMauro Carvalho Chehab 		t *= 10;
3269a0bf528SMauro Carvalho Chehab 		t *= 32768;
3279a0bf528SMauro Carvalho Chehab 		do_div(t, sample_freq_hz);
3289a0bf528SMauro Carvalho Chehab 		t += 5;
3299a0bf528SMauro Carvalho Chehab 		do_div(t, 10);
3309a0bf528SMauro Carvalho Chehab 		t = ~t + 1;
3319a0bf528SMauro Carvalho Chehab 	}
3329a0bf528SMauro Carvalho Chehab 
3339a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t);
3349a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8));
3359a0bf528SMauro Carvalho Chehab 
3369a0bf528SMauro Carvalho Chehab 	return 0;
3379a0bf528SMauro Carvalho Chehab }
3389a0bf528SMauro Carvalho Chehab 
3399a0bf528SMauro Carvalho Chehab static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
3409a0bf528SMauro Carvalho Chehab 			     u32 bw)
3419a0bf528SMauro Carvalho Chehab {
3429a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
3439a0bf528SMauro Carvalho Chehab 	u64 t, z;
3449a0bf528SMauro Carvalho Chehab 
3459a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
3469a0bf528SMauro Carvalho Chehab 
3479a0bf528SMauro Carvalho Chehab 	if (sample_freq_hz == 0)
3489a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3499a0bf528SMauro Carvalho Chehab 
3509a0bf528SMauro Carvalho Chehab 	/* WREF = (B / (7 * fs)) * 2^31 */
3519a0bf528SMauro Carvalho Chehab 	t = bw * 10;
3529a0bf528SMauro Carvalho Chehab 	/* avoid warning: this decimal constant is unsigned only in ISO C90 */
3539a0bf528SMauro Carvalho Chehab 	/* t *= 2147483648 on 32bit platforms */
3549a0bf528SMauro Carvalho Chehab 	t *= (2048 * 1024);
3559a0bf528SMauro Carvalho Chehab 	t *= 1024;
3569a0bf528SMauro Carvalho Chehab 	z = 7 * sample_freq_hz;
3579a0bf528SMauro Carvalho Chehab 	do_div(t, z);
3589a0bf528SMauro Carvalho Chehab 	t += 5;
3599a0bf528SMauro Carvalho Chehab 	do_div(t, 10);
3609a0bf528SMauro Carvalho Chehab 
3619a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t);
3629a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8));
3639a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16));
3649a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24));
3659a0bf528SMauro Carvalho Chehab 
3669a0bf528SMauro Carvalho Chehab 	return 0;
3679a0bf528SMauro Carvalho Chehab }
3689a0bf528SMauro Carvalho Chehab 
3699a0bf528SMauro Carvalho Chehab static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
3709a0bf528SMauro Carvalho Chehab 				u32 bw)
3719a0bf528SMauro Carvalho Chehab {
3729a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
3739a0bf528SMauro Carvalho Chehab 	u64 t;
3749a0bf528SMauro Carvalho Chehab 
3759a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
3769a0bf528SMauro Carvalho Chehab 
3779a0bf528SMauro Carvalho Chehab 	if (sample_freq_hz == 0)
3789a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3799a0bf528SMauro Carvalho Chehab 
3809a0bf528SMauro Carvalho Chehab 	/* INVWREF = ((7 * fs) / B) * 2^5 */
3819a0bf528SMauro Carvalho Chehab 	t = sample_freq_hz;
3829a0bf528SMauro Carvalho Chehab 	t *= 7;
3839a0bf528SMauro Carvalho Chehab 	t *= 32;
3849a0bf528SMauro Carvalho Chehab 	t *= 10;
3859a0bf528SMauro Carvalho Chehab 	do_div(t, bw);
3869a0bf528SMauro Carvalho Chehab 	t += 5;
3879a0bf528SMauro Carvalho Chehab 	do_div(t, 10);
3889a0bf528SMauro Carvalho Chehab 
3899a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t);
3909a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8));
3919a0bf528SMauro Carvalho Chehab 
3929a0bf528SMauro Carvalho Chehab 	return 0;
3939a0bf528SMauro Carvalho Chehab }
3949a0bf528SMauro Carvalho Chehab 
3959a0bf528SMauro Carvalho Chehab static int tda10048_set_bandwidth(struct dvb_frontend *fe,
3969a0bf528SMauro Carvalho Chehab 	u32 bw)
3979a0bf528SMauro Carvalho Chehab {
3989a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
3999a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s(bw=%d)\n", __func__, bw);
4009a0bf528SMauro Carvalho Chehab 
4019a0bf528SMauro Carvalho Chehab 	/* Bandwidth setting may need to be adjusted */
4029a0bf528SMauro Carvalho Chehab 	switch (bw) {
4039a0bf528SMauro Carvalho Chehab 	case 6000000:
4049a0bf528SMauro Carvalho Chehab 	case 7000000:
4059a0bf528SMauro Carvalho Chehab 	case 8000000:
4069a0bf528SMauro Carvalho Chehab 		tda10048_set_wref(fe, state->sample_freq, bw);
4079a0bf528SMauro Carvalho Chehab 		tda10048_set_invwref(fe, state->sample_freq, bw);
4089a0bf528SMauro Carvalho Chehab 		break;
4099a0bf528SMauro Carvalho Chehab 	default:
4109a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s() invalid bandwidth\n", __func__);
4119a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4129a0bf528SMauro Carvalho Chehab 	}
4139a0bf528SMauro Carvalho Chehab 
4149a0bf528SMauro Carvalho Chehab 	state->bandwidth = bw;
4159a0bf528SMauro Carvalho Chehab 
4169a0bf528SMauro Carvalho Chehab 	return 0;
4179a0bf528SMauro Carvalho Chehab }
4189a0bf528SMauro Carvalho Chehab 
4199a0bf528SMauro Carvalho Chehab static int tda10048_set_if(struct dvb_frontend *fe, u32 bw)
4209a0bf528SMauro Carvalho Chehab {
4219a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
4229a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
4239a0bf528SMauro Carvalho Chehab 	int i;
4249a0bf528SMauro Carvalho Chehab 	u32 if_freq_khz;
4259a0bf528SMauro Carvalho Chehab 
4269a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s(bw = %d)\n", __func__, bw);
4279a0bf528SMauro Carvalho Chehab 
4289a0bf528SMauro Carvalho Chehab 	/* based on target bandwidth and clk we calculate pll factors */
4299a0bf528SMauro Carvalho Chehab 	switch (bw) {
4309a0bf528SMauro Carvalho Chehab 	case 6000000:
4319a0bf528SMauro Carvalho Chehab 		if_freq_khz = config->dtv6_if_freq_khz;
4329a0bf528SMauro Carvalho Chehab 		break;
4339a0bf528SMauro Carvalho Chehab 	case 7000000:
4349a0bf528SMauro Carvalho Chehab 		if_freq_khz = config->dtv7_if_freq_khz;
4359a0bf528SMauro Carvalho Chehab 		break;
4369a0bf528SMauro Carvalho Chehab 	case 8000000:
4379a0bf528SMauro Carvalho Chehab 		if_freq_khz = config->dtv8_if_freq_khz;
4389a0bf528SMauro Carvalho Chehab 		break;
4399a0bf528SMauro Carvalho Chehab 	default:
4409a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s() no default\n", __func__);
4419a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4429a0bf528SMauro Carvalho Chehab 	}
4439a0bf528SMauro Carvalho Chehab 
4449a0bf528SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(pll_tab); i++) {
4459a0bf528SMauro Carvalho Chehab 		if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) &&
4469a0bf528SMauro Carvalho Chehab 			(pll_tab[i].if_freq_khz == if_freq_khz)) {
4479a0bf528SMauro Carvalho Chehab 
4489a0bf528SMauro Carvalho Chehab 			state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
4499a0bf528SMauro Carvalho Chehab 			state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
4509a0bf528SMauro Carvalho Chehab 			break;
4519a0bf528SMauro Carvalho Chehab 		}
4529a0bf528SMauro Carvalho Chehab 	}
4539a0bf528SMauro Carvalho Chehab 	if (i == ARRAY_SIZE(pll_tab)) {
4549a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s() Incorrect attach settings\n",
4559a0bf528SMauro Carvalho Chehab 			__func__);
4569a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4579a0bf528SMauro Carvalho Chehab 	}
4589a0bf528SMauro Carvalho Chehab 
4599a0bf528SMauro Carvalho Chehab 	dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz);
4609a0bf528SMauro Carvalho Chehab 	dprintk(1, "- xtal_hz = %d\n", state->xtal_hz);
4619a0bf528SMauro Carvalho Chehab 	dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor);
4629a0bf528SMauro Carvalho Chehab 	dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor);
4639a0bf528SMauro Carvalho Chehab 	dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
4649a0bf528SMauro Carvalho Chehab 
4659a0bf528SMauro Carvalho Chehab 	/* Calculate the sample frequency */
4669a0bf528SMauro Carvalho Chehab 	state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
4679a0bf528SMauro Carvalho Chehab 	state->sample_freq /= (state->pll_nfactor + 1);
4689a0bf528SMauro Carvalho Chehab 	state->sample_freq /= (state->pll_pfactor + 4);
4699a0bf528SMauro Carvalho Chehab 	dprintk(1, "- sample_freq = %d\n", state->sample_freq);
4709a0bf528SMauro Carvalho Chehab 
4719a0bf528SMauro Carvalho Chehab 	/* Update the I/F */
4729a0bf528SMauro Carvalho Chehab 	tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz);
4739a0bf528SMauro Carvalho Chehab 
4749a0bf528SMauro Carvalho Chehab 	return 0;
4759a0bf528SMauro Carvalho Chehab }
4769a0bf528SMauro Carvalho Chehab 
4779a0bf528SMauro Carvalho Chehab static int tda10048_firmware_upload(struct dvb_frontend *fe)
4789a0bf528SMauro Carvalho Chehab {
4799a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
4809a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
4819a0bf528SMauro Carvalho Chehab 	const struct firmware *fw;
4829a0bf528SMauro Carvalho Chehab 	int ret;
4839a0bf528SMauro Carvalho Chehab 	int pos = 0;
4849a0bf528SMauro Carvalho Chehab 	int cnt;
4859a0bf528SMauro Carvalho Chehab 	u8 wlen = config->fwbulkwritelen;
4869a0bf528SMauro Carvalho Chehab 
4879a0bf528SMauro Carvalho Chehab 	if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
4889a0bf528SMauro Carvalho Chehab 		wlen = TDA10048_BULKWRITE_200;
4899a0bf528SMauro Carvalho Chehab 
4909a0bf528SMauro Carvalho Chehab 	/* request the firmware, this will block and timeout */
4919a0bf528SMauro Carvalho Chehab 	printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n",
4929a0bf528SMauro Carvalho Chehab 		__func__,
4939a0bf528SMauro Carvalho Chehab 		TDA10048_DEFAULT_FIRMWARE);
4949a0bf528SMauro Carvalho Chehab 
4959a0bf528SMauro Carvalho Chehab 	ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
4969a0bf528SMauro Carvalho Chehab 		state->i2c->dev.parent);
4979a0bf528SMauro Carvalho Chehab 	if (ret) {
4989a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
4999a0bf528SMauro Carvalho Chehab 			__func__);
5009a0bf528SMauro Carvalho Chehab 		return -EIO;
5019a0bf528SMauro Carvalho Chehab 	} else {
5025b5e0928SAlexey Dobriyan 		printk(KERN_INFO "%s: firmware read %zu bytes.\n",
5039a0bf528SMauro Carvalho Chehab 			__func__,
5049a0bf528SMauro Carvalho Chehab 			fw->size);
5059a0bf528SMauro Carvalho Chehab 		ret = 0;
5069a0bf528SMauro Carvalho Chehab 	}
5079a0bf528SMauro Carvalho Chehab 
5089a0bf528SMauro Carvalho Chehab 	if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
5099a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
5109a0bf528SMauro Carvalho Chehab 		ret = -EIO;
5119a0bf528SMauro Carvalho Chehab 	} else {
5129a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "%s: firmware uploading\n", __func__);
5139a0bf528SMauro Carvalho Chehab 
5149a0bf528SMauro Carvalho Chehab 		/* Soft reset */
5159a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
5169a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
5179a0bf528SMauro Carvalho Chehab 				& 0xfe);
5189a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
5199a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
5209a0bf528SMauro Carvalho Chehab 				| 0x01);
5219a0bf528SMauro Carvalho Chehab 
5229a0bf528SMauro Carvalho Chehab 		/* Put the demod into host download mode */
5239a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_C4_1,
5249a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9);
5259a0bf528SMauro Carvalho Chehab 
5269a0bf528SMauro Carvalho Chehab 		/* Boot the DSP */
5279a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_C4_1,
5289a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08);
5299a0bf528SMauro Carvalho Chehab 
5309a0bf528SMauro Carvalho Chehab 		/* Prepare for download */
5319a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0);
5329a0bf528SMauro Carvalho Chehab 
5339a0bf528SMauro Carvalho Chehab 		/* Download the firmware payload */
5349a0bf528SMauro Carvalho Chehab 		while (pos < fw->size) {
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 			if ((fw->size - pos) > wlen)
5379a0bf528SMauro Carvalho Chehab 				cnt = wlen;
5389a0bf528SMauro Carvalho Chehab 			else
5399a0bf528SMauro Carvalho Chehab 				cnt = fw->size - pos;
5409a0bf528SMauro Carvalho Chehab 
5419a0bf528SMauro Carvalho Chehab 			tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN,
5429a0bf528SMauro Carvalho Chehab 				&fw->data[pos], cnt);
5439a0bf528SMauro Carvalho Chehab 
5449a0bf528SMauro Carvalho Chehab 			pos += cnt;
5459a0bf528SMauro Carvalho Chehab 		}
5469a0bf528SMauro Carvalho Chehab 
5479a0bf528SMauro Carvalho Chehab 		ret = -EIO;
5489a0bf528SMauro Carvalho Chehab 		/* Wait up to 250ms for the DSP to boot */
5499a0bf528SMauro Carvalho Chehab 		for (cnt = 0; cnt < 250 ; cnt += 10) {
5509a0bf528SMauro Carvalho Chehab 
5519a0bf528SMauro Carvalho Chehab 			msleep(10);
5529a0bf528SMauro Carvalho Chehab 
5539a0bf528SMauro Carvalho Chehab 			if (tda10048_readreg(state, TDA10048_SYNC_STATUS)
5549a0bf528SMauro Carvalho Chehab 				& 0x40) {
5559a0bf528SMauro Carvalho Chehab 				ret = 0;
5569a0bf528SMauro Carvalho Chehab 				break;
5579a0bf528SMauro Carvalho Chehab 			}
5589a0bf528SMauro Carvalho Chehab 		}
5599a0bf528SMauro Carvalho Chehab 	}
5609a0bf528SMauro Carvalho Chehab 
5619a0bf528SMauro Carvalho Chehab 	release_firmware(fw);
5629a0bf528SMauro Carvalho Chehab 
5639a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
5649a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "%s: firmware uploaded\n", __func__);
5659a0bf528SMauro Carvalho Chehab 		state->fwloaded = 1;
5669a0bf528SMauro Carvalho Chehab 	} else
5679a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "%s: firmware upload failed\n", __func__);
5689a0bf528SMauro Carvalho Chehab 
5699a0bf528SMauro Carvalho Chehab 	return ret;
5709a0bf528SMauro Carvalho Chehab }
5719a0bf528SMauro Carvalho Chehab 
5729a0bf528SMauro Carvalho Chehab static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
5739a0bf528SMauro Carvalho Chehab {
5749a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
5759a0bf528SMauro Carvalho Chehab 
5769a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s(%d)\n", __func__, inversion);
5779a0bf528SMauro Carvalho Chehab 
5789a0bf528SMauro Carvalho Chehab 	if (inversion == TDA10048_INVERSION_ON)
5799a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_C1_1,
5809a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20);
5819a0bf528SMauro Carvalho Chehab 	else
5829a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_C1_1,
5839a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf);
5849a0bf528SMauro Carvalho Chehab 
5859a0bf528SMauro Carvalho Chehab 	return 0;
5869a0bf528SMauro Carvalho Chehab }
5879a0bf528SMauro Carvalho Chehab 
5889a0bf528SMauro Carvalho Chehab /* Retrieve the demod settings */
5899a0bf528SMauro Carvalho Chehab static int tda10048_get_tps(struct tda10048_state *state,
5909a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p)
5919a0bf528SMauro Carvalho Chehab {
5929a0bf528SMauro Carvalho Chehab 	u8 val;
5939a0bf528SMauro Carvalho Chehab 
5949a0bf528SMauro Carvalho Chehab 	/* Make sure the TPS regs are valid */
5959a0bf528SMauro Carvalho Chehab 	if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01))
5969a0bf528SMauro Carvalho Chehab 		return -EAGAIN;
5979a0bf528SMauro Carvalho Chehab 
5989a0bf528SMauro Carvalho Chehab 	val = tda10048_readreg(state, TDA10048_OUT_CONF2);
5999a0bf528SMauro Carvalho Chehab 	switch ((val & 0x60) >> 5) {
6009a0bf528SMauro Carvalho Chehab 	case 0:
6019a0bf528SMauro Carvalho Chehab 		p->modulation = QPSK;
6029a0bf528SMauro Carvalho Chehab 		break;
6039a0bf528SMauro Carvalho Chehab 	case 1:
6049a0bf528SMauro Carvalho Chehab 		p->modulation = QAM_16;
6059a0bf528SMauro Carvalho Chehab 		break;
6069a0bf528SMauro Carvalho Chehab 	case 2:
6079a0bf528SMauro Carvalho Chehab 		p->modulation = QAM_64;
6089a0bf528SMauro Carvalho Chehab 		break;
6099a0bf528SMauro Carvalho Chehab 	}
6109a0bf528SMauro Carvalho Chehab 	switch ((val & 0x18) >> 3) {
6119a0bf528SMauro Carvalho Chehab 	case 0:
6129a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_NONE;
6139a0bf528SMauro Carvalho Chehab 		break;
6149a0bf528SMauro Carvalho Chehab 	case 1:
6159a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_1;
6169a0bf528SMauro Carvalho Chehab 		break;
6179a0bf528SMauro Carvalho Chehab 	case 2:
6189a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_2;
6199a0bf528SMauro Carvalho Chehab 		break;
6209a0bf528SMauro Carvalho Chehab 	case 3:
6219a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_4;
6229a0bf528SMauro Carvalho Chehab 		break;
6239a0bf528SMauro Carvalho Chehab 	}
6249a0bf528SMauro Carvalho Chehab 	switch (val & 0x07) {
6259a0bf528SMauro Carvalho Chehab 	case 0:
6269a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_1_2;
6279a0bf528SMauro Carvalho Chehab 		break;
6289a0bf528SMauro Carvalho Chehab 	case 1:
6299a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_2_3;
6309a0bf528SMauro Carvalho Chehab 		break;
6319a0bf528SMauro Carvalho Chehab 	case 2:
6329a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_3_4;
6339a0bf528SMauro Carvalho Chehab 		break;
6349a0bf528SMauro Carvalho Chehab 	case 3:
6359a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_5_6;
6369a0bf528SMauro Carvalho Chehab 		break;
6379a0bf528SMauro Carvalho Chehab 	case 4:
6389a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_7_8;
6399a0bf528SMauro Carvalho Chehab 		break;
6409a0bf528SMauro Carvalho Chehab 	}
6419a0bf528SMauro Carvalho Chehab 
6429a0bf528SMauro Carvalho Chehab 	val = tda10048_readreg(state, TDA10048_OUT_CONF3);
6439a0bf528SMauro Carvalho Chehab 	switch (val & 0x07) {
6449a0bf528SMauro Carvalho Chehab 	case 0:
6459a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_1_2;
6469a0bf528SMauro Carvalho Chehab 		break;
6479a0bf528SMauro Carvalho Chehab 	case 1:
6489a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_2_3;
6499a0bf528SMauro Carvalho Chehab 		break;
6509a0bf528SMauro Carvalho Chehab 	case 2:
6519a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_3_4;
6529a0bf528SMauro Carvalho Chehab 		break;
6539a0bf528SMauro Carvalho Chehab 	case 3:
6549a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_5_6;
6559a0bf528SMauro Carvalho Chehab 		break;
6569a0bf528SMauro Carvalho Chehab 	case 4:
6579a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_7_8;
6589a0bf528SMauro Carvalho Chehab 		break;
6599a0bf528SMauro Carvalho Chehab 	}
6609a0bf528SMauro Carvalho Chehab 
6619a0bf528SMauro Carvalho Chehab 	val = tda10048_readreg(state, TDA10048_OUT_CONF1);
6629a0bf528SMauro Carvalho Chehab 	switch ((val & 0x0c) >> 2) {
6639a0bf528SMauro Carvalho Chehab 	case 0:
6649a0bf528SMauro Carvalho Chehab 		p->guard_interval = GUARD_INTERVAL_1_32;
6659a0bf528SMauro Carvalho Chehab 		break;
6669a0bf528SMauro Carvalho Chehab 	case 1:
6679a0bf528SMauro Carvalho Chehab 		p->guard_interval = GUARD_INTERVAL_1_16;
6689a0bf528SMauro Carvalho Chehab 		break;
6699a0bf528SMauro Carvalho Chehab 	case 2:
6709a0bf528SMauro Carvalho Chehab 		p->guard_interval =  GUARD_INTERVAL_1_8;
6719a0bf528SMauro Carvalho Chehab 		break;
6729a0bf528SMauro Carvalho Chehab 	case 3:
6739a0bf528SMauro Carvalho Chehab 		p->guard_interval =  GUARD_INTERVAL_1_4;
6749a0bf528SMauro Carvalho Chehab 		break;
6759a0bf528SMauro Carvalho Chehab 	}
6769a0bf528SMauro Carvalho Chehab 	switch (val & 0x03) {
6779a0bf528SMauro Carvalho Chehab 	case 0:
6789a0bf528SMauro Carvalho Chehab 		p->transmission_mode = TRANSMISSION_MODE_2K;
6799a0bf528SMauro Carvalho Chehab 		break;
6809a0bf528SMauro Carvalho Chehab 	case 1:
6819a0bf528SMauro Carvalho Chehab 		p->transmission_mode = TRANSMISSION_MODE_8K;
6829a0bf528SMauro Carvalho Chehab 		break;
6839a0bf528SMauro Carvalho Chehab 	}
6849a0bf528SMauro Carvalho Chehab 
6859a0bf528SMauro Carvalho Chehab 	return 0;
6869a0bf528SMauro Carvalho Chehab }
6879a0bf528SMauro Carvalho Chehab 
6889a0bf528SMauro Carvalho Chehab static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
6899a0bf528SMauro Carvalho Chehab {
6909a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
6919a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
6929a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s(%d)\n", __func__, enable);
6939a0bf528SMauro Carvalho Chehab 
6949a0bf528SMauro Carvalho Chehab 	if (config->disable_gate_access)
6959a0bf528SMauro Carvalho Chehab 		return 0;
6969a0bf528SMauro Carvalho Chehab 
6979a0bf528SMauro Carvalho Chehab 	if (enable)
6989a0bf528SMauro Carvalho Chehab 		return tda10048_writereg(state, TDA10048_CONF_C4_1,
6999a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
7009a0bf528SMauro Carvalho Chehab 	else
7019a0bf528SMauro Carvalho Chehab 		return tda10048_writereg(state, TDA10048_CONF_C4_1,
7029a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd);
7039a0bf528SMauro Carvalho Chehab }
7049a0bf528SMauro Carvalho Chehab 
7059a0bf528SMauro Carvalho Chehab static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
7069a0bf528SMauro Carvalho Chehab {
7079a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
7089a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s(%d)\n", __func__, serial);
7099a0bf528SMauro Carvalho Chehab 
7109a0bf528SMauro Carvalho Chehab 	/* Ensure pins are out of tri-state */
7119a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21);
7129a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00);
7139a0bf528SMauro Carvalho Chehab 
7149a0bf528SMauro Carvalho Chehab 	if (serial) {
7159a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20);
7169a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0);
7179a0bf528SMauro Carvalho Chehab 	} else {
7189a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_IC_MODE, 0x00);
7199a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CONF_TS2, 0x01);
7209a0bf528SMauro Carvalho Chehab 	}
7219a0bf528SMauro Carvalho Chehab 
7229a0bf528SMauro Carvalho Chehab 	return 0;
7239a0bf528SMauro Carvalho Chehab }
7249a0bf528SMauro Carvalho Chehab 
7259a0bf528SMauro Carvalho Chehab /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
7269a0bf528SMauro Carvalho Chehab /* TODO: Support manual tuning with specific params */
7279a0bf528SMauro Carvalho Chehab static int tda10048_set_frontend(struct dvb_frontend *fe)
7289a0bf528SMauro Carvalho Chehab {
7299a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
7309a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
7319a0bf528SMauro Carvalho Chehab 
7329a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
7339a0bf528SMauro Carvalho Chehab 
7349a0bf528SMauro Carvalho Chehab 	/* Update the I/F pll's if the bandwidth changes */
7359a0bf528SMauro Carvalho Chehab 	if (p->bandwidth_hz != state->bandwidth) {
7369a0bf528SMauro Carvalho Chehab 		tda10048_set_if(fe, p->bandwidth_hz);
7379a0bf528SMauro Carvalho Chehab 		tda10048_set_bandwidth(fe, p->bandwidth_hz);
7389a0bf528SMauro Carvalho Chehab 	}
7399a0bf528SMauro Carvalho Chehab 
7409a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
7419a0bf528SMauro Carvalho Chehab 
7429a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
7439a0bf528SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 1);
7449a0bf528SMauro Carvalho Chehab 
7459a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
7469a0bf528SMauro Carvalho Chehab 
7479a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
7489a0bf528SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
7499a0bf528SMauro Carvalho Chehab 	}
7509a0bf528SMauro Carvalho Chehab 
7519a0bf528SMauro Carvalho Chehab 	/* Enable demod TPS auto detection and begin acquisition */
7529a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_AUTO, 0x57);
7539a0bf528SMauro Carvalho Chehab 	/* trigger cber and vber acquisition */
7549a0bf528SMauro Carvalho Chehab 	tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B);
7559a0bf528SMauro Carvalho Chehab 
7569a0bf528SMauro Carvalho Chehab 	return 0;
7579a0bf528SMauro Carvalho Chehab }
7589a0bf528SMauro Carvalho Chehab 
7599a0bf528SMauro Carvalho Chehab /* Establish sane defaults and load firmware. */
7609a0bf528SMauro Carvalho Chehab static int tda10048_init(struct dvb_frontend *fe)
7619a0bf528SMauro Carvalho Chehab {
7629a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
7639a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
7649a0bf528SMauro Carvalho Chehab 	int ret = 0, i;
7659a0bf528SMauro Carvalho Chehab 
7669a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 	/* PLL */
7699a0bf528SMauro Carvalho Chehab 	init_tab[4].data = (u8)(state->pll_mfactor);
7709a0bf528SMauro Carvalho Chehab 	init_tab[5].data = (u8)(state->pll_nfactor) | 0x40;
7719a0bf528SMauro Carvalho Chehab 
7729a0bf528SMauro Carvalho Chehab 	/* Apply register defaults */
7739a0bf528SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
7749a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
7759a0bf528SMauro Carvalho Chehab 
7769a0bf528SMauro Carvalho Chehab 	if (state->fwloaded == 0)
7779a0bf528SMauro Carvalho Chehab 		ret = tda10048_firmware_upload(fe);
7789a0bf528SMauro Carvalho Chehab 
7799a0bf528SMauro Carvalho Chehab 	/* Set either serial or parallel */
7809a0bf528SMauro Carvalho Chehab 	tda10048_output_mode(fe, config->output_mode);
7819a0bf528SMauro Carvalho Chehab 
7829a0bf528SMauro Carvalho Chehab 	/* Set inversion */
7839a0bf528SMauro Carvalho Chehab 	tda10048_set_inversion(fe, config->inversion);
7849a0bf528SMauro Carvalho Chehab 
7859a0bf528SMauro Carvalho Chehab 	/* Establish default RF values */
7869a0bf528SMauro Carvalho Chehab 	tda10048_set_if(fe, 8000000);
7879a0bf528SMauro Carvalho Chehab 	tda10048_set_bandwidth(fe, 8000000);
7889a0bf528SMauro Carvalho Chehab 
7899a0bf528SMauro Carvalho Chehab 	/* Ensure we leave the gate closed */
7909a0bf528SMauro Carvalho Chehab 	tda10048_i2c_gate_ctrl(fe, 0);
7919a0bf528SMauro Carvalho Chehab 
7929a0bf528SMauro Carvalho Chehab 	return ret;
7939a0bf528SMauro Carvalho Chehab }
7949a0bf528SMauro Carvalho Chehab 
7950df289a2SMauro Carvalho Chehab static int tda10048_read_status(struct dvb_frontend *fe, enum fe_status *status)
7969a0bf528SMauro Carvalho Chehab {
7979a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
7989a0bf528SMauro Carvalho Chehab 	u8 reg;
7999a0bf528SMauro Carvalho Chehab 
8009a0bf528SMauro Carvalho Chehab 	*status = 0;
8019a0bf528SMauro Carvalho Chehab 
8029a0bf528SMauro Carvalho Chehab 	reg = tda10048_readreg(state, TDA10048_SYNC_STATUS);
8039a0bf528SMauro Carvalho Chehab 
8049a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s() status =0x%02x\n", __func__, reg);
8059a0bf528SMauro Carvalho Chehab 
8069a0bf528SMauro Carvalho Chehab 	if (reg & 0x02)
8079a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_CARRIER;
8089a0bf528SMauro Carvalho Chehab 
8099a0bf528SMauro Carvalho Chehab 	if (reg & 0x04)
8109a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
8119a0bf528SMauro Carvalho Chehab 
8129a0bf528SMauro Carvalho Chehab 	if (reg & 0x08) {
8139a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK;
8149a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_VITERBI;
8159a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
8169a0bf528SMauro Carvalho Chehab 	}
8179a0bf528SMauro Carvalho Chehab 
8189a0bf528SMauro Carvalho Chehab 	return 0;
8199a0bf528SMauro Carvalho Chehab }
8209a0bf528SMauro Carvalho Chehab 
8219a0bf528SMauro Carvalho Chehab static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
8229a0bf528SMauro Carvalho Chehab {
8239a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
8249a0bf528SMauro Carvalho Chehab 	static u32 cber_current;
8259a0bf528SMauro Carvalho Chehab 	u32 cber_nmax;
8269a0bf528SMauro Carvalho Chehab 	u64 cber_tmp;
8279a0bf528SMauro Carvalho Chehab 
8289a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
8299a0bf528SMauro Carvalho Chehab 
8309a0bf528SMauro Carvalho Chehab 	/* update cber on interrupt */
8319a0bf528SMauro Carvalho Chehab 	if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) {
8329a0bf528SMauro Carvalho Chehab 		cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
8339a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CBER_LSB);
8349a0bf528SMauro Carvalho Chehab 		cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 |
8359a0bf528SMauro Carvalho Chehab 			tda10048_readreg(state, TDA10048_CBER_NMAX_LSB);
8369a0bf528SMauro Carvalho Chehab 		cber_tmp *= 100000000;
8379a0bf528SMauro Carvalho Chehab 		cber_tmp *= 2;
8389a0bf528SMauro Carvalho Chehab 		cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1);
8399a0bf528SMauro Carvalho Chehab 		cber_current = (u32)cber_tmp;
8409a0bf528SMauro Carvalho Chehab 		/* retrigger cber acquisition */
8419a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39);
8429a0bf528SMauro Carvalho Chehab 	}
8439a0bf528SMauro Carvalho Chehab 	/* actual cber is (*ber)/1e8 */
8449a0bf528SMauro Carvalho Chehab 	*ber = cber_current;
8459a0bf528SMauro Carvalho Chehab 
8469a0bf528SMauro Carvalho Chehab 	return 0;
8479a0bf528SMauro Carvalho Chehab }
8489a0bf528SMauro Carvalho Chehab 
8499a0bf528SMauro Carvalho Chehab static int tda10048_read_signal_strength(struct dvb_frontend *fe,
8509a0bf528SMauro Carvalho Chehab 	u16 *signal_strength)
8519a0bf528SMauro Carvalho Chehab {
8529a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
8539a0bf528SMauro Carvalho Chehab 	u8 v;
8549a0bf528SMauro Carvalho Chehab 
8559a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
8569a0bf528SMauro Carvalho Chehab 
8579a0bf528SMauro Carvalho Chehab 	*signal_strength = 65535;
8589a0bf528SMauro Carvalho Chehab 
8599a0bf528SMauro Carvalho Chehab 	v = tda10048_readreg(state, TDA10048_NP_OUT);
8609a0bf528SMauro Carvalho Chehab 	if (v > 0)
8619a0bf528SMauro Carvalho Chehab 		*signal_strength -= (v << 8) | v;
8629a0bf528SMauro Carvalho Chehab 
8639a0bf528SMauro Carvalho Chehab 	return 0;
8649a0bf528SMauro Carvalho Chehab }
8659a0bf528SMauro Carvalho Chehab 
8669a0bf528SMauro Carvalho Chehab /* SNR lookup table */
8679a0bf528SMauro Carvalho Chehab static struct snr_tab {
8689a0bf528SMauro Carvalho Chehab 	u8 val;
8699a0bf528SMauro Carvalho Chehab 	u8 data;
8709a0bf528SMauro Carvalho Chehab } snr_tab[] = {
8719a0bf528SMauro Carvalho Chehab 	{   0,   0 },
8729a0bf528SMauro Carvalho Chehab 	{   1, 246 },
8739a0bf528SMauro Carvalho Chehab 	{   2, 215 },
8749a0bf528SMauro Carvalho Chehab 	{   3, 198 },
8759a0bf528SMauro Carvalho Chehab 	{   4, 185 },
8769a0bf528SMauro Carvalho Chehab 	{   5, 176 },
8779a0bf528SMauro Carvalho Chehab 	{   6, 168 },
8789a0bf528SMauro Carvalho Chehab 	{   7, 161 },
8799a0bf528SMauro Carvalho Chehab 	{   8, 155 },
8809a0bf528SMauro Carvalho Chehab 	{   9, 150 },
8819a0bf528SMauro Carvalho Chehab 	{  10, 146 },
8829a0bf528SMauro Carvalho Chehab 	{  11, 141 },
8839a0bf528SMauro Carvalho Chehab 	{  12, 138 },
8849a0bf528SMauro Carvalho Chehab 	{  13, 134 },
8859a0bf528SMauro Carvalho Chehab 	{  14, 131 },
8869a0bf528SMauro Carvalho Chehab 	{  15, 128 },
8879a0bf528SMauro Carvalho Chehab 	{  16, 125 },
8889a0bf528SMauro Carvalho Chehab 	{  17, 122 },
8899a0bf528SMauro Carvalho Chehab 	{  18, 120 },
8909a0bf528SMauro Carvalho Chehab 	{  19, 118 },
8919a0bf528SMauro Carvalho Chehab 	{  20, 115 },
8929a0bf528SMauro Carvalho Chehab 	{  21, 113 },
8939a0bf528SMauro Carvalho Chehab 	{  22, 111 },
8949a0bf528SMauro Carvalho Chehab 	{  23, 109 },
8959a0bf528SMauro Carvalho Chehab 	{  24, 107 },
8969a0bf528SMauro Carvalho Chehab 	{  25, 106 },
8979a0bf528SMauro Carvalho Chehab 	{  26, 104 },
8989a0bf528SMauro Carvalho Chehab 	{  27, 102 },
8999a0bf528SMauro Carvalho Chehab 	{  28, 101 },
9009a0bf528SMauro Carvalho Chehab 	{  29,  99 },
9019a0bf528SMauro Carvalho Chehab 	{  30,  98 },
9029a0bf528SMauro Carvalho Chehab 	{  31,  96 },
9039a0bf528SMauro Carvalho Chehab 	{  32,  95 },
9049a0bf528SMauro Carvalho Chehab 	{  33,  94 },
9059a0bf528SMauro Carvalho Chehab 	{  34,  92 },
9069a0bf528SMauro Carvalho Chehab 	{  35,  91 },
9079a0bf528SMauro Carvalho Chehab 	{  36,  90 },
9089a0bf528SMauro Carvalho Chehab 	{  37,  89 },
9099a0bf528SMauro Carvalho Chehab 	{  38,  88 },
9109a0bf528SMauro Carvalho Chehab 	{  39,  86 },
9119a0bf528SMauro Carvalho Chehab 	{  40,  85 },
9129a0bf528SMauro Carvalho Chehab 	{  41,  84 },
9139a0bf528SMauro Carvalho Chehab 	{  42,  83 },
9149a0bf528SMauro Carvalho Chehab 	{  43,  82 },
9159a0bf528SMauro Carvalho Chehab 	{  44,  81 },
9169a0bf528SMauro Carvalho Chehab 	{  45,  80 },
9179a0bf528SMauro Carvalho Chehab 	{  46,  79 },
9189a0bf528SMauro Carvalho Chehab 	{  47,  78 },
9199a0bf528SMauro Carvalho Chehab 	{  48,  77 },
9209a0bf528SMauro Carvalho Chehab 	{  49,  76 },
9219a0bf528SMauro Carvalho Chehab 	{  50,  76 },
9229a0bf528SMauro Carvalho Chehab 	{  51,  75 },
9239a0bf528SMauro Carvalho Chehab 	{  52,  74 },
9249a0bf528SMauro Carvalho Chehab 	{  53,  73 },
9259a0bf528SMauro Carvalho Chehab 	{  54,  72 },
9269a0bf528SMauro Carvalho Chehab 	{  56,  71 },
9279a0bf528SMauro Carvalho Chehab 	{  57,  70 },
9289a0bf528SMauro Carvalho Chehab 	{  58,  69 },
9299a0bf528SMauro Carvalho Chehab 	{  60,  68 },
9309a0bf528SMauro Carvalho Chehab 	{  61,  67 },
9319a0bf528SMauro Carvalho Chehab 	{  63,  66 },
9329a0bf528SMauro Carvalho Chehab 	{  64,  65 },
9339a0bf528SMauro Carvalho Chehab 	{  66,  64 },
9349a0bf528SMauro Carvalho Chehab 	{  67,  63 },
9359a0bf528SMauro Carvalho Chehab 	{  68,  62 },
9369a0bf528SMauro Carvalho Chehab 	{  69,  62 },
9379a0bf528SMauro Carvalho Chehab 	{  70,  61 },
9389a0bf528SMauro Carvalho Chehab 	{  72,  60 },
9399a0bf528SMauro Carvalho Chehab 	{  74,  59 },
9409a0bf528SMauro Carvalho Chehab 	{  75,  58 },
9419a0bf528SMauro Carvalho Chehab 	{  77,  57 },
9429a0bf528SMauro Carvalho Chehab 	{  79,  56 },
9439a0bf528SMauro Carvalho Chehab 	{  81,  55 },
9449a0bf528SMauro Carvalho Chehab 	{  83,  54 },
9459a0bf528SMauro Carvalho Chehab 	{  85,  53 },
9469a0bf528SMauro Carvalho Chehab 	{  87,  52 },
9479a0bf528SMauro Carvalho Chehab 	{  89,  51 },
9489a0bf528SMauro Carvalho Chehab 	{  91,  50 },
9499a0bf528SMauro Carvalho Chehab 	{  93,  49 },
9509a0bf528SMauro Carvalho Chehab 	{  95,  48 },
9519a0bf528SMauro Carvalho Chehab 	{  97,  47 },
9529a0bf528SMauro Carvalho Chehab 	{ 100,  46 },
9539a0bf528SMauro Carvalho Chehab 	{ 102,  45 },
9549a0bf528SMauro Carvalho Chehab 	{ 104,  44 },
9559a0bf528SMauro Carvalho Chehab 	{ 107,  43 },
9569a0bf528SMauro Carvalho Chehab 	{ 109,  42 },
9579a0bf528SMauro Carvalho Chehab 	{ 112,  41 },
9589a0bf528SMauro Carvalho Chehab 	{ 114,  40 },
9599a0bf528SMauro Carvalho Chehab 	{ 117,  39 },
9609a0bf528SMauro Carvalho Chehab 	{ 120,  38 },
9619a0bf528SMauro Carvalho Chehab 	{ 123,  37 },
9629a0bf528SMauro Carvalho Chehab 	{ 125,  36 },
9639a0bf528SMauro Carvalho Chehab 	{ 128,  35 },
9649a0bf528SMauro Carvalho Chehab 	{ 131,  34 },
9659a0bf528SMauro Carvalho Chehab 	{ 134,  33 },
9669a0bf528SMauro Carvalho Chehab 	{ 138,  32 },
9679a0bf528SMauro Carvalho Chehab 	{ 141,  31 },
9689a0bf528SMauro Carvalho Chehab 	{ 144,  30 },
9699a0bf528SMauro Carvalho Chehab 	{ 147,  29 },
9709a0bf528SMauro Carvalho Chehab 	{ 151,  28 },
9719a0bf528SMauro Carvalho Chehab 	{ 154,  27 },
9729a0bf528SMauro Carvalho Chehab 	{ 158,  26 },
9739a0bf528SMauro Carvalho Chehab 	{ 162,  25 },
9749a0bf528SMauro Carvalho Chehab 	{ 165,  24 },
9759a0bf528SMauro Carvalho Chehab 	{ 169,  23 },
9769a0bf528SMauro Carvalho Chehab 	{ 173,  22 },
9779a0bf528SMauro Carvalho Chehab 	{ 177,  21 },
9789a0bf528SMauro Carvalho Chehab 	{ 181,  20 },
9799a0bf528SMauro Carvalho Chehab 	{ 186,  19 },
9809a0bf528SMauro Carvalho Chehab 	{ 190,  18 },
9819a0bf528SMauro Carvalho Chehab 	{ 194,  17 },
9829a0bf528SMauro Carvalho Chehab 	{ 199,  16 },
9839a0bf528SMauro Carvalho Chehab 	{ 204,  15 },
9849a0bf528SMauro Carvalho Chehab 	{ 208,  14 },
9859a0bf528SMauro Carvalho Chehab 	{ 213,  13 },
9869a0bf528SMauro Carvalho Chehab 	{ 218,  12 },
9879a0bf528SMauro Carvalho Chehab 	{ 223,  11 },
9889a0bf528SMauro Carvalho Chehab 	{ 229,  10 },
9899a0bf528SMauro Carvalho Chehab 	{ 234,   9 },
9909a0bf528SMauro Carvalho Chehab 	{ 239,   8 },
9919a0bf528SMauro Carvalho Chehab 	{ 245,   7 },
9929a0bf528SMauro Carvalho Chehab 	{ 251,   6 },
9939a0bf528SMauro Carvalho Chehab 	{ 255,   5 },
9949a0bf528SMauro Carvalho Chehab };
9959a0bf528SMauro Carvalho Chehab 
9969a0bf528SMauro Carvalho Chehab static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr)
9979a0bf528SMauro Carvalho Chehab {
9989a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
9999a0bf528SMauro Carvalho Chehab 	u8 v;
10009a0bf528SMauro Carvalho Chehab 	int i, ret = -EINVAL;
10019a0bf528SMauro Carvalho Chehab 
10029a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
10039a0bf528SMauro Carvalho Chehab 
10049a0bf528SMauro Carvalho Chehab 	v = tda10048_readreg(state, TDA10048_NP_OUT);
10059a0bf528SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(snr_tab); i++) {
10069a0bf528SMauro Carvalho Chehab 		if (v <= snr_tab[i].val) {
10079a0bf528SMauro Carvalho Chehab 			*snr = snr_tab[i].data;
10089a0bf528SMauro Carvalho Chehab 			ret = 0;
10099a0bf528SMauro Carvalho Chehab 			break;
10109a0bf528SMauro Carvalho Chehab 		}
10119a0bf528SMauro Carvalho Chehab 	}
10129a0bf528SMauro Carvalho Chehab 
10139a0bf528SMauro Carvalho Chehab 	return ret;
10149a0bf528SMauro Carvalho Chehab }
10159a0bf528SMauro Carvalho Chehab 
10169a0bf528SMauro Carvalho Chehab static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
10179a0bf528SMauro Carvalho Chehab {
10189a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
10199a0bf528SMauro Carvalho Chehab 
10209a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
10219a0bf528SMauro Carvalho Chehab 
10229a0bf528SMauro Carvalho Chehab 	*ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
10239a0bf528SMauro Carvalho Chehab 		tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
10249a0bf528SMauro Carvalho Chehab 	/* clear the uncorrected TS packets counter when saturated */
10259a0bf528SMauro Carvalho Chehab 	if (*ucblocks == 0xFFFF)
10269a0bf528SMauro Carvalho Chehab 		tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80);
10279a0bf528SMauro Carvalho Chehab 
10289a0bf528SMauro Carvalho Chehab 	return 0;
10299a0bf528SMauro Carvalho Chehab }
10309a0bf528SMauro Carvalho Chehab 
10317e3e68bcSMauro Carvalho Chehab static int tda10048_get_frontend(struct dvb_frontend *fe,
10327e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *p)
10339a0bf528SMauro Carvalho Chehab {
10349a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
10359a0bf528SMauro Carvalho Chehab 
10369a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
10379a0bf528SMauro Carvalho Chehab 
10389a0bf528SMauro Carvalho Chehab 	p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
10399a0bf528SMauro Carvalho Chehab 		& 0x20 ? INVERSION_ON : INVERSION_OFF;
10409a0bf528SMauro Carvalho Chehab 
10419a0bf528SMauro Carvalho Chehab 	return tda10048_get_tps(state, p);
10429a0bf528SMauro Carvalho Chehab }
10439a0bf528SMauro Carvalho Chehab 
10449a0bf528SMauro Carvalho Chehab static int tda10048_get_tune_settings(struct dvb_frontend *fe,
10459a0bf528SMauro Carvalho Chehab 	struct dvb_frontend_tune_settings *tune)
10469a0bf528SMauro Carvalho Chehab {
10479a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
10489a0bf528SMauro Carvalho Chehab 	return 0;
10499a0bf528SMauro Carvalho Chehab }
10509a0bf528SMauro Carvalho Chehab 
10519a0bf528SMauro Carvalho Chehab static void tda10048_release(struct dvb_frontend *fe)
10529a0bf528SMauro Carvalho Chehab {
10539a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
10549a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
10559a0bf528SMauro Carvalho Chehab 	kfree(state);
10569a0bf528SMauro Carvalho Chehab }
10579a0bf528SMauro Carvalho Chehab 
10589a0bf528SMauro Carvalho Chehab static void tda10048_establish_defaults(struct dvb_frontend *fe)
10599a0bf528SMauro Carvalho Chehab {
10609a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = fe->demodulator_priv;
10619a0bf528SMauro Carvalho Chehab 	struct tda10048_config *config = &state->config;
10629a0bf528SMauro Carvalho Chehab 
10639a0bf528SMauro Carvalho Chehab 	/* Validate/default the config */
10649a0bf528SMauro Carvalho Chehab 	if (config->dtv6_if_freq_khz == 0) {
10659a0bf528SMauro Carvalho Chehab 		config->dtv6_if_freq_khz = TDA10048_IF_4300;
10664bd69e7bSMauro Carvalho Chehab 		printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz is not set (defaulting to %d)\n",
10679a0bf528SMauro Carvalho Chehab 			__func__,
10689a0bf528SMauro Carvalho Chehab 			config->dtv6_if_freq_khz);
10699a0bf528SMauro Carvalho Chehab 	}
10709a0bf528SMauro Carvalho Chehab 
10719a0bf528SMauro Carvalho Chehab 	if (config->dtv7_if_freq_khz == 0) {
10729a0bf528SMauro Carvalho Chehab 		config->dtv7_if_freq_khz = TDA10048_IF_4300;
10734bd69e7bSMauro Carvalho Chehab 		printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz is not set (defaulting to %d)\n",
10749a0bf528SMauro Carvalho Chehab 			__func__,
10759a0bf528SMauro Carvalho Chehab 			config->dtv7_if_freq_khz);
10769a0bf528SMauro Carvalho Chehab 	}
10779a0bf528SMauro Carvalho Chehab 
10789a0bf528SMauro Carvalho Chehab 	if (config->dtv8_if_freq_khz == 0) {
10799a0bf528SMauro Carvalho Chehab 		config->dtv8_if_freq_khz = TDA10048_IF_4300;
10804bd69e7bSMauro Carvalho Chehab 		printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz is not set (defaulting to %d)\n",
10819a0bf528SMauro Carvalho Chehab 			__func__,
10829a0bf528SMauro Carvalho Chehab 			config->dtv8_if_freq_khz);
10839a0bf528SMauro Carvalho Chehab 	}
10849a0bf528SMauro Carvalho Chehab 
10859a0bf528SMauro Carvalho Chehab 	if (config->clk_freq_khz == 0) {
10869a0bf528SMauro Carvalho Chehab 		config->clk_freq_khz = TDA10048_CLK_16000;
10874bd69e7bSMauro Carvalho Chehab 		printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz is not set (defaulting to %d)\n",
10889a0bf528SMauro Carvalho Chehab 			__func__,
10899a0bf528SMauro Carvalho Chehab 			config->clk_freq_khz);
10909a0bf528SMauro Carvalho Chehab 	}
10919a0bf528SMauro Carvalho Chehab }
10929a0bf528SMauro Carvalho Chehab 
1093bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10048_ops;
10949a0bf528SMauro Carvalho Chehab 
10959a0bf528SMauro Carvalho Chehab struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
10969a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c)
10979a0bf528SMauro Carvalho Chehab {
10989a0bf528SMauro Carvalho Chehab 	struct tda10048_state *state = NULL;
10999a0bf528SMauro Carvalho Chehab 
11009a0bf528SMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
11019a0bf528SMauro Carvalho Chehab 
11029a0bf528SMauro Carvalho Chehab 	/* allocate memory for the internal state */
11039a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct tda10048_state), GFP_KERNEL);
11049a0bf528SMauro Carvalho Chehab 	if (state == NULL)
11059a0bf528SMauro Carvalho Chehab 		goto error;
11069a0bf528SMauro Carvalho Chehab 
11079a0bf528SMauro Carvalho Chehab 	/* setup the state and clone the config */
11089a0bf528SMauro Carvalho Chehab 	memcpy(&state->config, config, sizeof(*config));
11099a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
11109a0bf528SMauro Carvalho Chehab 	state->fwloaded = config->no_firmware;
11119a0bf528SMauro Carvalho Chehab 	state->bandwidth = 8000000;
11129a0bf528SMauro Carvalho Chehab 
11139a0bf528SMauro Carvalho Chehab 	/* check if the demod is present */
11149a0bf528SMauro Carvalho Chehab 	if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
11159a0bf528SMauro Carvalho Chehab 		goto error;
11169a0bf528SMauro Carvalho Chehab 
11179a0bf528SMauro Carvalho Chehab 	/* create dvb_frontend */
11189a0bf528SMauro Carvalho Chehab 	memcpy(&state->frontend.ops, &tda10048_ops,
11199a0bf528SMauro Carvalho Chehab 		sizeof(struct dvb_frontend_ops));
11209a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
11219a0bf528SMauro Carvalho Chehab 
11229a0bf528SMauro Carvalho Chehab 	/* set pll */
11239a0bf528SMauro Carvalho Chehab 	if (config->set_pll) {
11249a0bf528SMauro Carvalho Chehab 		state->pll_mfactor = config->pll_m;
11259a0bf528SMauro Carvalho Chehab 		state->pll_nfactor = config->pll_n;
11269a0bf528SMauro Carvalho Chehab 		state->pll_pfactor = config->pll_p;
11279a0bf528SMauro Carvalho Chehab 	} else {
11289a0bf528SMauro Carvalho Chehab 		state->pll_mfactor = 10;
11299a0bf528SMauro Carvalho Chehab 		state->pll_nfactor = 3;
11309a0bf528SMauro Carvalho Chehab 		state->pll_pfactor = 0;
11319a0bf528SMauro Carvalho Chehab 	}
11329a0bf528SMauro Carvalho Chehab 
11339a0bf528SMauro Carvalho Chehab 	/* Establish any defaults the the user didn't pass */
11349a0bf528SMauro Carvalho Chehab 	tda10048_establish_defaults(&state->frontend);
11359a0bf528SMauro Carvalho Chehab 
11369a0bf528SMauro Carvalho Chehab 	/* Set the xtal and freq defaults */
11379a0bf528SMauro Carvalho Chehab 	if (tda10048_set_if(&state->frontend, 8000000) != 0)
11389a0bf528SMauro Carvalho Chehab 		goto error;
11399a0bf528SMauro Carvalho Chehab 
11409a0bf528SMauro Carvalho Chehab 	/* Default bandwidth */
11419a0bf528SMauro Carvalho Chehab 	if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0)
11429a0bf528SMauro Carvalho Chehab 		goto error;
11439a0bf528SMauro Carvalho Chehab 
11449a0bf528SMauro Carvalho Chehab 	/* Leave the gate closed */
11459a0bf528SMauro Carvalho Chehab 	tda10048_i2c_gate_ctrl(&state->frontend, 0);
11469a0bf528SMauro Carvalho Chehab 
11479a0bf528SMauro Carvalho Chehab 	return &state->frontend;
11489a0bf528SMauro Carvalho Chehab 
11499a0bf528SMauro Carvalho Chehab error:
11509a0bf528SMauro Carvalho Chehab 	kfree(state);
11519a0bf528SMauro Carvalho Chehab 	return NULL;
11529a0bf528SMauro Carvalho Chehab }
11539a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(tda10048_attach);
11549a0bf528SMauro Carvalho Chehab 
1155bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10048_ops = {
11569a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
11579a0bf528SMauro Carvalho Chehab 	.info = {
11589a0bf528SMauro Carvalho Chehab 		.name			= "NXP TDA10048HN DVB-T",
11599a0bf528SMauro Carvalho Chehab 		.frequency_min		= 177000000,
11609a0bf528SMauro Carvalho Chehab 		.frequency_max		= 858000000,
11619a0bf528SMauro Carvalho Chehab 		.frequency_stepsize	= 166666,
11629a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
11639a0bf528SMauro Carvalho Chehab 		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
11649a0bf528SMauro Carvalho Chehab 		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
11659a0bf528SMauro Carvalho Chehab 		FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
11669a0bf528SMauro Carvalho Chehab 		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
11679a0bf528SMauro Carvalho Chehab 	},
11689a0bf528SMauro Carvalho Chehab 
11699a0bf528SMauro Carvalho Chehab 	.release = tda10048_release,
11709a0bf528SMauro Carvalho Chehab 	.init = tda10048_init,
11719a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl = tda10048_i2c_gate_ctrl,
11729a0bf528SMauro Carvalho Chehab 	.set_frontend = tda10048_set_frontend,
11739a0bf528SMauro Carvalho Chehab 	.get_frontend = tda10048_get_frontend,
11749a0bf528SMauro Carvalho Chehab 	.get_tune_settings = tda10048_get_tune_settings,
11759a0bf528SMauro Carvalho Chehab 	.read_status = tda10048_read_status,
11769a0bf528SMauro Carvalho Chehab 	.read_ber = tda10048_read_ber,
11779a0bf528SMauro Carvalho Chehab 	.read_signal_strength = tda10048_read_signal_strength,
11789a0bf528SMauro Carvalho Chehab 	.read_snr = tda10048_read_snr,
11799a0bf528SMauro Carvalho Chehab 	.read_ucblocks = tda10048_read_ucblocks,
11809a0bf528SMauro Carvalho Chehab };
11819a0bf528SMauro Carvalho Chehab 
11829a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
11839a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Enable verbose debug messages");
11849a0bf528SMauro Carvalho Chehab 
11859a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver");
11869a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth");
11879a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1188