18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci /* 38c2ecf20Sopenharmony_ci Driver for Philips tda10086 DVBS Demodulator 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci (c) 2006 Andrew de Quincey 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 188c2ecf20Sopenharmony_ci#include "tda10086.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define SACLK 96000000U 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct tda10086_state { 238c2ecf20Sopenharmony_ci struct i2c_adapter* i2c; 248c2ecf20Sopenharmony_ci const struct tda10086_config* config; 258c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* private demod data */ 288c2ecf20Sopenharmony_ci u32 frequency; 298c2ecf20Sopenharmony_ci u32 symbol_rate; 308c2ecf20Sopenharmony_ci bool has_lock; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int debug; 348c2ecf20Sopenharmony_ci#define dprintk(args...) \ 358c2ecf20Sopenharmony_ci do { \ 368c2ecf20Sopenharmony_ci if (debug) printk(KERN_DEBUG "tda10086: " args); \ 378c2ecf20Sopenharmony_ci } while (0) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int tda10086_write_byte(struct tda10086_state *state, int reg, int data) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci int ret; 428c2ecf20Sopenharmony_ci u8 b0[] = { reg, data }; 438c2ecf20Sopenharmony_ci struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 }; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci msg.addr = state->config->demod_address; 468c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (ret != 1) 498c2ecf20Sopenharmony_ci dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", 508c2ecf20Sopenharmony_ci __func__, reg, data, ret); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return (ret != 1) ? ret : 0; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int tda10086_read_byte(struct tda10086_state *state, int reg) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci int ret; 588c2ecf20Sopenharmony_ci u8 b0[] = { reg }; 598c2ecf20Sopenharmony_ci u8 b1[] = { 0 }; 608c2ecf20Sopenharmony_ci struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 }, 618c2ecf20Sopenharmony_ci { .flags = I2C_M_RD, .buf = b1, .len = 1 }}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci msg[0].addr = state->config->demod_address; 648c2ecf20Sopenharmony_ci msg[1].addr = state->config->demod_address; 658c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (ret != 2) { 688c2ecf20Sopenharmony_ci dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, 698c2ecf20Sopenharmony_ci ret); 708c2ecf20Sopenharmony_ci return ret; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return b1[0]; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci int val; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* read a byte and check */ 818c2ecf20Sopenharmony_ci val = tda10086_read_byte(state, reg); 828c2ecf20Sopenharmony_ci if (val < 0) 838c2ecf20Sopenharmony_ci return val; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* mask if off */ 868c2ecf20Sopenharmony_ci val = val & ~mask; 878c2ecf20Sopenharmony_ci val |= data & 0xff; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* write it out again */ 908c2ecf20Sopenharmony_ci return tda10086_write_byte(state, reg, val); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int tda10086_init(struct dvb_frontend* fe) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 968c2ecf20Sopenharmony_ci u8 t22k_off = 0x80; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (state->config->diseqc_tone) 1018c2ecf20Sopenharmony_ci t22k_off = 0; 1028c2ecf20Sopenharmony_ci /* reset */ 1038c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x00, 0x00); 1048c2ecf20Sopenharmony_ci msleep(10); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* misc setup */ 1078c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x01, 0x94); 1088c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x02, 0x35); /* NOTE: TT drivers appear to disable CSWP */ 1098c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x03, 0xe4); 1108c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x04, 0x43); 1118c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x0c, 0x0c); 1128c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x1b, 0xb0); /* noise threshold */ 1138c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x20, 0x89); /* misc */ 1148c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x30, 0x04); /* acquisition period length */ 1158c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x32, 0x00); /* irq off */ 1168c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x31, 0x56); /* setup AFC */ 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* setup PLL (this assumes SACLK = 96MHz) */ 1198c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x55, 0x2c); /* misc PLL setup */ 1208c2ecf20Sopenharmony_ci if (state->config->xtal_freq == TDA10086_XTAL_16M) { 1218c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3a, 0x0b); /* M=12 */ 1228c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3b, 0x01); /* P=2 */ 1238c2ecf20Sopenharmony_ci } else { 1248c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3a, 0x17); /* M=24 */ 1258c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3b, 0x00); /* P=1 */ 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x55, 0x20, 0x00); /* powerup PLL */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* setup TS interface */ 1308c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x11, 0x81); 1318c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x12, 0x81); 1328c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x19, 0x40); /* parallel mode A + MSBFIRST */ 1338c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x56, 0x80); /* powerdown WPLL - unused in the mode we use */ 1348c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x57, 0x08); /* bypass WPLL - unused in the mode we use */ 1358c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x10, 0x2a); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* setup ADC */ 1388c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x58, 0x61); /* ADC setup */ 1398c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x58, 0x01, 0x00); /* powerup ADC */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* setup AGC */ 1428c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x05, 0x0B); 1438c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x37, 0x63); 1448c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3f, 0x0a); /* NOTE: flydvb varies it */ 1458c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x40, 0x64); 1468c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x41, 0x4f); 1478c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x42, 0x43); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* setup viterbi */ 1508c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x1a, 0x11); /* VBER 10^6, DVB, QPSK */ 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* setup carrier recovery */ 1538c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3d, 0x80); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* setup SEC */ 1568c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, t22k_off); /* all SEC off, 22k tone */ 1578c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); 1588c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void tda10086_diseqc_wait(struct tda10086_state *state) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(200); 1668c2ecf20Sopenharmony_ci while (!(tda10086_read_byte(state, 0x50) & 0x01)) { 1678c2ecf20Sopenharmony_ci if(time_after(jiffies, timeout)) { 1688c2ecf20Sopenharmony_ci printk("%s: diseqc queue not ready, command may be lost.\n", __func__); 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci msleep(10); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int tda10086_set_tone(struct dvb_frontend *fe, 1768c2ecf20Sopenharmony_ci enum fe_sec_tone_mode tone) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 1798c2ecf20Sopenharmony_ci u8 t22k_off = 0x80; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (state->config->diseqc_tone) 1848c2ecf20Sopenharmony_ci t22k_off = 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci switch (tone) { 1878c2ecf20Sopenharmony_ci case SEC_TONE_OFF: 1888c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, t22k_off); 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci case SEC_TONE_ON: 1928c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, 0x01 + t22k_off); 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int tda10086_send_master_cmd (struct dvb_frontend* fe, 2008c2ecf20Sopenharmony_ci struct dvb_diseqc_master_cmd* cmd) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 2038c2ecf20Sopenharmony_ci int i; 2048c2ecf20Sopenharmony_ci u8 oldval; 2058c2ecf20Sopenharmony_ci u8 t22k_off = 0x80; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (state->config->diseqc_tone) 2108c2ecf20Sopenharmony_ci t22k_off = 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (cmd->msg_len > 6) 2138c2ecf20Sopenharmony_ci return -EINVAL; 2148c2ecf20Sopenharmony_ci oldval = tda10086_read_byte(state, 0x36); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci for(i=0; i< cmd->msg_len; i++) { 2178c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x48+i, cmd->msg[i]); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, (0x08 + t22k_off) 2208c2ecf20Sopenharmony_ci | ((cmd->msg_len - 1) << 4)); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci tda10086_diseqc_wait(state); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, oldval); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int tda10086_send_burst(struct dvb_frontend *fe, 2308c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd minicmd) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 2338c2ecf20Sopenharmony_ci u8 oldval = tda10086_read_byte(state, 0x36); 2348c2ecf20Sopenharmony_ci u8 t22k_off = 0x80; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (state->config->diseqc_tone) 2398c2ecf20Sopenharmony_ci t22k_off = 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci switch(minicmd) { 2428c2ecf20Sopenharmony_ci case SEC_MINI_A: 2438c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, 0x04 + t22k_off); 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci case SEC_MINI_B: 2478c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, 0x06 + t22k_off); 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci tda10086_diseqc_wait(state); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x36, oldval); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int tda10086_set_inversion(struct tda10086_state *state, 2598c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fe_params) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci u8 invval = 0x80; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dprintk ("%s %i %i\n", __func__, fe_params->inversion, state->config->invert); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci switch(fe_params->inversion) { 2668c2ecf20Sopenharmony_ci case INVERSION_OFF: 2678c2ecf20Sopenharmony_ci if (state->config->invert) 2688c2ecf20Sopenharmony_ci invval = 0x40; 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case INVERSION_ON: 2718c2ecf20Sopenharmony_ci if (!state->config->invert) 2728c2ecf20Sopenharmony_ci invval = 0x40; 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci case INVERSION_AUTO: 2758c2ecf20Sopenharmony_ci invval = 0x00; 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x0c, 0xc0, invval); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int tda10086_set_symbol_rate(struct tda10086_state *state, 2848c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fe_params) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci u8 dfn = 0; 2878c2ecf20Sopenharmony_ci u8 afs = 0; 2888c2ecf20Sopenharmony_ci u8 byp = 0; 2898c2ecf20Sopenharmony_ci u8 reg37 = 0x43; 2908c2ecf20Sopenharmony_ci u8 reg42 = 0x43; 2918c2ecf20Sopenharmony_ci u64 big; 2928c2ecf20Sopenharmony_ci u32 tmp; 2938c2ecf20Sopenharmony_ci u32 bdr; 2948c2ecf20Sopenharmony_ci u32 bdri; 2958c2ecf20Sopenharmony_ci u32 symbol_rate = fe_params->symbol_rate; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci dprintk ("%s %i\n", __func__, symbol_rate); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* setup the decimation and anti-aliasing filters.. */ 3008c2ecf20Sopenharmony_ci if (symbol_rate < SACLK / 10000 * 137) { 3018c2ecf20Sopenharmony_ci dfn=4; 3028c2ecf20Sopenharmony_ci afs=1; 3038c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 208) { 3048c2ecf20Sopenharmony_ci dfn=4; 3058c2ecf20Sopenharmony_ci afs=0; 3068c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 270) { 3078c2ecf20Sopenharmony_ci dfn=3; 3088c2ecf20Sopenharmony_ci afs=1; 3098c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 416) { 3108c2ecf20Sopenharmony_ci dfn=3; 3118c2ecf20Sopenharmony_ci afs=0; 3128c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 550) { 3138c2ecf20Sopenharmony_ci dfn=2; 3148c2ecf20Sopenharmony_ci afs=1; 3158c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 833) { 3168c2ecf20Sopenharmony_ci dfn=2; 3178c2ecf20Sopenharmony_ci afs=0; 3188c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 1100) { 3198c2ecf20Sopenharmony_ci dfn=1; 3208c2ecf20Sopenharmony_ci afs=1; 3218c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 1666) { 3228c2ecf20Sopenharmony_ci dfn=1; 3238c2ecf20Sopenharmony_ci afs=0; 3248c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 2200) { 3258c2ecf20Sopenharmony_ci dfn=0; 3268c2ecf20Sopenharmony_ci afs=1; 3278c2ecf20Sopenharmony_ci } else if (symbol_rate < SACLK / 10000 * 3333) { 3288c2ecf20Sopenharmony_ci dfn=0; 3298c2ecf20Sopenharmony_ci afs=0; 3308c2ecf20Sopenharmony_ci } else { 3318c2ecf20Sopenharmony_ci reg37 = 0x63; 3328c2ecf20Sopenharmony_ci reg42 = 0x4f; 3338c2ecf20Sopenharmony_ci byp=1; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* calculate BDR */ 3378c2ecf20Sopenharmony_ci big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<<dfn); 3388c2ecf20Sopenharmony_ci big += ((SACLK/1000ULL)-1ULL); 3398c2ecf20Sopenharmony_ci do_div(big, (SACLK/1000ULL)); 3408c2ecf20Sopenharmony_ci bdr = big & 0xfffff; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* calculate BDRI */ 3438c2ecf20Sopenharmony_ci tmp = (1<<dfn)*(symbol_rate/1000); 3448c2ecf20Sopenharmony_ci bdri = ((32 * (SACLK/1000)) + (tmp-1)) / tmp; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x21, (afs << 7) | dfn); 3478c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x20, 0x08, byp << 3); 3488c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x06, bdr); 3498c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x07, bdr >> 8); 3508c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x08, bdr >> 16); 3518c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x09, bdri); 3528c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x37, reg37); 3538c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x42, reg42); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int tda10086_set_fec(struct tda10086_state *state, 3598c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fe_params) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci u8 fecval; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci dprintk("%s %i\n", __func__, fe_params->fec_inner); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci switch (fe_params->fec_inner) { 3668c2ecf20Sopenharmony_ci case FEC_1_2: 3678c2ecf20Sopenharmony_ci fecval = 0x00; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci case FEC_2_3: 3708c2ecf20Sopenharmony_ci fecval = 0x01; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case FEC_3_4: 3738c2ecf20Sopenharmony_ci fecval = 0x02; 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci case FEC_4_5: 3768c2ecf20Sopenharmony_ci fecval = 0x03; 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci case FEC_5_6: 3798c2ecf20Sopenharmony_ci fecval = 0x04; 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci case FEC_6_7: 3828c2ecf20Sopenharmony_ci fecval = 0x05; 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci case FEC_7_8: 3858c2ecf20Sopenharmony_ci fecval = 0x06; 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci case FEC_8_9: 3888c2ecf20Sopenharmony_ci fecval = 0x07; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case FEC_AUTO: 3918c2ecf20Sopenharmony_ci fecval = 0x08; 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci default: 3948c2ecf20Sopenharmony_ci return -1; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x0d, fecval); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int tda10086_set_frontend(struct dvb_frontend *fe) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; 4048c2ecf20Sopenharmony_ci struct tda10086_state *state = fe->demodulator_priv; 4058c2ecf20Sopenharmony_ci int ret; 4068c2ecf20Sopenharmony_ci u32 freq = 0; 4078c2ecf20Sopenharmony_ci int freqoff; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* modify parameters for tuning */ 4128c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x02, 0x35); 4138c2ecf20Sopenharmony_ci state->has_lock = false; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* set params */ 4168c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 4178c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 4188c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4198c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.get_frequency) 4228c2ecf20Sopenharmony_ci fe->ops.tuner_ops.get_frequency(fe, &freq); 4238c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4248c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* calculate the frequency offset (in *Hz* not kHz) */ 4288c2ecf20Sopenharmony_ci freqoff = fe_params->frequency - freq; 4298c2ecf20Sopenharmony_ci freqoff = ((1<<16) * freqoff) / (SACLK/1000); 4308c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f)); 4318c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x3e, freqoff); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if ((ret = tda10086_set_inversion(state, fe_params)) < 0) 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0) 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci if ((ret = tda10086_set_fec(state, fe_params)) < 0) 4388c2ecf20Sopenharmony_ci return ret; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* soft reset + disable TS output until lock */ 4418c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x10, 0x40, 0x40); 4428c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x00, 0x01, 0x00); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci state->symbol_rate = fe_params->symbol_rate; 4458c2ecf20Sopenharmony_ci state->frequency = fe_params->frequency; 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int tda10086_get_frontend(struct dvb_frontend *fe, 4508c2ecf20Sopenharmony_ci struct dtv_frontend_properties *fe_params) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 4538c2ecf20Sopenharmony_ci u8 val; 4548c2ecf20Sopenharmony_ci int tmp; 4558c2ecf20Sopenharmony_ci u64 tmp64; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* check for invalid symbol rate */ 4608c2ecf20Sopenharmony_ci if (fe_params->symbol_rate < 500000) 4618c2ecf20Sopenharmony_ci return -EINVAL; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* calculate the updated frequency (note: we convert from Hz->kHz) */ 4648c2ecf20Sopenharmony_ci tmp64 = ((u64)tda10086_read_byte(state, 0x52) 4658c2ecf20Sopenharmony_ci | (tda10086_read_byte(state, 0x51) << 8)); 4668c2ecf20Sopenharmony_ci if (tmp64 & 0x8000) 4678c2ecf20Sopenharmony_ci tmp64 |= 0xffffffffffff0000ULL; 4688c2ecf20Sopenharmony_ci tmp64 = (tmp64 * (SACLK/1000ULL)); 4698c2ecf20Sopenharmony_ci do_div(tmp64, (1ULL<<15) * (1ULL<<1)); 4708c2ecf20Sopenharmony_ci fe_params->frequency = (int) state->frequency + (int) tmp64; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* the inversion */ 4738c2ecf20Sopenharmony_ci val = tda10086_read_byte(state, 0x0c); 4748c2ecf20Sopenharmony_ci if (val & 0x80) { 4758c2ecf20Sopenharmony_ci switch(val & 0x40) { 4768c2ecf20Sopenharmony_ci case 0x00: 4778c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_OFF; 4788c2ecf20Sopenharmony_ci if (state->config->invert) 4798c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_ON; 4808c2ecf20Sopenharmony_ci break; 4818c2ecf20Sopenharmony_ci default: 4828c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_ON; 4838c2ecf20Sopenharmony_ci if (state->config->invert) 4848c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_OFF; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci } else { 4888c2ecf20Sopenharmony_ci tda10086_read_byte(state, 0x0f); 4898c2ecf20Sopenharmony_ci switch(val & 0x02) { 4908c2ecf20Sopenharmony_ci case 0x00: 4918c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_OFF; 4928c2ecf20Sopenharmony_ci if (state->config->invert) 4938c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_ON; 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci default: 4968c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_ON; 4978c2ecf20Sopenharmony_ci if (state->config->invert) 4988c2ecf20Sopenharmony_ci fe_params->inversion = INVERSION_OFF; 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* calculate the updated symbol rate */ 5048c2ecf20Sopenharmony_ci tmp = tda10086_read_byte(state, 0x1d); 5058c2ecf20Sopenharmony_ci if (tmp & 0x80) 5068c2ecf20Sopenharmony_ci tmp |= 0xffffff00; 5078c2ecf20Sopenharmony_ci tmp = (tmp * 480 * (1<<1)) / 128; 5088c2ecf20Sopenharmony_ci tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000); 5098c2ecf20Sopenharmony_ci fe_params->symbol_rate = state->symbol_rate + tmp; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* the FEC */ 5128c2ecf20Sopenharmony_ci val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4; 5138c2ecf20Sopenharmony_ci switch(val) { 5148c2ecf20Sopenharmony_ci case 0x00: 5158c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_1_2; 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci case 0x01: 5188c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_2_3; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci case 0x02: 5218c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_3_4; 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case 0x03: 5248c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_4_5; 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci case 0x04: 5278c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_5_6; 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case 0x05: 5308c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_6_7; 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci case 0x06: 5338c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_7_8; 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci case 0x07: 5368c2ecf20Sopenharmony_ci fe_params->fec_inner = FEC_8_9; 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int tda10086_read_status(struct dvb_frontend *fe, 5448c2ecf20Sopenharmony_ci enum fe_status *fe_status) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 5478c2ecf20Sopenharmony_ci u8 val; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci val = tda10086_read_byte(state, 0x0e); 5528c2ecf20Sopenharmony_ci *fe_status = 0; 5538c2ecf20Sopenharmony_ci if (val & 0x01) 5548c2ecf20Sopenharmony_ci *fe_status |= FE_HAS_SIGNAL; 5558c2ecf20Sopenharmony_ci if (val & 0x02) 5568c2ecf20Sopenharmony_ci *fe_status |= FE_HAS_CARRIER; 5578c2ecf20Sopenharmony_ci if (val & 0x04) 5588c2ecf20Sopenharmony_ci *fe_status |= FE_HAS_VITERBI; 5598c2ecf20Sopenharmony_ci if (val & 0x08) 5608c2ecf20Sopenharmony_ci *fe_status |= FE_HAS_SYNC; 5618c2ecf20Sopenharmony_ci if (val & 0x10) { 5628c2ecf20Sopenharmony_ci *fe_status |= FE_HAS_LOCK; 5638c2ecf20Sopenharmony_ci if (!state->has_lock) { 5648c2ecf20Sopenharmony_ci state->has_lock = true; 5658c2ecf20Sopenharmony_ci /* modify parameters for stable reception */ 5668c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x02, 0x00); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 5768c2ecf20Sopenharmony_ci u8 _str; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci _str = 0xff - tda10086_read_byte(state, 0x43); 5818c2ecf20Sopenharmony_ci *signal = (_str << 8) | _str; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 5898c2ecf20Sopenharmony_ci u8 _snr; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci _snr = 0xff - tda10086_read_byte(state, 0x1c); 5948c2ecf20Sopenharmony_ci *snr = (_snr << 8) | _snr; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* read it */ 6068c2ecf20Sopenharmony_ci *ucblocks = tda10086_read_byte(state, 0x18) & 0x7f; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* reset counter */ 6098c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x18, 0x00); 6108c2ecf20Sopenharmony_ci tda10086_write_byte(state, 0x18, 0x80); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return 0; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int tda10086_read_ber(struct dvb_frontend* fe, u32* ber) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* read it */ 6228c2ecf20Sopenharmony_ci *ber = 0; 6238c2ecf20Sopenharmony_ci *ber |= tda10086_read_byte(state, 0x15); 6248c2ecf20Sopenharmony_ci *ber |= tda10086_read_byte(state, 0x16) << 8; 6258c2ecf20Sopenharmony_ci *ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int tda10086_sleep(struct dvb_frontend* fe) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x00, 0x08, 0x08); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct tda10086_state* state = fe->demodulator_priv; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (enable) { 6488c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x00, 0x10, 0x10); 6498c2ecf20Sopenharmony_ci } else { 6508c2ecf20Sopenharmony_ci tda10086_write_mask(state, 0x00, 0x10, 0x00); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (p->symbol_rate > 20000000) { 6618c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 50; 6628c2ecf20Sopenharmony_ci fesettings->step_size = 2000; 6638c2ecf20Sopenharmony_ci fesettings->max_drift = 8000; 6648c2ecf20Sopenharmony_ci } else if (p->symbol_rate > 12000000) { 6658c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 100; 6668c2ecf20Sopenharmony_ci fesettings->step_size = 1500; 6678c2ecf20Sopenharmony_ci fesettings->max_drift = 9000; 6688c2ecf20Sopenharmony_ci } else if (p->symbol_rate > 8000000) { 6698c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 100; 6708c2ecf20Sopenharmony_ci fesettings->step_size = 1000; 6718c2ecf20Sopenharmony_ci fesettings->max_drift = 8000; 6728c2ecf20Sopenharmony_ci } else if (p->symbol_rate > 4000000) { 6738c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 100; 6748c2ecf20Sopenharmony_ci fesettings->step_size = 500; 6758c2ecf20Sopenharmony_ci fesettings->max_drift = 7000; 6768c2ecf20Sopenharmony_ci } else if (p->symbol_rate > 2000000) { 6778c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 200; 6788c2ecf20Sopenharmony_ci fesettings->step_size = p->symbol_rate / 8000; 6798c2ecf20Sopenharmony_ci fesettings->max_drift = 14 * fesettings->step_size; 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci fesettings->min_delay_ms = 200; 6828c2ecf20Sopenharmony_ci fesettings->step_size = p->symbol_rate / 8000; 6838c2ecf20Sopenharmony_ci fesettings->max_drift = 18 * fesettings->step_size; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return 0; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic void tda10086_release(struct dvb_frontend* fe) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct tda10086_state *state = fe->demodulator_priv; 6928c2ecf20Sopenharmony_ci tda10086_sleep(fe); 6938c2ecf20Sopenharmony_ci kfree(state); 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops tda10086_ops = { 6978c2ecf20Sopenharmony_ci .delsys = { SYS_DVBS }, 6988c2ecf20Sopenharmony_ci .info = { 6998c2ecf20Sopenharmony_ci .name = "Philips TDA10086 DVB-S", 7008c2ecf20Sopenharmony_ci .frequency_min_hz = 950 * MHz, 7018c2ecf20Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 7028c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 125 * kHz, 7038c2ecf20Sopenharmony_ci .symbol_rate_min = 1000000, 7048c2ecf20Sopenharmony_ci .symbol_rate_max = 45000000, 7058c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 7068c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 7078c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 7088c2ecf20Sopenharmony_ci FE_CAN_QPSK 7098c2ecf20Sopenharmony_ci }, 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci .release = tda10086_release, 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci .init = tda10086_init, 7148c2ecf20Sopenharmony_ci .sleep = tda10086_sleep, 7158c2ecf20Sopenharmony_ci .i2c_gate_ctrl = tda10086_i2c_gate_ctrl, 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci .set_frontend = tda10086_set_frontend, 7188c2ecf20Sopenharmony_ci .get_frontend = tda10086_get_frontend, 7198c2ecf20Sopenharmony_ci .get_tune_settings = tda10086_get_tune_settings, 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci .read_status = tda10086_read_status, 7228c2ecf20Sopenharmony_ci .read_ber = tda10086_read_ber, 7238c2ecf20Sopenharmony_ci .read_signal_strength = tda10086_read_signal_strength, 7248c2ecf20Sopenharmony_ci .read_snr = tda10086_read_snr, 7258c2ecf20Sopenharmony_ci .read_ucblocks = tda10086_read_ucblocks, 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci .diseqc_send_master_cmd = tda10086_send_master_cmd, 7288c2ecf20Sopenharmony_ci .diseqc_send_burst = tda10086_send_burst, 7298c2ecf20Sopenharmony_ci .set_tone = tda10086_set_tone, 7308c2ecf20Sopenharmony_ci}; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistruct dvb_frontend* tda10086_attach(const struct tda10086_config* config, 7338c2ecf20Sopenharmony_ci struct i2c_adapter* i2c) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct tda10086_state *state; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci dprintk ("%s\n", __func__); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 7408c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct tda10086_state), GFP_KERNEL); 7418c2ecf20Sopenharmony_ci if (!state) 7428c2ecf20Sopenharmony_ci return NULL; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* setup the state */ 7458c2ecf20Sopenharmony_ci state->config = config; 7468c2ecf20Sopenharmony_ci state->i2c = i2c; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* check if the demod is there */ 7498c2ecf20Sopenharmony_ci if (tda10086_read_byte(state, 0x1e) != 0xe1) { 7508c2ecf20Sopenharmony_ci kfree(state); 7518c2ecf20Sopenharmony_ci return NULL; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* create dvb_frontend */ 7558c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops)); 7568c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 7578c2ecf20Sopenharmony_ci return &state->frontend; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 7618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator"); 7648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrew de Quincey"); 7658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tda10086_attach); 768