18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci NXP TDA10048HN DVB OFDM demodulator driver 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) 2009 Steven Toth <stoth@kernellabs.com> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/math64.h> 178c2ecf20Sopenharmony_ci#include <asm/div64.h> 188c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 198c2ecf20Sopenharmony_ci#include <media/dvb_math.h> 208c2ecf20Sopenharmony_ci#include "tda10048.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw" 238c2ecf20Sopenharmony_ci#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Register name definitions */ 268c2ecf20Sopenharmony_ci#define TDA10048_IDENTITY 0x00 278c2ecf20Sopenharmony_ci#define TDA10048_VERSION 0x01 288c2ecf20Sopenharmony_ci#define TDA10048_DSP_CODE_CPT 0x0C 298c2ecf20Sopenharmony_ci#define TDA10048_DSP_CODE_IN 0x0E 308c2ecf20Sopenharmony_ci#define TDA10048_IN_CONF1 0x10 318c2ecf20Sopenharmony_ci#define TDA10048_IN_CONF2 0x11 328c2ecf20Sopenharmony_ci#define TDA10048_IN_CONF3 0x12 338c2ecf20Sopenharmony_ci#define TDA10048_OUT_CONF1 0x14 348c2ecf20Sopenharmony_ci#define TDA10048_OUT_CONF2 0x15 358c2ecf20Sopenharmony_ci#define TDA10048_OUT_CONF3 0x16 368c2ecf20Sopenharmony_ci#define TDA10048_AUTO 0x18 378c2ecf20Sopenharmony_ci#define TDA10048_SYNC_STATUS 0x1A 388c2ecf20Sopenharmony_ci#define TDA10048_CONF_C4_1 0x1E 398c2ecf20Sopenharmony_ci#define TDA10048_CONF_C4_2 0x1F 408c2ecf20Sopenharmony_ci#define TDA10048_CODE_IN_RAM 0x20 418c2ecf20Sopenharmony_ci#define TDA10048_CHANNEL_INFO1_R 0x22 428c2ecf20Sopenharmony_ci#define TDA10048_CHANNEL_INFO2_R 0x23 438c2ecf20Sopenharmony_ci#define TDA10048_CHANNEL_INFO1 0x24 448c2ecf20Sopenharmony_ci#define TDA10048_CHANNEL_INFO2 0x25 458c2ecf20Sopenharmony_ci#define TDA10048_TIME_ERROR_R 0x26 468c2ecf20Sopenharmony_ci#define TDA10048_TIME_ERROR 0x27 478c2ecf20Sopenharmony_ci#define TDA10048_FREQ_ERROR_LSB_R 0x28 488c2ecf20Sopenharmony_ci#define TDA10048_FREQ_ERROR_MSB_R 0x29 498c2ecf20Sopenharmony_ci#define TDA10048_FREQ_ERROR_LSB 0x2A 508c2ecf20Sopenharmony_ci#define TDA10048_FREQ_ERROR_MSB 0x2B 518c2ecf20Sopenharmony_ci#define TDA10048_IT_SEL 0x30 528c2ecf20Sopenharmony_ci#define TDA10048_IT_STAT 0x32 538c2ecf20Sopenharmony_ci#define TDA10048_DSP_AD_LSB 0x3C 548c2ecf20Sopenharmony_ci#define TDA10048_DSP_AD_MSB 0x3D 558c2ecf20Sopenharmony_ci#define TDA10048_DSP_REG_LSB 0x3E 568c2ecf20Sopenharmony_ci#define TDA10048_DSP_REG_MSB 0x3F 578c2ecf20Sopenharmony_ci#define TDA10048_CONF_TRISTATE1 0x44 588c2ecf20Sopenharmony_ci#define TDA10048_CONF_TRISTATE2 0x45 598c2ecf20Sopenharmony_ci#define TDA10048_CONF_POLARITY 0x46 608c2ecf20Sopenharmony_ci#define TDA10048_GPIO_SP_DS0 0x48 618c2ecf20Sopenharmony_ci#define TDA10048_GPIO_SP_DS1 0x49 628c2ecf20Sopenharmony_ci#define TDA10048_GPIO_SP_DS2 0x4A 638c2ecf20Sopenharmony_ci#define TDA10048_GPIO_SP_DS3 0x4B 648c2ecf20Sopenharmony_ci#define TDA10048_GPIO_OUT_SEL 0x4C 658c2ecf20Sopenharmony_ci#define TDA10048_GPIO_SELECT 0x4D 668c2ecf20Sopenharmony_ci#define TDA10048_IC_MODE 0x4E 678c2ecf20Sopenharmony_ci#define TDA10048_CONF_XO 0x50 688c2ecf20Sopenharmony_ci#define TDA10048_CONF_PLL1 0x51 698c2ecf20Sopenharmony_ci#define TDA10048_CONF_PLL2 0x52 708c2ecf20Sopenharmony_ci#define TDA10048_CONF_PLL3 0x53 718c2ecf20Sopenharmony_ci#define TDA10048_CONF_ADC 0x54 728c2ecf20Sopenharmony_ci#define TDA10048_CONF_ADC_2 0x55 738c2ecf20Sopenharmony_ci#define TDA10048_CONF_C1_1 0x60 748c2ecf20Sopenharmony_ci#define TDA10048_CONF_C1_3 0x62 758c2ecf20Sopenharmony_ci#define TDA10048_AGC_CONF 0x70 768c2ecf20Sopenharmony_ci#define TDA10048_AGC_THRESHOLD_LSB 0x72 778c2ecf20Sopenharmony_ci#define TDA10048_AGC_THRESHOLD_MSB 0x73 788c2ecf20Sopenharmony_ci#define TDA10048_AGC_RENORM 0x74 798c2ecf20Sopenharmony_ci#define TDA10048_AGC_GAINS 0x76 808c2ecf20Sopenharmony_ci#define TDA10048_AGC_TUN_MIN 0x78 818c2ecf20Sopenharmony_ci#define TDA10048_AGC_TUN_MAX 0x79 828c2ecf20Sopenharmony_ci#define TDA10048_AGC_IF_MIN 0x7A 838c2ecf20Sopenharmony_ci#define TDA10048_AGC_IF_MAX 0x7B 848c2ecf20Sopenharmony_ci#define TDA10048_AGC_TUN_LEVEL 0x7E 858c2ecf20Sopenharmony_ci#define TDA10048_AGC_IF_LEVEL 0x7F 868c2ecf20Sopenharmony_ci#define TDA10048_DIG_AGC_LEVEL 0x81 878c2ecf20Sopenharmony_ci#define TDA10048_FREQ_PHY2_LSB 0x86 888c2ecf20Sopenharmony_ci#define TDA10048_FREQ_PHY2_MSB 0x87 898c2ecf20Sopenharmony_ci#define TDA10048_TIME_INVWREF_LSB 0x88 908c2ecf20Sopenharmony_ci#define TDA10048_TIME_INVWREF_MSB 0x89 918c2ecf20Sopenharmony_ci#define TDA10048_TIME_WREF_LSB 0x8A 928c2ecf20Sopenharmony_ci#define TDA10048_TIME_WREF_MID1 0x8B 938c2ecf20Sopenharmony_ci#define TDA10048_TIME_WREF_MID2 0x8C 948c2ecf20Sopenharmony_ci#define TDA10048_TIME_WREF_MSB 0x8D 958c2ecf20Sopenharmony_ci#define TDA10048_NP_OUT 0xA2 968c2ecf20Sopenharmony_ci#define TDA10048_CELL_ID_LSB 0xA4 978c2ecf20Sopenharmony_ci#define TDA10048_CELL_ID_MSB 0xA5 988c2ecf20Sopenharmony_ci#define TDA10048_EXTTPS_ODD 0xAA 998c2ecf20Sopenharmony_ci#define TDA10048_EXTTPS_EVEN 0xAB 1008c2ecf20Sopenharmony_ci#define TDA10048_TPS_LENGTH 0xAC 1018c2ecf20Sopenharmony_ci#define TDA10048_FREE_REG_1 0xB2 1028c2ecf20Sopenharmony_ci#define TDA10048_FREE_REG_2 0xB3 1038c2ecf20Sopenharmony_ci#define TDA10048_CONF_C3_1 0xC0 1048c2ecf20Sopenharmony_ci#define TDA10048_CVBER_CTRL 0xC2 1058c2ecf20Sopenharmony_ci#define TDA10048_CBER_NMAX_LSB 0xC4 1068c2ecf20Sopenharmony_ci#define TDA10048_CBER_NMAX_MSB 0xC5 1078c2ecf20Sopenharmony_ci#define TDA10048_CBER_LSB 0xC6 1088c2ecf20Sopenharmony_ci#define TDA10048_CBER_MSB 0xC7 1098c2ecf20Sopenharmony_ci#define TDA10048_VBER_LSB 0xC8 1108c2ecf20Sopenharmony_ci#define TDA10048_VBER_MID 0xC9 1118c2ecf20Sopenharmony_ci#define TDA10048_VBER_MSB 0xCA 1128c2ecf20Sopenharmony_ci#define TDA10048_CVBER_LUT 0xCC 1138c2ecf20Sopenharmony_ci#define TDA10048_UNCOR_CTRL 0xCD 1148c2ecf20Sopenharmony_ci#define TDA10048_UNCOR_CPT_LSB 0xCE 1158c2ecf20Sopenharmony_ci#define TDA10048_UNCOR_CPT_MSB 0xCF 1168c2ecf20Sopenharmony_ci#define TDA10048_SOFT_IT_C3 0xD6 1178c2ecf20Sopenharmony_ci#define TDA10048_CONF_TS2 0xE0 1188c2ecf20Sopenharmony_ci#define TDA10048_CONF_TS1 0xE1 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic unsigned int debug; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...)\ 1238c2ecf20Sopenharmony_ci do { if (debug >= level)\ 1248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "tda10048: " fmt, ## arg);\ 1258c2ecf20Sopenharmony_ci } while (0) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct tda10048_state { 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* We'll cache and update the attach config settings */ 1328c2ecf20Sopenharmony_ci struct tda10048_config config; 1338c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci int fwloaded; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci u32 freq_if_hz; 1388c2ecf20Sopenharmony_ci u32 xtal_hz; 1398c2ecf20Sopenharmony_ci u32 pll_mfactor; 1408c2ecf20Sopenharmony_ci u32 pll_nfactor; 1418c2ecf20Sopenharmony_ci u32 pll_pfactor; 1428c2ecf20Sopenharmony_ci u32 sample_freq; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci u32 bandwidth; 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic struct init_tab { 1488c2ecf20Sopenharmony_ci u8 reg; 1498c2ecf20Sopenharmony_ci u16 data; 1508c2ecf20Sopenharmony_ci} init_tab[] = { 1518c2ecf20Sopenharmony_ci { TDA10048_CONF_PLL1, 0x08 }, 1528c2ecf20Sopenharmony_ci { TDA10048_CONF_ADC_2, 0x00 }, 1538c2ecf20Sopenharmony_ci { TDA10048_CONF_C4_1, 0x00 }, 1548c2ecf20Sopenharmony_ci { TDA10048_CONF_PLL1, 0x0f }, 1558c2ecf20Sopenharmony_ci { TDA10048_CONF_PLL2, 0x0a }, 1568c2ecf20Sopenharmony_ci { TDA10048_CONF_PLL3, 0x43 }, 1578c2ecf20Sopenharmony_ci { TDA10048_FREQ_PHY2_LSB, 0x02 }, 1588c2ecf20Sopenharmony_ci { TDA10048_FREQ_PHY2_MSB, 0x0a }, 1598c2ecf20Sopenharmony_ci { TDA10048_TIME_WREF_LSB, 0xbd }, 1608c2ecf20Sopenharmony_ci { TDA10048_TIME_WREF_MID1, 0xe4 }, 1618c2ecf20Sopenharmony_ci { TDA10048_TIME_WREF_MID2, 0xa8 }, 1628c2ecf20Sopenharmony_ci { TDA10048_TIME_WREF_MSB, 0x02 }, 1638c2ecf20Sopenharmony_ci { TDA10048_TIME_INVWREF_LSB, 0x04 }, 1648c2ecf20Sopenharmony_ci { TDA10048_TIME_INVWREF_MSB, 0x06 }, 1658c2ecf20Sopenharmony_ci { TDA10048_CONF_C4_1, 0x00 }, 1668c2ecf20Sopenharmony_ci { TDA10048_CONF_C1_1, 0xa8 }, 1678c2ecf20Sopenharmony_ci { TDA10048_AGC_CONF, 0x16 }, 1688c2ecf20Sopenharmony_ci { TDA10048_CONF_C1_3, 0x0b }, 1698c2ecf20Sopenharmony_ci { TDA10048_AGC_TUN_MIN, 0x00 }, 1708c2ecf20Sopenharmony_ci { TDA10048_AGC_TUN_MAX, 0xff }, 1718c2ecf20Sopenharmony_ci { TDA10048_AGC_IF_MIN, 0x00 }, 1728c2ecf20Sopenharmony_ci { TDA10048_AGC_IF_MAX, 0xff }, 1738c2ecf20Sopenharmony_ci { TDA10048_AGC_THRESHOLD_MSB, 0x00 }, 1748c2ecf20Sopenharmony_ci { TDA10048_AGC_THRESHOLD_LSB, 0x70 }, 1758c2ecf20Sopenharmony_ci { TDA10048_CVBER_CTRL, 0x38 }, 1768c2ecf20Sopenharmony_ci { TDA10048_AGC_GAINS, 0x12 }, 1778c2ecf20Sopenharmony_ci { TDA10048_CONF_XO, 0x00 }, 1788c2ecf20Sopenharmony_ci { TDA10048_CONF_TS1, 0x07 }, 1798c2ecf20Sopenharmony_ci { TDA10048_IC_MODE, 0x00 }, 1808c2ecf20Sopenharmony_ci { TDA10048_CONF_TS2, 0xc0 }, 1818c2ecf20Sopenharmony_ci { TDA10048_CONF_TRISTATE1, 0x21 }, 1828c2ecf20Sopenharmony_ci { TDA10048_CONF_TRISTATE2, 0x00 }, 1838c2ecf20Sopenharmony_ci { TDA10048_CONF_POLARITY, 0x00 }, 1848c2ecf20Sopenharmony_ci { TDA10048_CONF_C4_2, 0x04 }, 1858c2ecf20Sopenharmony_ci { TDA10048_CONF_ADC, 0x60 }, 1868c2ecf20Sopenharmony_ci { TDA10048_CONF_ADC_2, 0x10 }, 1878c2ecf20Sopenharmony_ci { TDA10048_CONF_ADC, 0x60 }, 1888c2ecf20Sopenharmony_ci { TDA10048_CONF_ADC_2, 0x00 }, 1898c2ecf20Sopenharmony_ci { TDA10048_CONF_C1_1, 0xa8 }, 1908c2ecf20Sopenharmony_ci { TDA10048_UNCOR_CTRL, 0x00 }, 1918c2ecf20Sopenharmony_ci { TDA10048_CONF_C4_2, 0x04 }, 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic struct pll_tab { 1958c2ecf20Sopenharmony_ci u32 clk_freq_khz; 1968c2ecf20Sopenharmony_ci u32 if_freq_khz; 1978c2ecf20Sopenharmony_ci} pll_tab[] = { 1988c2ecf20Sopenharmony_ci { TDA10048_CLK_4000, TDA10048_IF_36130 }, 1998c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_3300 }, 2008c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_3500 }, 2018c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_3800 }, 2028c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_4000 }, 2038c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_4300 }, 2048c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_4500 }, 2058c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_5000 }, 2068c2ecf20Sopenharmony_ci { TDA10048_CLK_16000, TDA10048_IF_36130 }, 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 2128c2ecf20Sopenharmony_ci int ret; 2138c2ecf20Sopenharmony_ci u8 buf[] = { reg, data }; 2148c2ecf20Sopenharmony_ci struct i2c_msg msg = { 2158c2ecf20Sopenharmony_ci .addr = config->demod_address, 2168c2ecf20Sopenharmony_ci .flags = 0, .buf = buf, .len = 2 }; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (ret != 1) 2238c2ecf20Sopenharmony_ci printk("%s: writereg error (ret == %i)\n", __func__, ret); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return (ret != 1) ? -1 : 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic u8 tda10048_readreg(struct tda10048_state *state, u8 reg) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 2318c2ecf20Sopenharmony_ci int ret; 2328c2ecf20Sopenharmony_ci u8 b0[] = { reg }; 2338c2ecf20Sopenharmony_ci u8 b1[] = { 0 }; 2348c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 2358c2ecf20Sopenharmony_ci { .addr = config->demod_address, 2368c2ecf20Sopenharmony_ci .flags = 0, .buf = b0, .len = 1 }, 2378c2ecf20Sopenharmony_ci { .addr = config->demod_address, 2388c2ecf20Sopenharmony_ci .flags = I2C_M_RD, .buf = b1, .len = 1 } }; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (ret != 2) 2458c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: readreg error (ret == %i)\n", 2468c2ecf20Sopenharmony_ci __func__, ret); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return b1[0]; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int tda10048_writeregbulk(struct tda10048_state *state, u8 reg, 2528c2ecf20Sopenharmony_ci const u8 *data, u16 len) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 2558c2ecf20Sopenharmony_ci int ret = -EREMOTEIO; 2568c2ecf20Sopenharmony_ci struct i2c_msg msg; 2578c2ecf20Sopenharmony_ci u8 *buf; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci buf = kmalloc(len + 1, GFP_KERNEL); 2628c2ecf20Sopenharmony_ci if (buf == NULL) { 2638c2ecf20Sopenharmony_ci ret = -ENOMEM; 2648c2ecf20Sopenharmony_ci goto error; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci *buf = reg; 2688c2ecf20Sopenharmony_ci memcpy(buf + 1, data, len); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci msg.addr = config->demod_address; 2718c2ecf20Sopenharmony_ci msg.flags = 0; 2728c2ecf20Sopenharmony_ci msg.buf = buf; 2738c2ecf20Sopenharmony_ci msg.len = len + 1; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci dprintk(2, "%s(): write len = %d\n", 2768c2ecf20Sopenharmony_ci __func__, msg.len); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 2798c2ecf20Sopenharmony_ci if (ret != 1) { 2808c2ecf20Sopenharmony_ci printk(KERN_ERR "%s(): writereg error err %i\n", 2818c2ecf20Sopenharmony_ci __func__, ret); 2828c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cierror: 2868c2ecf20Sopenharmony_ci kfree(buf); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return ret; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz, 2928c2ecf20Sopenharmony_ci u32 if_hz) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 2958c2ecf20Sopenharmony_ci u64 t; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (sample_freq_hz == 0) 3008c2ecf20Sopenharmony_ci return -EINVAL; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (if_hz < (sample_freq_hz / 2)) { 3038c2ecf20Sopenharmony_ci /* PHY2 = (if2/fs) * 2^15 */ 3048c2ecf20Sopenharmony_ci t = if_hz; 3058c2ecf20Sopenharmony_ci t *= 10; 3068c2ecf20Sopenharmony_ci t *= 32768; 3078c2ecf20Sopenharmony_ci do_div(t, sample_freq_hz); 3088c2ecf20Sopenharmony_ci t += 5; 3098c2ecf20Sopenharmony_ci do_div(t, 10); 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci /* PHY2 = ((IF1-fs)/fs) * 2^15 */ 3128c2ecf20Sopenharmony_ci t = sample_freq_hz - if_hz; 3138c2ecf20Sopenharmony_ci t *= 10; 3148c2ecf20Sopenharmony_ci t *= 32768; 3158c2ecf20Sopenharmony_ci do_div(t, sample_freq_hz); 3168c2ecf20Sopenharmony_ci t += 5; 3178c2ecf20Sopenharmony_ci do_div(t, 10); 3188c2ecf20Sopenharmony_ci t = ~t + 1; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t); 3228c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8)); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz, 3288c2ecf20Sopenharmony_ci u32 bw) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 3318c2ecf20Sopenharmony_ci u64 t, z; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (sample_freq_hz == 0) 3368c2ecf20Sopenharmony_ci return -EINVAL; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* WREF = (B / (7 * fs)) * 2^31 */ 3398c2ecf20Sopenharmony_ci t = bw * 10; 3408c2ecf20Sopenharmony_ci /* avoid warning: this decimal constant is unsigned only in ISO C90 */ 3418c2ecf20Sopenharmony_ci /* t *= 2147483648 on 32bit platforms */ 3428c2ecf20Sopenharmony_ci t *= (2048 * 1024); 3438c2ecf20Sopenharmony_ci t *= 1024; 3448c2ecf20Sopenharmony_ci z = 7 * sample_freq_hz; 3458c2ecf20Sopenharmony_ci do_div(t, z); 3468c2ecf20Sopenharmony_ci t += 5; 3478c2ecf20Sopenharmony_ci do_div(t, 10); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t); 3508c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8)); 3518c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16)); 3528c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24)); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, 3588c2ecf20Sopenharmony_ci u32 bw) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 3618c2ecf20Sopenharmony_ci u64 t; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (sample_freq_hz == 0) 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* INVWREF = ((7 * fs) / B) * 2^5 */ 3698c2ecf20Sopenharmony_ci t = sample_freq_hz; 3708c2ecf20Sopenharmony_ci t *= 7; 3718c2ecf20Sopenharmony_ci t *= 32; 3728c2ecf20Sopenharmony_ci t *= 10; 3738c2ecf20Sopenharmony_ci do_div(t, bw); 3748c2ecf20Sopenharmony_ci t += 5; 3758c2ecf20Sopenharmony_ci do_div(t, 10); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t); 3788c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8)); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int tda10048_set_bandwidth(struct dvb_frontend *fe, 3848c2ecf20Sopenharmony_ci u32 bw) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 3878c2ecf20Sopenharmony_ci dprintk(1, "%s(bw=%d)\n", __func__, bw); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Bandwidth setting may need to be adjusted */ 3908c2ecf20Sopenharmony_ci switch (bw) { 3918c2ecf20Sopenharmony_ci case 6000000: 3928c2ecf20Sopenharmony_ci case 7000000: 3938c2ecf20Sopenharmony_ci case 8000000: 3948c2ecf20Sopenharmony_ci tda10048_set_wref(fe, state->sample_freq, bw); 3958c2ecf20Sopenharmony_ci tda10048_set_invwref(fe, state->sample_freq, bw); 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci default: 3988c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() invalid bandwidth\n", __func__); 3998c2ecf20Sopenharmony_ci return -EINVAL; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci state->bandwidth = bw; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int tda10048_set_if(struct dvb_frontend *fe, u32 bw) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 4108c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 4118c2ecf20Sopenharmony_ci int i; 4128c2ecf20Sopenharmony_ci u32 if_freq_khz; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci dprintk(1, "%s(bw = %d)\n", __func__, bw); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* based on target bandwidth and clk we calculate pll factors */ 4178c2ecf20Sopenharmony_ci switch (bw) { 4188c2ecf20Sopenharmony_ci case 6000000: 4198c2ecf20Sopenharmony_ci if_freq_khz = config->dtv6_if_freq_khz; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci case 7000000: 4228c2ecf20Sopenharmony_ci if_freq_khz = config->dtv7_if_freq_khz; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci case 8000000: 4258c2ecf20Sopenharmony_ci if_freq_khz = config->dtv8_if_freq_khz; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci default: 4288c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() no default\n", __func__); 4298c2ecf20Sopenharmony_ci return -EINVAL; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pll_tab); i++) { 4338c2ecf20Sopenharmony_ci if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) && 4348c2ecf20Sopenharmony_ci (pll_tab[i].if_freq_khz == if_freq_khz)) { 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci state->freq_if_hz = pll_tab[i].if_freq_khz * 1000; 4378c2ecf20Sopenharmony_ci state->xtal_hz = pll_tab[i].clk_freq_khz * 1000; 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(pll_tab)) { 4428c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() Incorrect attach settings\n", 4438c2ecf20Sopenharmony_ci __func__); 4448c2ecf20Sopenharmony_ci return -EINVAL; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz); 4488c2ecf20Sopenharmony_ci dprintk(1, "- xtal_hz = %d\n", state->xtal_hz); 4498c2ecf20Sopenharmony_ci dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor); 4508c2ecf20Sopenharmony_ci dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor); 4518c2ecf20Sopenharmony_ci dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* Calculate the sample frequency */ 4548c2ecf20Sopenharmony_ci state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45); 4558c2ecf20Sopenharmony_ci state->sample_freq /= (state->pll_nfactor + 1); 4568c2ecf20Sopenharmony_ci state->sample_freq /= (state->pll_pfactor + 4); 4578c2ecf20Sopenharmony_ci dprintk(1, "- sample_freq = %d\n", state->sample_freq); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Update the I/F */ 4608c2ecf20Sopenharmony_ci tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int tda10048_firmware_upload(struct dvb_frontend *fe) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 4688c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 4698c2ecf20Sopenharmony_ci const struct firmware *fw; 4708c2ecf20Sopenharmony_ci int ret; 4718c2ecf20Sopenharmony_ci int pos = 0; 4728c2ecf20Sopenharmony_ci int cnt; 4738c2ecf20Sopenharmony_ci u8 wlen = config->fwbulkwritelen; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50)) 4768c2ecf20Sopenharmony_ci wlen = TDA10048_BULKWRITE_200; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* request the firmware, this will block and timeout */ 4798c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n", 4808c2ecf20Sopenharmony_ci __func__, 4818c2ecf20Sopenharmony_ci TDA10048_DEFAULT_FIRMWARE); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE, 4848c2ecf20Sopenharmony_ci state->i2c->dev.parent); 4858c2ecf20Sopenharmony_ci if (ret) { 4868c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Upload failed. (file not found?)\n", 4878c2ecf20Sopenharmony_ci __func__); 4888c2ecf20Sopenharmony_ci return -EIO; 4898c2ecf20Sopenharmony_ci } else { 4908c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: firmware read %zu bytes.\n", 4918c2ecf20Sopenharmony_ci __func__, 4928c2ecf20Sopenharmony_ci fw->size); 4938c2ecf20Sopenharmony_ci ret = 0; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) { 4978c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: firmware incorrect size\n", __func__); 4988c2ecf20Sopenharmony_ci ret = -EIO; 4998c2ecf20Sopenharmony_ci } else { 5008c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: firmware uploading\n", __func__); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Soft reset */ 5038c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 5048c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_TRISTATE1) 5058c2ecf20Sopenharmony_ci & 0xfe); 5068c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 5078c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_TRISTATE1) 5088c2ecf20Sopenharmony_ci | 0x01); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* Put the demod into host download mode */ 5118c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_C4_1, 5128c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* Boot the DSP */ 5158c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_C4_1, 5168c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Prepare for download */ 5198c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* Download the firmware payload */ 5228c2ecf20Sopenharmony_ci while (pos < fw->size) { 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if ((fw->size - pos) > wlen) 5258c2ecf20Sopenharmony_ci cnt = wlen; 5268c2ecf20Sopenharmony_ci else 5278c2ecf20Sopenharmony_ci cnt = fw->size - pos; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN, 5308c2ecf20Sopenharmony_ci &fw->data[pos], cnt); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci pos += cnt; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ret = -EIO; 5368c2ecf20Sopenharmony_ci /* Wait up to 250ms for the DSP to boot */ 5378c2ecf20Sopenharmony_ci for (cnt = 0; cnt < 250 ; cnt += 10) { 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci msleep(10); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (tda10048_readreg(state, TDA10048_SYNC_STATUS) 5428c2ecf20Sopenharmony_ci & 0x40) { 5438c2ecf20Sopenharmony_ci ret = 0; 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci release_firmware(fw); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (ret == 0) { 5528c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: firmware uploaded\n", __func__); 5538c2ecf20Sopenharmony_ci state->fwloaded = 1; 5548c2ecf20Sopenharmony_ci } else 5558c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: firmware upload failed\n", __func__); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return ret; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int tda10048_set_inversion(struct dvb_frontend *fe, int inversion) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci dprintk(1, "%s(%d)\n", __func__, inversion); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (inversion == TDA10048_INVERSION_ON) 5678c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_C1_1, 5688c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20); 5698c2ecf20Sopenharmony_ci else 5708c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_C1_1, 5718c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/* Retrieve the demod settings */ 5778c2ecf20Sopenharmony_cistatic int tda10048_get_tps(struct tda10048_state *state, 5788c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci u8 val; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Make sure the TPS regs are valid */ 5838c2ecf20Sopenharmony_ci if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01)) 5848c2ecf20Sopenharmony_ci return -EAGAIN; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci val = tda10048_readreg(state, TDA10048_OUT_CONF2); 5878c2ecf20Sopenharmony_ci switch ((val & 0x60) >> 5) { 5888c2ecf20Sopenharmony_ci case 0: 5898c2ecf20Sopenharmony_ci p->modulation = QPSK; 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci case 1: 5928c2ecf20Sopenharmony_ci p->modulation = QAM_16; 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci case 2: 5958c2ecf20Sopenharmony_ci p->modulation = QAM_64; 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci switch ((val & 0x18) >> 3) { 5998c2ecf20Sopenharmony_ci case 0: 6008c2ecf20Sopenharmony_ci p->hierarchy = HIERARCHY_NONE; 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci case 1: 6038c2ecf20Sopenharmony_ci p->hierarchy = HIERARCHY_1; 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci case 2: 6068c2ecf20Sopenharmony_ci p->hierarchy = HIERARCHY_2; 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci case 3: 6098c2ecf20Sopenharmony_ci p->hierarchy = HIERARCHY_4; 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci switch (val & 0x07) { 6138c2ecf20Sopenharmony_ci case 0: 6148c2ecf20Sopenharmony_ci p->code_rate_HP = FEC_1_2; 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci case 1: 6178c2ecf20Sopenharmony_ci p->code_rate_HP = FEC_2_3; 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci case 2: 6208c2ecf20Sopenharmony_ci p->code_rate_HP = FEC_3_4; 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci case 3: 6238c2ecf20Sopenharmony_ci p->code_rate_HP = FEC_5_6; 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci case 4: 6268c2ecf20Sopenharmony_ci p->code_rate_HP = FEC_7_8; 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci val = tda10048_readreg(state, TDA10048_OUT_CONF3); 6318c2ecf20Sopenharmony_ci switch (val & 0x07) { 6328c2ecf20Sopenharmony_ci case 0: 6338c2ecf20Sopenharmony_ci p->code_rate_LP = FEC_1_2; 6348c2ecf20Sopenharmony_ci break; 6358c2ecf20Sopenharmony_ci case 1: 6368c2ecf20Sopenharmony_ci p->code_rate_LP = FEC_2_3; 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci case 2: 6398c2ecf20Sopenharmony_ci p->code_rate_LP = FEC_3_4; 6408c2ecf20Sopenharmony_ci break; 6418c2ecf20Sopenharmony_ci case 3: 6428c2ecf20Sopenharmony_ci p->code_rate_LP = FEC_5_6; 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci case 4: 6458c2ecf20Sopenharmony_ci p->code_rate_LP = FEC_7_8; 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci val = tda10048_readreg(state, TDA10048_OUT_CONF1); 6508c2ecf20Sopenharmony_ci switch ((val & 0x0c) >> 2) { 6518c2ecf20Sopenharmony_ci case 0: 6528c2ecf20Sopenharmony_ci p->guard_interval = GUARD_INTERVAL_1_32; 6538c2ecf20Sopenharmony_ci break; 6548c2ecf20Sopenharmony_ci case 1: 6558c2ecf20Sopenharmony_ci p->guard_interval = GUARD_INTERVAL_1_16; 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci case 2: 6588c2ecf20Sopenharmony_ci p->guard_interval = GUARD_INTERVAL_1_8; 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci case 3: 6618c2ecf20Sopenharmony_ci p->guard_interval = GUARD_INTERVAL_1_4; 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci switch (val & 0x03) { 6658c2ecf20Sopenharmony_ci case 0: 6668c2ecf20Sopenharmony_ci p->transmission_mode = TRANSMISSION_MODE_2K; 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci case 1: 6698c2ecf20Sopenharmony_ci p->transmission_mode = TRANSMISSION_MODE_8K; 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 6798c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 6808c2ecf20Sopenharmony_ci dprintk(1, "%s(%d)\n", __func__, enable); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (config->disable_gate_access) 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (enable) 6868c2ecf20Sopenharmony_ci return tda10048_writereg(state, TDA10048_CONF_C4_1, 6878c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02); 6888c2ecf20Sopenharmony_ci else 6898c2ecf20Sopenharmony_ci return tda10048_writereg(state, TDA10048_CONF_C4_1, 6908c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int tda10048_output_mode(struct dvb_frontend *fe, int serial) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 6968c2ecf20Sopenharmony_ci dprintk(1, "%s(%d)\n", __func__, serial); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* Ensure pins are out of tri-state */ 6998c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21); 7008c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (serial) { 7038c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20); 7048c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0); 7058c2ecf20Sopenharmony_ci } else { 7068c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_IC_MODE, 0x00); 7078c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CONF_TS2, 0x01); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ 7148c2ecf20Sopenharmony_ci/* TODO: Support manual tuning with specific params */ 7158c2ecf20Sopenharmony_cistatic int tda10048_set_frontend(struct dvb_frontend *fe) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 7188c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* Update the I/F pll's if the bandwidth changes */ 7238c2ecf20Sopenharmony_ci if (p->bandwidth_hz != state->bandwidth) { 7248c2ecf20Sopenharmony_ci tda10048_set_if(fe, p->bandwidth_hz); 7258c2ecf20Sopenharmony_ci tda10048_set_bandwidth(fe, p->bandwidth_hz); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 7318c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 7368c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* Enable demod TPS auto detection and begin acquisition */ 7408c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_AUTO, 0x57); 7418c2ecf20Sopenharmony_ci /* trigger cber and vber acquisition */ 7428c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return 0; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci/* Establish sane defaults and load firmware. */ 7488c2ecf20Sopenharmony_cistatic int tda10048_init(struct dvb_frontend *fe) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 7518c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 7528c2ecf20Sopenharmony_ci int ret = 0, i; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* PLL */ 7578c2ecf20Sopenharmony_ci init_tab[4].data = (u8)(state->pll_mfactor); 7588c2ecf20Sopenharmony_ci init_tab[5].data = (u8)(state->pll_nfactor) | 0x40; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* Apply register defaults */ 7618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_tab); i++) 7628c2ecf20Sopenharmony_ci tda10048_writereg(state, init_tab[i].reg, init_tab[i].data); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (state->fwloaded == 0) 7658c2ecf20Sopenharmony_ci ret = tda10048_firmware_upload(fe); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* Set either serial or parallel */ 7688c2ecf20Sopenharmony_ci tda10048_output_mode(fe, config->output_mode); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Set inversion */ 7718c2ecf20Sopenharmony_ci tda10048_set_inversion(fe, config->inversion); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* Establish default RF values */ 7748c2ecf20Sopenharmony_ci tda10048_set_if(fe, 8000000); 7758c2ecf20Sopenharmony_ci tda10048_set_bandwidth(fe, 8000000); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* Ensure we leave the gate closed */ 7788c2ecf20Sopenharmony_ci tda10048_i2c_gate_ctrl(fe, 0); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return ret; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int tda10048_read_status(struct dvb_frontend *fe, enum fe_status *status) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 7868c2ecf20Sopenharmony_ci u8 reg; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci *status = 0; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci reg = tda10048_readreg(state, TDA10048_SYNC_STATUS); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci dprintk(1, "%s() status =0x%02x\n", __func__, reg); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (reg & 0x02) 7958c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (reg & 0x04) 7988c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (reg & 0x08) { 8018c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 8028c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI; 8038c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return 0; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 8128c2ecf20Sopenharmony_ci static u32 cber_current; 8138c2ecf20Sopenharmony_ci u32 cber_nmax; 8148c2ecf20Sopenharmony_ci u64 cber_tmp; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* update cber on interrupt */ 8198c2ecf20Sopenharmony_ci if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) { 8208c2ecf20Sopenharmony_ci cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 | 8218c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CBER_LSB); 8228c2ecf20Sopenharmony_ci cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 | 8238c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_CBER_NMAX_LSB); 8248c2ecf20Sopenharmony_ci cber_tmp *= 100000000; 8258c2ecf20Sopenharmony_ci cber_tmp *= 2; 8268c2ecf20Sopenharmony_ci cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1); 8278c2ecf20Sopenharmony_ci cber_current = (u32)cber_tmp; 8288c2ecf20Sopenharmony_ci /* retrigger cber acquisition */ 8298c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39); 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci /* actual cber is (*ber)/1e8 */ 8328c2ecf20Sopenharmony_ci *ber = cber_current; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return 0; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int tda10048_read_signal_strength(struct dvb_frontend *fe, 8388c2ecf20Sopenharmony_ci u16 *signal_strength) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 8418c2ecf20Sopenharmony_ci u8 v; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci *signal_strength = 65535; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci v = tda10048_readreg(state, TDA10048_NP_OUT); 8488c2ecf20Sopenharmony_ci if (v > 0) 8498c2ecf20Sopenharmony_ci *signal_strength -= (v << 8) | v; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci return 0; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci/* SNR lookup table */ 8558c2ecf20Sopenharmony_cistatic struct snr_tab { 8568c2ecf20Sopenharmony_ci u8 val; 8578c2ecf20Sopenharmony_ci u8 data; 8588c2ecf20Sopenharmony_ci} snr_tab[] = { 8598c2ecf20Sopenharmony_ci { 0, 0 }, 8608c2ecf20Sopenharmony_ci { 1, 246 }, 8618c2ecf20Sopenharmony_ci { 2, 215 }, 8628c2ecf20Sopenharmony_ci { 3, 198 }, 8638c2ecf20Sopenharmony_ci { 4, 185 }, 8648c2ecf20Sopenharmony_ci { 5, 176 }, 8658c2ecf20Sopenharmony_ci { 6, 168 }, 8668c2ecf20Sopenharmony_ci { 7, 161 }, 8678c2ecf20Sopenharmony_ci { 8, 155 }, 8688c2ecf20Sopenharmony_ci { 9, 150 }, 8698c2ecf20Sopenharmony_ci { 10, 146 }, 8708c2ecf20Sopenharmony_ci { 11, 141 }, 8718c2ecf20Sopenharmony_ci { 12, 138 }, 8728c2ecf20Sopenharmony_ci { 13, 134 }, 8738c2ecf20Sopenharmony_ci { 14, 131 }, 8748c2ecf20Sopenharmony_ci { 15, 128 }, 8758c2ecf20Sopenharmony_ci { 16, 125 }, 8768c2ecf20Sopenharmony_ci { 17, 122 }, 8778c2ecf20Sopenharmony_ci { 18, 120 }, 8788c2ecf20Sopenharmony_ci { 19, 118 }, 8798c2ecf20Sopenharmony_ci { 20, 115 }, 8808c2ecf20Sopenharmony_ci { 21, 113 }, 8818c2ecf20Sopenharmony_ci { 22, 111 }, 8828c2ecf20Sopenharmony_ci { 23, 109 }, 8838c2ecf20Sopenharmony_ci { 24, 107 }, 8848c2ecf20Sopenharmony_ci { 25, 106 }, 8858c2ecf20Sopenharmony_ci { 26, 104 }, 8868c2ecf20Sopenharmony_ci { 27, 102 }, 8878c2ecf20Sopenharmony_ci { 28, 101 }, 8888c2ecf20Sopenharmony_ci { 29, 99 }, 8898c2ecf20Sopenharmony_ci { 30, 98 }, 8908c2ecf20Sopenharmony_ci { 31, 96 }, 8918c2ecf20Sopenharmony_ci { 32, 95 }, 8928c2ecf20Sopenharmony_ci { 33, 94 }, 8938c2ecf20Sopenharmony_ci { 34, 92 }, 8948c2ecf20Sopenharmony_ci { 35, 91 }, 8958c2ecf20Sopenharmony_ci { 36, 90 }, 8968c2ecf20Sopenharmony_ci { 37, 89 }, 8978c2ecf20Sopenharmony_ci { 38, 88 }, 8988c2ecf20Sopenharmony_ci { 39, 86 }, 8998c2ecf20Sopenharmony_ci { 40, 85 }, 9008c2ecf20Sopenharmony_ci { 41, 84 }, 9018c2ecf20Sopenharmony_ci { 42, 83 }, 9028c2ecf20Sopenharmony_ci { 43, 82 }, 9038c2ecf20Sopenharmony_ci { 44, 81 }, 9048c2ecf20Sopenharmony_ci { 45, 80 }, 9058c2ecf20Sopenharmony_ci { 46, 79 }, 9068c2ecf20Sopenharmony_ci { 47, 78 }, 9078c2ecf20Sopenharmony_ci { 48, 77 }, 9088c2ecf20Sopenharmony_ci { 49, 76 }, 9098c2ecf20Sopenharmony_ci { 50, 76 }, 9108c2ecf20Sopenharmony_ci { 51, 75 }, 9118c2ecf20Sopenharmony_ci { 52, 74 }, 9128c2ecf20Sopenharmony_ci { 53, 73 }, 9138c2ecf20Sopenharmony_ci { 54, 72 }, 9148c2ecf20Sopenharmony_ci { 56, 71 }, 9158c2ecf20Sopenharmony_ci { 57, 70 }, 9168c2ecf20Sopenharmony_ci { 58, 69 }, 9178c2ecf20Sopenharmony_ci { 60, 68 }, 9188c2ecf20Sopenharmony_ci { 61, 67 }, 9198c2ecf20Sopenharmony_ci { 63, 66 }, 9208c2ecf20Sopenharmony_ci { 64, 65 }, 9218c2ecf20Sopenharmony_ci { 66, 64 }, 9228c2ecf20Sopenharmony_ci { 67, 63 }, 9238c2ecf20Sopenharmony_ci { 68, 62 }, 9248c2ecf20Sopenharmony_ci { 69, 62 }, 9258c2ecf20Sopenharmony_ci { 70, 61 }, 9268c2ecf20Sopenharmony_ci { 72, 60 }, 9278c2ecf20Sopenharmony_ci { 74, 59 }, 9288c2ecf20Sopenharmony_ci { 75, 58 }, 9298c2ecf20Sopenharmony_ci { 77, 57 }, 9308c2ecf20Sopenharmony_ci { 79, 56 }, 9318c2ecf20Sopenharmony_ci { 81, 55 }, 9328c2ecf20Sopenharmony_ci { 83, 54 }, 9338c2ecf20Sopenharmony_ci { 85, 53 }, 9348c2ecf20Sopenharmony_ci { 87, 52 }, 9358c2ecf20Sopenharmony_ci { 89, 51 }, 9368c2ecf20Sopenharmony_ci { 91, 50 }, 9378c2ecf20Sopenharmony_ci { 93, 49 }, 9388c2ecf20Sopenharmony_ci { 95, 48 }, 9398c2ecf20Sopenharmony_ci { 97, 47 }, 9408c2ecf20Sopenharmony_ci { 100, 46 }, 9418c2ecf20Sopenharmony_ci { 102, 45 }, 9428c2ecf20Sopenharmony_ci { 104, 44 }, 9438c2ecf20Sopenharmony_ci { 107, 43 }, 9448c2ecf20Sopenharmony_ci { 109, 42 }, 9458c2ecf20Sopenharmony_ci { 112, 41 }, 9468c2ecf20Sopenharmony_ci { 114, 40 }, 9478c2ecf20Sopenharmony_ci { 117, 39 }, 9488c2ecf20Sopenharmony_ci { 120, 38 }, 9498c2ecf20Sopenharmony_ci { 123, 37 }, 9508c2ecf20Sopenharmony_ci { 125, 36 }, 9518c2ecf20Sopenharmony_ci { 128, 35 }, 9528c2ecf20Sopenharmony_ci { 131, 34 }, 9538c2ecf20Sopenharmony_ci { 134, 33 }, 9548c2ecf20Sopenharmony_ci { 138, 32 }, 9558c2ecf20Sopenharmony_ci { 141, 31 }, 9568c2ecf20Sopenharmony_ci { 144, 30 }, 9578c2ecf20Sopenharmony_ci { 147, 29 }, 9588c2ecf20Sopenharmony_ci { 151, 28 }, 9598c2ecf20Sopenharmony_ci { 154, 27 }, 9608c2ecf20Sopenharmony_ci { 158, 26 }, 9618c2ecf20Sopenharmony_ci { 162, 25 }, 9628c2ecf20Sopenharmony_ci { 165, 24 }, 9638c2ecf20Sopenharmony_ci { 169, 23 }, 9648c2ecf20Sopenharmony_ci { 173, 22 }, 9658c2ecf20Sopenharmony_ci { 177, 21 }, 9668c2ecf20Sopenharmony_ci { 181, 20 }, 9678c2ecf20Sopenharmony_ci { 186, 19 }, 9688c2ecf20Sopenharmony_ci { 190, 18 }, 9698c2ecf20Sopenharmony_ci { 194, 17 }, 9708c2ecf20Sopenharmony_ci { 199, 16 }, 9718c2ecf20Sopenharmony_ci { 204, 15 }, 9728c2ecf20Sopenharmony_ci { 208, 14 }, 9738c2ecf20Sopenharmony_ci { 213, 13 }, 9748c2ecf20Sopenharmony_ci { 218, 12 }, 9758c2ecf20Sopenharmony_ci { 223, 11 }, 9768c2ecf20Sopenharmony_ci { 229, 10 }, 9778c2ecf20Sopenharmony_ci { 234, 9 }, 9788c2ecf20Sopenharmony_ci { 239, 8 }, 9798c2ecf20Sopenharmony_ci { 245, 7 }, 9808c2ecf20Sopenharmony_ci { 251, 6 }, 9818c2ecf20Sopenharmony_ci { 255, 5 }, 9828c2ecf20Sopenharmony_ci}; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 9878c2ecf20Sopenharmony_ci u8 v; 9888c2ecf20Sopenharmony_ci int i, ret = -EINVAL; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci v = tda10048_readreg(state, TDA10048_NP_OUT); 9938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snr_tab); i++) { 9948c2ecf20Sopenharmony_ci if (v <= snr_tab[i].val) { 9958c2ecf20Sopenharmony_ci *snr = snr_tab[i].data; 9968c2ecf20Sopenharmony_ci ret = 0; 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return ret; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci *ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 | 10118c2ecf20Sopenharmony_ci tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB); 10128c2ecf20Sopenharmony_ci /* clear the uncorrected TS packets counter when saturated */ 10138c2ecf20Sopenharmony_ci if (*ucblocks == 0xFFFF) 10148c2ecf20Sopenharmony_ci tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci return 0; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic int tda10048_get_frontend(struct dvb_frontend *fe, 10208c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1) 10278c2ecf20Sopenharmony_ci & 0x20 ? INVERSION_ON : INVERSION_OFF; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return tda10048_get_tps(state, p); 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic int tda10048_get_tune_settings(struct dvb_frontend *fe, 10338c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings *tune) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci tune->min_delay_ms = 1000; 10368c2ecf20Sopenharmony_ci return 0; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic void tda10048_release(struct dvb_frontend *fe) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 10428c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10438c2ecf20Sopenharmony_ci kfree(state); 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic void tda10048_establish_defaults(struct dvb_frontend *fe) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct tda10048_state *state = fe->demodulator_priv; 10498c2ecf20Sopenharmony_ci struct tda10048_config *config = &state->config; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* Validate/default the config */ 10528c2ecf20Sopenharmony_ci if (config->dtv6_if_freq_khz == 0) { 10538c2ecf20Sopenharmony_ci config->dtv6_if_freq_khz = TDA10048_IF_4300; 10548c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz is not set (defaulting to %d)\n", 10558c2ecf20Sopenharmony_ci __func__, 10568c2ecf20Sopenharmony_ci config->dtv6_if_freq_khz); 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (config->dtv7_if_freq_khz == 0) { 10608c2ecf20Sopenharmony_ci config->dtv7_if_freq_khz = TDA10048_IF_4300; 10618c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz is not set (defaulting to %d)\n", 10628c2ecf20Sopenharmony_ci __func__, 10638c2ecf20Sopenharmony_ci config->dtv7_if_freq_khz); 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (config->dtv8_if_freq_khz == 0) { 10678c2ecf20Sopenharmony_ci config->dtv8_if_freq_khz = TDA10048_IF_4300; 10688c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz is not set (defaulting to %d)\n", 10698c2ecf20Sopenharmony_ci __func__, 10708c2ecf20Sopenharmony_ci config->dtv8_if_freq_khz); 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (config->clk_freq_khz == 0) { 10748c2ecf20Sopenharmony_ci config->clk_freq_khz = TDA10048_CLK_16000; 10758c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz is not set (defaulting to %d)\n", 10768c2ecf20Sopenharmony_ci __func__, 10778c2ecf20Sopenharmony_ci config->clk_freq_khz); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops tda10048_ops; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistruct dvb_frontend *tda10048_attach(const struct tda10048_config *config, 10848c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct tda10048_state *state = NULL; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 10918c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct tda10048_state), GFP_KERNEL); 10928c2ecf20Sopenharmony_ci if (state == NULL) 10938c2ecf20Sopenharmony_ci goto error; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* setup the state and clone the config */ 10968c2ecf20Sopenharmony_ci memcpy(&state->config, config, sizeof(*config)); 10978c2ecf20Sopenharmony_ci state->i2c = i2c; 10988c2ecf20Sopenharmony_ci state->fwloaded = config->no_firmware; 10998c2ecf20Sopenharmony_ci state->bandwidth = 8000000; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* check if the demod is present */ 11028c2ecf20Sopenharmony_ci if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) 11038c2ecf20Sopenharmony_ci goto error; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* create dvb_frontend */ 11068c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &tda10048_ops, 11078c2ecf20Sopenharmony_ci sizeof(struct dvb_frontend_ops)); 11088c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* set pll */ 11118c2ecf20Sopenharmony_ci if (config->set_pll) { 11128c2ecf20Sopenharmony_ci state->pll_mfactor = config->pll_m; 11138c2ecf20Sopenharmony_ci state->pll_nfactor = config->pll_n; 11148c2ecf20Sopenharmony_ci state->pll_pfactor = config->pll_p; 11158c2ecf20Sopenharmony_ci } else { 11168c2ecf20Sopenharmony_ci state->pll_mfactor = 10; 11178c2ecf20Sopenharmony_ci state->pll_nfactor = 3; 11188c2ecf20Sopenharmony_ci state->pll_pfactor = 0; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* Establish any defaults the the user didn't pass */ 11228c2ecf20Sopenharmony_ci tda10048_establish_defaults(&state->frontend); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci /* Set the xtal and freq defaults */ 11258c2ecf20Sopenharmony_ci if (tda10048_set_if(&state->frontend, 8000000) != 0) 11268c2ecf20Sopenharmony_ci goto error; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* Default bandwidth */ 11298c2ecf20Sopenharmony_ci if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0) 11308c2ecf20Sopenharmony_ci goto error; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* Leave the gate closed */ 11338c2ecf20Sopenharmony_ci tda10048_i2c_gate_ctrl(&state->frontend, 0); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci return &state->frontend; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cierror: 11388c2ecf20Sopenharmony_ci kfree(state); 11398c2ecf20Sopenharmony_ci return NULL; 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tda10048_attach); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops tda10048_ops = { 11448c2ecf20Sopenharmony_ci .delsys = { SYS_DVBT }, 11458c2ecf20Sopenharmony_ci .info = { 11468c2ecf20Sopenharmony_ci .name = "NXP TDA10048HN DVB-T", 11478c2ecf20Sopenharmony_ci .frequency_min_hz = 177 * MHz, 11488c2ecf20Sopenharmony_ci .frequency_max_hz = 858 * MHz, 11498c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 166666, 11508c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 11518c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 11528c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 11538c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | 11548c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER 11558c2ecf20Sopenharmony_ci }, 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci .release = tda10048_release, 11588c2ecf20Sopenharmony_ci .init = tda10048_init, 11598c2ecf20Sopenharmony_ci .i2c_gate_ctrl = tda10048_i2c_gate_ctrl, 11608c2ecf20Sopenharmony_ci .set_frontend = tda10048_set_frontend, 11618c2ecf20Sopenharmony_ci .get_frontend = tda10048_get_frontend, 11628c2ecf20Sopenharmony_ci .get_tune_settings = tda10048_get_tune_settings, 11638c2ecf20Sopenharmony_ci .read_status = tda10048_read_status, 11648c2ecf20Sopenharmony_ci .read_ber = tda10048_read_ber, 11658c2ecf20Sopenharmony_ci .read_signal_strength = tda10048_read_signal_strength, 11668c2ecf20Sopenharmony_ci .read_snr = tda10048_read_snr, 11678c2ecf20Sopenharmony_ci .read_ucblocks = tda10048_read_ucblocks, 11688c2ecf20Sopenharmony_ci}; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 11718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Enable verbose debug messages"); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver"); 11748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steven Toth"); 11758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1176