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