19a0bf528SMauro Carvalho Chehab /* 29a0bf528SMauro Carvalho Chehab * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T). 39a0bf528SMauro Carvalho Chehab * 49a0bf528SMauro Carvalho Chehab * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/) 59a0bf528SMauro Carvalho Chehab * 69a0bf528SMauro Carvalho Chehab * This program is free software; you can redistribute it and/or 79a0bf528SMauro Carvalho Chehab * modify it under the terms of the GNU General Public License as 89a0bf528SMauro Carvalho Chehab * published by the Free Software Foundation, version 2. 99a0bf528SMauro Carvalho Chehab */ 108af16adfSMauro Carvalho Chehab 118af16adfSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 128af16adfSMauro Carvalho Chehab 139a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 149a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 159a0bf528SMauro Carvalho Chehab #include <linux/i2c.h> 169a0bf528SMauro Carvalho Chehab #include <linux/mutex.h> 17b4600d70SMauro Carvalho Chehab #include <asm/div64.h> 189a0bf528SMauro Carvalho Chehab 199a0bf528SMauro Carvalho Chehab #include "dvb_math.h" 209a0bf528SMauro Carvalho Chehab 219a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 229a0bf528SMauro Carvalho Chehab 239a0bf528SMauro Carvalho Chehab #include "dib8000.h" 249a0bf528SMauro Carvalho Chehab 259a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1 269a0bf528SMauro Carvalho Chehab #define LAYER_A 1 279a0bf528SMauro Carvalho Chehab #define LAYER_B 2 289a0bf528SMauro Carvalho Chehab #define LAYER_C 3 299a0bf528SMauro Carvalho Chehab 309a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6 31173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */ 329a0bf528SMauro Carvalho Chehab 339a0bf528SMauro Carvalho Chehab static int debug; 349a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 359a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 369a0bf528SMauro Carvalho Chehab 378af16adfSMauro Carvalho Chehab #define dprintk(fmt, arg...) do { \ 388af16adfSMauro Carvalho Chehab if (debug) \ 398af16adfSMauro Carvalho Chehab printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 408af16adfSMauro Carvalho Chehab __func__, ##arg); \ 418af16adfSMauro Carvalho Chehab } while (0) 429a0bf528SMauro Carvalho Chehab 439a0bf528SMauro Carvalho Chehab struct i2c_device { 449a0bf528SMauro Carvalho Chehab struct i2c_adapter *adap; 459a0bf528SMauro Carvalho Chehab u8 addr; 469a0bf528SMauro Carvalho Chehab u8 *i2c_write_buffer; 479a0bf528SMauro Carvalho Chehab u8 *i2c_read_buffer; 489a0bf528SMauro Carvalho Chehab struct mutex *i2c_buffer_lock; 499a0bf528SMauro Carvalho Chehab }; 509a0bf528SMauro Carvalho Chehab 51173a64cbSPatrick Boettcher enum param_loop_step { 52173a64cbSPatrick Boettcher LOOP_TUNE_1, 53173a64cbSPatrick Boettcher LOOP_TUNE_2 54173a64cbSPatrick Boettcher }; 55173a64cbSPatrick Boettcher 56173a64cbSPatrick Boettcher enum dib8000_autosearch_step { 57173a64cbSPatrick Boettcher AS_START = 0, 58173a64cbSPatrick Boettcher AS_SEARCHING_FFT, 59173a64cbSPatrick Boettcher AS_SEARCHING_GUARD, 60173a64cbSPatrick Boettcher AS_DONE = 100, 61173a64cbSPatrick Boettcher }; 62173a64cbSPatrick Boettcher 63173a64cbSPatrick Boettcher enum timeout_mode { 64173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_OFF = 0, 65173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_ON, 66173a64cbSPatrick Boettcher }; 67173a64cbSPatrick Boettcher 689a0bf528SMauro Carvalho Chehab struct dib8000_state { 699a0bf528SMauro Carvalho Chehab struct dib8000_config cfg; 709a0bf528SMauro Carvalho Chehab 719a0bf528SMauro Carvalho Chehab struct i2c_device i2c; 729a0bf528SMauro Carvalho Chehab 739a0bf528SMauro Carvalho Chehab struct dibx000_i2c_master i2c_master; 749a0bf528SMauro Carvalho Chehab 759a0bf528SMauro Carvalho Chehab u16 wbd_ref; 769a0bf528SMauro Carvalho Chehab 779a0bf528SMauro Carvalho Chehab u8 current_band; 789a0bf528SMauro Carvalho Chehab u32 current_bandwidth; 799a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *current_agc; 809a0bf528SMauro Carvalho Chehab u32 timf; 819a0bf528SMauro Carvalho Chehab u32 timf_default; 829a0bf528SMauro Carvalho Chehab 839a0bf528SMauro Carvalho Chehab u8 div_force_off:1; 849a0bf528SMauro Carvalho Chehab u8 div_state:1; 859a0bf528SMauro Carvalho Chehab u16 div_sync_wait; 869a0bf528SMauro Carvalho Chehab 879a0bf528SMauro Carvalho Chehab u8 agc_state; 889a0bf528SMauro Carvalho Chehab u8 differential_constellation; 899a0bf528SMauro Carvalho Chehab u8 diversity_onoff; 909a0bf528SMauro Carvalho Chehab 919a0bf528SMauro Carvalho Chehab s16 ber_monitored_layer; 929a0bf528SMauro Carvalho Chehab u16 gpio_dir; 939a0bf528SMauro Carvalho Chehab u16 gpio_val; 949a0bf528SMauro Carvalho Chehab 959a0bf528SMauro Carvalho Chehab u16 revision; 969a0bf528SMauro Carvalho Chehab u8 isdbt_cfg_loaded; 979a0bf528SMauro Carvalho Chehab enum frontend_tune_state tune_state; 98173a64cbSPatrick Boettcher s32 status; 999a0bf528SMauro Carvalho Chehab 1009a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; 1019a0bf528SMauro Carvalho Chehab 1029a0bf528SMauro Carvalho Chehab /* for the I2C transfer */ 1039a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2]; 1049a0bf528SMauro Carvalho Chehab u8 i2c_write_buffer[4]; 1059a0bf528SMauro Carvalho Chehab u8 i2c_read_buffer[2]; 1069a0bf528SMauro Carvalho Chehab struct mutex i2c_buffer_lock; 1079a0bf528SMauro Carvalho Chehab u8 input_mode_mpeg; 1089a0bf528SMauro Carvalho Chehab 1099a0bf528SMauro Carvalho Chehab u16 tuner_enable; 1109a0bf528SMauro Carvalho Chehab struct i2c_adapter dib8096p_tuner_adap; 111173a64cbSPatrick Boettcher u16 current_demod_bw; 112173a64cbSPatrick Boettcher 113173a64cbSPatrick Boettcher u16 seg_mask; 114173a64cbSPatrick Boettcher u16 seg_diff_mask; 115173a64cbSPatrick Boettcher u16 mode; 116173a64cbSPatrick Boettcher u8 layer_b_nb_seg; 117173a64cbSPatrick Boettcher u8 layer_c_nb_seg; 118173a64cbSPatrick Boettcher 119173a64cbSPatrick Boettcher u8 channel_parameters_set; 120173a64cbSPatrick Boettcher u16 autosearch_state; 121173a64cbSPatrick Boettcher u16 found_nfft; 122173a64cbSPatrick Boettcher u16 found_guard; 123173a64cbSPatrick Boettcher u8 subchannel; 124173a64cbSPatrick Boettcher u8 symbol_duration; 125d6c62b76SMauro Carvalho Chehab unsigned long timeout; 126173a64cbSPatrick Boettcher u8 longest_intlv_layer; 127173a64cbSPatrick Boettcher u16 output_mode; 128173a64cbSPatrick Boettcher 129704f01bbSMauro Carvalho Chehab /* for DVBv5 stats */ 1307a9d85d5SMauro Carvalho Chehab s64 init_ucb; 1310400c535SMauro Carvalho Chehab unsigned long per_jiffies_stats; 1320400c535SMauro Carvalho Chehab unsigned long ber_jiffies_stats; 1330400c535SMauro Carvalho Chehab unsigned long ber_jiffies_stats_layer[3]; 134704f01bbSMauro Carvalho Chehab 135173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 136173a64cbSPatrick Boettcher u16 agc1_max; 137173a64cbSPatrick Boettcher u16 agc1_min; 138173a64cbSPatrick Boettcher u16 agc2_max; 139173a64cbSPatrick Boettcher u16 agc2_min; 140173a64cbSPatrick Boettcher #endif 1419a0bf528SMauro Carvalho Chehab }; 1429a0bf528SMauro Carvalho Chehab 1439a0bf528SMauro Carvalho Chehab enum dib8000_power_mode { 1449a0bf528SMauro Carvalho Chehab DIB8000_POWER_ALL = 0, 1459a0bf528SMauro Carvalho Chehab DIB8000_POWER_INTERFACE_ONLY, 1469a0bf528SMauro Carvalho Chehab }; 1479a0bf528SMauro Carvalho Chehab 1489a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) 1499a0bf528SMauro Carvalho Chehab { 1509a0bf528SMauro Carvalho Chehab u16 ret; 1519a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2] = { 1529a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = 0, .len = 2}, 1539a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2}, 1549a0bf528SMauro Carvalho Chehab }; 1559a0bf528SMauro Carvalho Chehab 1569a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { 1578af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n"); 1589a0bf528SMauro Carvalho Chehab return 0; 1599a0bf528SMauro Carvalho Chehab } 1609a0bf528SMauro Carvalho Chehab 1619a0bf528SMauro Carvalho Chehab msg[0].buf = i2c->i2c_write_buffer; 1629a0bf528SMauro Carvalho Chehab msg[0].buf[0] = reg >> 8; 1639a0bf528SMauro Carvalho Chehab msg[0].buf[1] = reg & 0xff; 1649a0bf528SMauro Carvalho Chehab msg[1].buf = i2c->i2c_read_buffer; 1659a0bf528SMauro Carvalho Chehab 1669a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c->adap, msg, 2) != 2) 1678af16adfSMauro Carvalho Chehab dprintk("i2c read error on %d\n", reg); 1689a0bf528SMauro Carvalho Chehab 1699a0bf528SMauro Carvalho Chehab ret = (msg[1].buf[0] << 8) | msg[1].buf[1]; 1709a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock); 1719a0bf528SMauro Carvalho Chehab return ret; 1729a0bf528SMauro Carvalho Chehab } 1739a0bf528SMauro Carvalho Chehab 1745ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg) 1759a0bf528SMauro Carvalho Chehab { 1769a0bf528SMauro Carvalho Chehab u16 ret; 1779a0bf528SMauro Carvalho Chehab 1789a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = reg >> 8; 1799a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 1809a0bf528SMauro Carvalho Chehab 1819a0bf528SMauro Carvalho Chehab memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 1829a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1; 1839a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 1849a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 1859a0bf528SMauro Carvalho Chehab state->msg[0].len = 2; 1869a0bf528SMauro Carvalho Chehab state->msg[1].addr = state->i2c.addr >> 1; 1879a0bf528SMauro Carvalho Chehab state->msg[1].flags = I2C_M_RD; 1889a0bf528SMauro Carvalho Chehab state->msg[1].buf = state->i2c_read_buffer; 1899a0bf528SMauro Carvalho Chehab state->msg[1].len = 2; 1909a0bf528SMauro Carvalho Chehab 1919a0bf528SMauro Carvalho Chehab if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) 1928af16adfSMauro Carvalho Chehab dprintk("i2c read error on %d\n", reg); 1939a0bf528SMauro Carvalho Chehab 1949a0bf528SMauro Carvalho Chehab ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 1955ac64ba1SMauro Carvalho Chehab 1965ac64ba1SMauro Carvalho Chehab return ret; 1975ac64ba1SMauro Carvalho Chehab } 1985ac64ba1SMauro Carvalho Chehab 1995ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) 2005ac64ba1SMauro Carvalho Chehab { 2015ac64ba1SMauro Carvalho Chehab u16 ret; 2025ac64ba1SMauro Carvalho Chehab 2035ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 2048af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n"); 2055ac64ba1SMauro Carvalho Chehab return 0; 2065ac64ba1SMauro Carvalho Chehab } 2075ac64ba1SMauro Carvalho Chehab 2085ac64ba1SMauro Carvalho Chehab ret = __dib8000_read_word(state, reg); 2095ac64ba1SMauro Carvalho Chehab 2109a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2119a0bf528SMauro Carvalho Chehab 2129a0bf528SMauro Carvalho Chehab return ret; 2139a0bf528SMauro Carvalho Chehab } 2149a0bf528SMauro Carvalho Chehab 2159a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg) 2169a0bf528SMauro Carvalho Chehab { 2179a0bf528SMauro Carvalho Chehab u16 rw[2]; 2189a0bf528SMauro Carvalho Chehab 2195ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 2208af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n"); 2215ac64ba1SMauro Carvalho Chehab return 0; 2225ac64ba1SMauro Carvalho Chehab } 2235ac64ba1SMauro Carvalho Chehab 2245ac64ba1SMauro Carvalho Chehab rw[0] = __dib8000_read_word(state, reg + 0); 2255ac64ba1SMauro Carvalho Chehab rw[1] = __dib8000_read_word(state, reg + 1); 2265ac64ba1SMauro Carvalho Chehab 2275ac64ba1SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2289a0bf528SMauro Carvalho Chehab 2299a0bf528SMauro Carvalho Chehab return ((rw[0] << 16) | (rw[1])); 2309a0bf528SMauro Carvalho Chehab } 2319a0bf528SMauro Carvalho Chehab 2329a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) 2339a0bf528SMauro Carvalho Chehab { 2349a0bf528SMauro Carvalho Chehab struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4}; 2359a0bf528SMauro Carvalho Chehab int ret = 0; 2369a0bf528SMauro Carvalho Chehab 2379a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { 2388af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n"); 2399a0bf528SMauro Carvalho Chehab return -EINVAL; 2409a0bf528SMauro Carvalho Chehab } 2419a0bf528SMauro Carvalho Chehab 2429a0bf528SMauro Carvalho Chehab msg.buf = i2c->i2c_write_buffer; 2439a0bf528SMauro Carvalho Chehab msg.buf[0] = (reg >> 8) & 0xff; 2449a0bf528SMauro Carvalho Chehab msg.buf[1] = reg & 0xff; 2459a0bf528SMauro Carvalho Chehab msg.buf[2] = (val >> 8) & 0xff; 2469a0bf528SMauro Carvalho Chehab msg.buf[3] = val & 0xff; 2479a0bf528SMauro Carvalho Chehab 2489a0bf528SMauro Carvalho Chehab ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; 2499a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock); 2509a0bf528SMauro Carvalho Chehab 2519a0bf528SMauro Carvalho Chehab return ret; 2529a0bf528SMauro Carvalho Chehab } 2539a0bf528SMauro Carvalho Chehab 2549a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) 2559a0bf528SMauro Carvalho Chehab { 2569a0bf528SMauro Carvalho Chehab int ret; 2579a0bf528SMauro Carvalho Chehab 2589a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 2598af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n"); 2609a0bf528SMauro Carvalho Chehab return -EINVAL; 2619a0bf528SMauro Carvalho Chehab } 2629a0bf528SMauro Carvalho Chehab 2639a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = (reg >> 8) & 0xff; 2649a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 2659a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[2] = (val >> 8) & 0xff; 2669a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[3] = val & 0xff; 2679a0bf528SMauro Carvalho Chehab 2689a0bf528SMauro Carvalho Chehab memset(&state->msg[0], 0, sizeof(struct i2c_msg)); 2699a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1; 2709a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 2719a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 2729a0bf528SMauro Carvalho Chehab state->msg[0].len = 4; 2739a0bf528SMauro Carvalho Chehab 2749a0bf528SMauro Carvalho Chehab ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? 2759a0bf528SMauro Carvalho Chehab -EREMOTEIO : 0); 2769a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2779a0bf528SMauro Carvalho Chehab 2789a0bf528SMauro Carvalho Chehab return ret; 2799a0bf528SMauro Carvalho Chehab } 2809a0bf528SMauro Carvalho Chehab 2819a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = { 2829a0bf528SMauro Carvalho Chehab (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, 2839a0bf528SMauro Carvalho Chehab (920 << 5) | 0x09 2849a0bf528SMauro Carvalho Chehab }; 2859a0bf528SMauro Carvalho Chehab 2869a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = { 2879a0bf528SMauro Carvalho Chehab (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f 2889a0bf528SMauro Carvalho Chehab }; 2899a0bf528SMauro Carvalho Chehab 2909a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { 2919a0bf528SMauro Carvalho Chehab (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, 2929a0bf528SMauro Carvalho Chehab (-931 << 5) | 0x0f 2939a0bf528SMauro Carvalho Chehab }; 2949a0bf528SMauro Carvalho Chehab 2959a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = { 2969a0bf528SMauro Carvalho Chehab (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, 2979a0bf528SMauro Carvalho Chehab (982 << 5) | 0x0c 2989a0bf528SMauro Carvalho Chehab }; 2999a0bf528SMauro Carvalho Chehab 3009a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = { 3019a0bf528SMauro Carvalho Chehab (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, 3029a0bf528SMauro Carvalho Chehab (-720 << 5) | 0x0d 3039a0bf528SMauro Carvalho Chehab }; 3049a0bf528SMauro Carvalho Chehab 3059a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = { 3069a0bf528SMauro Carvalho Chehab (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, 3079a0bf528SMauro Carvalho Chehab (-610 << 5) | 0x0a 3089a0bf528SMauro Carvalho Chehab }; 3099a0bf528SMauro Carvalho Chehab 3109a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = { 3119a0bf528SMauro Carvalho Chehab (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, 3129a0bf528SMauro Carvalho Chehab (-922 << 5) | 0x0d 3139a0bf528SMauro Carvalho Chehab }; 3149a0bf528SMauro Carvalho Chehab 3159a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = { 3169a0bf528SMauro Carvalho Chehab (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, 3179a0bf528SMauro Carvalho Chehab (-655 << 5) | 0x0a 3189a0bf528SMauro Carvalho Chehab }; 3199a0bf528SMauro Carvalho Chehab 3209a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { 3219a0bf528SMauro Carvalho Chehab (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, 3229a0bf528SMauro Carvalho Chehab (-958 << 5) | 0x13 3239a0bf528SMauro Carvalho Chehab }; 3249a0bf528SMauro Carvalho Chehab 3259a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = { 3269a0bf528SMauro Carvalho Chehab (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, 3279a0bf528SMauro Carvalho Chehab (-568 << 5) | 0x0f 3289a0bf528SMauro Carvalho Chehab }; 3299a0bf528SMauro Carvalho Chehab 3309a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = { 3319a0bf528SMauro Carvalho Chehab (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, 3329a0bf528SMauro Carvalho Chehab (-848 << 5) | 0x13 3339a0bf528SMauro Carvalho Chehab }; 3349a0bf528SMauro Carvalho Chehab 3359a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = { 3369a0bf528SMauro Carvalho Chehab (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, 3379a0bf528SMauro Carvalho Chehab (-869 << 5) | 0x13 3389a0bf528SMauro Carvalho Chehab }; 3399a0bf528SMauro Carvalho Chehab 3409a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = { 3419a0bf528SMauro Carvalho Chehab (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, 3429a0bf528SMauro Carvalho Chehab (-598 << 5) | 0x10 3439a0bf528SMauro Carvalho Chehab }; 3449a0bf528SMauro Carvalho Chehab 3459a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = { 3469a0bf528SMauro Carvalho Chehab (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, 3479a0bf528SMauro Carvalho Chehab (585 << 5) | 0x0f 3489a0bf528SMauro Carvalho Chehab }; 3499a0bf528SMauro Carvalho Chehab 3509a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { 3519a0bf528SMauro Carvalho Chehab (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, 3529a0bf528SMauro Carvalho Chehab (0 << 5) | 0x14 3539a0bf528SMauro Carvalho Chehab }; 3549a0bf528SMauro Carvalho Chehab 3559a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = { 3569a0bf528SMauro Carvalho Chehab (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, 3579a0bf528SMauro Carvalho Chehab (-877 << 5) | 0x15 3589a0bf528SMauro Carvalho Chehab }; 3599a0bf528SMauro Carvalho Chehab 3609a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = { 3619a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, 3629a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x14 3639a0bf528SMauro Carvalho Chehab }; 3649a0bf528SMauro Carvalho Chehab 3659a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = { 3669a0bf528SMauro Carvalho Chehab (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, 3679a0bf528SMauro Carvalho Chehab (690 << 5) | 0x14 3689a0bf528SMauro Carvalho Chehab }; 3699a0bf528SMauro Carvalho Chehab 3709a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = { 3719a0bf528SMauro Carvalho Chehab 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 3729a0bf528SMauro Carvalho Chehab }; 3739a0bf528SMauro Carvalho Chehab 3749a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = { 3759a0bf528SMauro Carvalho Chehab 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 3769a0bf528SMauro Carvalho Chehab }; 3779a0bf528SMauro Carvalho Chehab 3789a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = { 3799a0bf528SMauro Carvalho Chehab 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 3809a0bf528SMauro Carvalho Chehab }; 3819a0bf528SMauro Carvalho Chehab 3829a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state) 3839a0bf528SMauro Carvalho Chehab { 3849a0bf528SMauro Carvalho Chehab u16 mode; 3859a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) { 3869a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 3879a0bf528SMauro Carvalho Chehab mode = 1; 3889a0bf528SMauro Carvalho Chehab break; 3899a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 3909a0bf528SMauro Carvalho Chehab mode = 2; 3919a0bf528SMauro Carvalho Chehab break; 3929a0bf528SMauro Carvalho Chehab default: 3939a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_AUTO: 3949a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 3959a0bf528SMauro Carvalho Chehab mode = 3; 3969a0bf528SMauro Carvalho Chehab break; 3979a0bf528SMauro Carvalho Chehab } 3989a0bf528SMauro Carvalho Chehab return mode; 3999a0bf528SMauro Carvalho Chehab } 4009a0bf528SMauro Carvalho Chehab 4019a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state) 4029a0bf528SMauro Carvalho Chehab { 4039a0bf528SMauro Carvalho Chehab u16 nud = dib8000_read_word(state, 298); 4049a0bf528SMauro Carvalho Chehab nud |= (1 << 3) | (1 << 0); 4058af16adfSMauro Carvalho Chehab dprintk("acquisition mode activated\n"); 4069a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 298, nud); 4079a0bf528SMauro Carvalho Chehab } 4089a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) 4099a0bf528SMauro Carvalho Chehab { 4109a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 4119a0bf528SMauro Carvalho Chehab u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ 4129a0bf528SMauro Carvalho Chehab 413173a64cbSPatrick Boettcher state->output_mode = mode; 4149a0bf528SMauro Carvalho Chehab outreg = 0; 4159a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 4169a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); 4179a0bf528SMauro Carvalho Chehab 4188af16adfSMauro Carvalho Chehab dprintk("-I- Setting output mode for demod %p to %d\n", 4199a0bf528SMauro Carvalho Chehab &state->fe[0], mode); 4209a0bf528SMauro Carvalho Chehab 4219a0bf528SMauro Carvalho Chehab switch (mode) { 4229a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock 4239a0bf528SMauro Carvalho Chehab outreg = (1 << 10); /* 0x0400 */ 4249a0bf528SMauro Carvalho Chehab break; 4259a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock 4269a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (1 << 6); /* 0x0440 */ 4279a0bf528SMauro Carvalho Chehab break; 4289a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: // STBs with serial input 4299a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ 4309a0bf528SMauro Carvalho Chehab break; 4319a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 4329a0bf528SMauro Carvalho Chehab if (state->cfg.hostbus_diversity) { 4339a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (4 << 6); /* 0x0500 */ 4349a0bf528SMauro Carvalho Chehab sram &= 0xfdff; 4359a0bf528SMauro Carvalho Chehab } else 4369a0bf528SMauro Carvalho Chehab sram |= 0x0c00; 4379a0bf528SMauro Carvalho Chehab break; 4389a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: // e.g. USB feeding 4399a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 4409a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 4419a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (5 << 6); 4429a0bf528SMauro Carvalho Chehab break; 4439a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: // disable 4449a0bf528SMauro Carvalho Chehab outreg = 0; 4459a0bf528SMauro Carvalho Chehab break; 4469a0bf528SMauro Carvalho Chehab 4479a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 4489a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (3 << 6); 4499a0bf528SMauro Carvalho Chehab dib8000_set_acquisition_mode(state); 4509a0bf528SMauro Carvalho Chehab break; 4519a0bf528SMauro Carvalho Chehab 4529a0bf528SMauro Carvalho Chehab default: 4538af16adfSMauro Carvalho Chehab dprintk("Unhandled output_mode passed to be set for demod %p\n", 4549a0bf528SMauro Carvalho Chehab &state->fe[0]); 4559a0bf528SMauro Carvalho Chehab return -EINVAL; 4569a0bf528SMauro Carvalho Chehab } 4579a0bf528SMauro Carvalho Chehab 4589a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 4599a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 4609a0bf528SMauro Carvalho Chehab 4619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 299, smo_mode); 4629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */ 4639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1286, outreg); 4649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1291, sram); 4659a0bf528SMauro Carvalho Chehab 4669a0bf528SMauro Carvalho Chehab return 0; 4679a0bf528SMauro Carvalho Chehab } 4689a0bf528SMauro Carvalho Chehab 4699a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) 4709a0bf528SMauro Carvalho Chehab { 4719a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 472173a64cbSPatrick Boettcher u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0; 4739a0bf528SMauro Carvalho Chehab 4748af16adfSMauro Carvalho Chehab dprintk("set diversity input to %i\n", onoff); 4759a0bf528SMauro Carvalho Chehab if (!state->differential_constellation) { 4769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 4779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 4789a0bf528SMauro Carvalho Chehab } else { 4799a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0 4809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0 4819a0bf528SMauro Carvalho Chehab } 4829a0bf528SMauro Carvalho Chehab state->diversity_onoff = onoff; 4839a0bf528SMauro Carvalho Chehab 4849a0bf528SMauro Carvalho Chehab switch (onoff) { 4859a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */ 4869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 1); 4879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 0); 4889a0bf528SMauro Carvalho Chehab break; 4899a0bf528SMauro Carvalho Chehab case 1: /* both ways */ 4909a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 6); 4919a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 6); 4929a0bf528SMauro Carvalho Chehab break; 4939a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */ 4949a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 0); 4959a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 1); 4969a0bf528SMauro Carvalho Chehab break; 4979a0bf528SMauro Carvalho Chehab } 498173a64cbSPatrick Boettcher 499173a64cbSPatrick Boettcher if (state->revision == 0x8002) { 500173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 903); 501173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp & ~(1 << 3)); 502173a64cbSPatrick Boettcher msleep(30); 503173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp | (1 << 3)); 504173a64cbSPatrick Boettcher } 5059a0bf528SMauro Carvalho Chehab return 0; 5069a0bf528SMauro Carvalho Chehab } 5079a0bf528SMauro Carvalho Chehab 5089a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode) 5099a0bf528SMauro Carvalho Chehab { 5109a0bf528SMauro Carvalho Chehab /* by default everything is going to be powered off */ 5119a0bf528SMauro Carvalho Chehab u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, 5129a0bf528SMauro Carvalho Chehab reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, 5139a0bf528SMauro Carvalho Chehab reg_1280; 5149a0bf528SMauro Carvalho Chehab 5159a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5169a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; 5179a0bf528SMauro Carvalho Chehab else 5189a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80; 5199a0bf528SMauro Carvalho Chehab 5209a0bf528SMauro Carvalho Chehab /* now, depending on the requested mode, we power on */ 5219a0bf528SMauro Carvalho Chehab switch (mode) { 5229a0bf528SMauro Carvalho Chehab /* power up everything in the demod */ 5239a0bf528SMauro Carvalho Chehab case DIB8000_POWER_ALL: 5249a0bf528SMauro Carvalho Chehab reg_774 = 0x0000; 5259a0bf528SMauro Carvalho Chehab reg_775 = 0x0000; 5269a0bf528SMauro Carvalho Chehab reg_776 = 0x0000; 5279a0bf528SMauro Carvalho Chehab reg_900 &= 0xfffc; 5289a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5299a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff; 5309a0bf528SMauro Carvalho Chehab else 5319a0bf528SMauro Carvalho Chehab reg_1280 &= 0x707f; 5329a0bf528SMauro Carvalho Chehab break; 5339a0bf528SMauro Carvalho Chehab case DIB8000_POWER_INTERFACE_ONLY: 5349a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5359a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff; 5369a0bf528SMauro Carvalho Chehab else 5379a0bf528SMauro Carvalho Chehab reg_1280 &= 0xfa7b; 5389a0bf528SMauro Carvalho Chehab break; 5399a0bf528SMauro Carvalho Chehab } 5409a0bf528SMauro Carvalho Chehab 5418af16adfSMauro Carvalho Chehab dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x\n", reg_774, reg_775, reg_776, reg_900, reg_1280); 5429a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 774, reg_774); 5439a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 775, reg_775); 5449a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 776, reg_776); 5459a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 900, reg_900); 5469a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, reg_1280); 5479a0bf528SMauro Carvalho Chehab } 5489a0bf528SMauro Carvalho Chehab 5499a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) 5509a0bf528SMauro Carvalho Chehab { 5519a0bf528SMauro Carvalho Chehab int ret = 0; 5529a0bf528SMauro Carvalho Chehab u16 reg, reg_907 = dib8000_read_word(state, 907); 5539a0bf528SMauro Carvalho Chehab u16 reg_908 = dib8000_read_word(state, 908); 5549a0bf528SMauro Carvalho Chehab 5559a0bf528SMauro Carvalho Chehab switch (no) { 5569a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_ON: 5579a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 5589a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0); 5599a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908); 5609a0bf528SMauro Carvalho Chehab reg_908 &= ~(1 << 1); 5619a0bf528SMauro Carvalho Chehab } else { 5629a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5639a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 1 */ 5649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg | 5659a0bf528SMauro Carvalho Chehab (1<<4) | (1<<2)); 5669a0bf528SMauro Carvalho Chehab 5679a0bf528SMauro Carvalho Chehab /* read acces to make it works... strange ... */ 5689a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5699a0bf528SMauro Carvalho Chehab msleep(20); 5709a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 0 */ 5719a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg & ~(1<<4)); 5729a0bf528SMauro Carvalho Chehab 5739a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 921) & ~((0x3 << 14) 5749a0bf528SMauro Carvalho Chehab | (0x3 << 12)); 5759a0bf528SMauro Carvalho Chehab /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; 5769a0bf528SMauro Carvalho Chehab (Vin2 = Vcm) */ 5779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, reg | (1 << 14) 5789a0bf528SMauro Carvalho Chehab | (3 << 12)); 5799a0bf528SMauro Carvalho Chehab } 5809a0bf528SMauro Carvalho Chehab break; 5819a0bf528SMauro Carvalho Chehab 5829a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_OFF: 5839a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 5849a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5859a0bf528SMauro Carvalho Chehab /* reset_sladc = 1 en_slowAdc = 0 */ 5869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, 5879a0bf528SMauro Carvalho Chehab (reg & ~(1<<2)) | (1<<4)); 5889a0bf528SMauro Carvalho Chehab } 5899a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0); 5909a0bf528SMauro Carvalho Chehab break; 5919a0bf528SMauro Carvalho Chehab 5929a0bf528SMauro Carvalho Chehab case DIBX000_ADC_ON: 5939a0bf528SMauro Carvalho Chehab reg_907 &= 0x0fff; 5949a0bf528SMauro Carvalho Chehab reg_908 &= 0x0003; 5959a0bf528SMauro Carvalho Chehab break; 5969a0bf528SMauro Carvalho Chehab 5979a0bf528SMauro Carvalho Chehab case DIBX000_ADC_OFF: // leave the VBG voltage on 598c063c7c6SMauro Carvalho Chehab reg_907 = (1 << 13) | (1 << 12); 599c063c7c6SMauro Carvalho Chehab reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1); 6009a0bf528SMauro Carvalho Chehab break; 6019a0bf528SMauro Carvalho Chehab 6029a0bf528SMauro Carvalho Chehab case DIBX000_VBG_ENABLE: 6039a0bf528SMauro Carvalho Chehab reg_907 &= ~(1 << 15); 6049a0bf528SMauro Carvalho Chehab break; 6059a0bf528SMauro Carvalho Chehab 6069a0bf528SMauro Carvalho Chehab case DIBX000_VBG_DISABLE: 6079a0bf528SMauro Carvalho Chehab reg_907 |= (1 << 15); 6089a0bf528SMauro Carvalho Chehab break; 6099a0bf528SMauro Carvalho Chehab 6109a0bf528SMauro Carvalho Chehab default: 6119a0bf528SMauro Carvalho Chehab break; 6129a0bf528SMauro Carvalho Chehab } 6139a0bf528SMauro Carvalho Chehab 6149a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 907, reg_907); 6159a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908); 6169a0bf528SMauro Carvalho Chehab 6179a0bf528SMauro Carvalho Chehab return ret; 6189a0bf528SMauro Carvalho Chehab } 6199a0bf528SMauro Carvalho Chehab 6209a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) 6219a0bf528SMauro Carvalho Chehab { 6229a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 6239a0bf528SMauro Carvalho Chehab u32 timf; 6249a0bf528SMauro Carvalho Chehab 6259a0bf528SMauro Carvalho Chehab if (bw == 0) 6269a0bf528SMauro Carvalho Chehab bw = 6000; 6279a0bf528SMauro Carvalho Chehab 6289a0bf528SMauro Carvalho Chehab if (state->timf == 0) { 6298af16adfSMauro Carvalho Chehab dprintk("using default timf\n"); 6309a0bf528SMauro Carvalho Chehab timf = state->timf_default; 6319a0bf528SMauro Carvalho Chehab } else { 6328af16adfSMauro Carvalho Chehab dprintk("using updated timf\n"); 6339a0bf528SMauro Carvalho Chehab timf = state->timf; 6349a0bf528SMauro Carvalho Chehab } 6359a0bf528SMauro Carvalho Chehab 6369a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff)); 6379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) ((timf) & 0xffff)); 6389a0bf528SMauro Carvalho Chehab 6399a0bf528SMauro Carvalho Chehab return 0; 6409a0bf528SMauro Carvalho Chehab } 6419a0bf528SMauro Carvalho Chehab 6429a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state) 6439a0bf528SMauro Carvalho Chehab { 644173a64cbSPatrick Boettcher u8 sad_sel = 3; 645173a64cbSPatrick Boettcher 6469a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 647173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2)); 648173a64cbSPatrick Boettcher dib8000_write_word(state, 923, 2048); 649173a64cbSPatrick Boettcher 650173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2) | 0x1); 651173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2)); 652173a64cbSPatrick Boettcher } else { 6539a0bf528SMauro Carvalho Chehab /* internal */ 6549a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); 655173a64cbSPatrick Boettcher dib8000_write_word(state, 924, 776); 6569a0bf528SMauro Carvalho Chehab 6579a0bf528SMauro Carvalho Chehab /* do the calibration */ 6589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (1 << 0)); 6599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 0)); 660173a64cbSPatrick Boettcher } 6619a0bf528SMauro Carvalho Chehab 6629a0bf528SMauro Carvalho Chehab msleep(1); 6639a0bf528SMauro Carvalho Chehab return 0; 6649a0bf528SMauro Carvalho Chehab } 6659a0bf528SMauro Carvalho Chehab 666d44913c1SMauro Carvalho Chehab static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) 6679a0bf528SMauro Carvalho Chehab { 6689a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 6699a0bf528SMauro Carvalho Chehab if (value > 4095) 6709a0bf528SMauro Carvalho Chehab value = 4095; 6719a0bf528SMauro Carvalho Chehab state->wbd_ref = value; 6729a0bf528SMauro Carvalho Chehab return dib8000_write_word(state, 106, value); 6739a0bf528SMauro Carvalho Chehab } 674173a64cbSPatrick Boettcher 6759a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) 6769a0bf528SMauro Carvalho Chehab { 6778af16adfSMauro Carvalho Chehab dprintk("ifreq: %d %x, inversion: %d\n", bw->ifreq, bw->ifreq, bw->ifreq >> 25); 6789a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 6799a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, 6809a0bf528SMauro Carvalho Chehab (u16) (((bw->internal * 1000) >> 16) & 0xffff)); 6819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, 6829a0bf528SMauro Carvalho Chehab (u16) ((bw->internal * 1000) & 0xffff)); 6839a0bf528SMauro Carvalho Chehab } else { 6849a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff)); 6859a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, 6869a0bf528SMauro Carvalho Chehab (u16) ((bw->internal / 2 * 1000) & 0xffff)); 6879a0bf528SMauro Carvalho Chehab } 6889a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); 6899a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); 6909a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); 6919a0bf528SMauro Carvalho Chehab 6929a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 6939a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, bw->sad_cfg); 6949a0bf528SMauro Carvalho Chehab } 6959a0bf528SMauro Carvalho Chehab 6969a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state) 6979a0bf528SMauro Carvalho Chehab { 6989a0bf528SMauro Carvalho Chehab const struct dibx000_bandwidth_config *pll = state->cfg.pll; 6999a0bf528SMauro Carvalho Chehab u16 clk_cfg1, reg; 7009a0bf528SMauro Carvalho Chehab 7019a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 7029a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 901, 7039a0bf528SMauro Carvalho Chehab (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); 7049a0bf528SMauro Carvalho Chehab 7059a0bf528SMauro Carvalho Chehab clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | 7069a0bf528SMauro Carvalho Chehab (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | 7079a0bf528SMauro Carvalho Chehab (1 << 3) | (pll->pll_range << 1) | 7089a0bf528SMauro Carvalho Chehab (pll->pll_reset << 0); 7099a0bf528SMauro Carvalho Chehab 7109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1); 7119a0bf528SMauro Carvalho Chehab clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); 7129a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1); 7139a0bf528SMauro Carvalho Chehab 7148af16adfSMauro Carvalho Chehab dprintk("clk_cfg1: 0x%04x\n", clk_cfg1); 7159a0bf528SMauro Carvalho Chehab 7169a0bf528SMauro Carvalho Chehab /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ 7179a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ADClkSrc == 0) 7189a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, 7199a0bf528SMauro Carvalho Chehab (0 << 15) | (0 << 12) | (0 << 10) | 7209a0bf528SMauro Carvalho Chehab (pll->modulo << 8) | 7219a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7229a0bf528SMauro Carvalho Chehab else if (state->cfg.refclksel != 0) 7239a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | 7249a0bf528SMauro Carvalho Chehab ((state->cfg.refclksel & 0x3) << 10) | 7259a0bf528SMauro Carvalho Chehab (pll->modulo << 8) | 7269a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7279a0bf528SMauro Carvalho Chehab else 7289a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | 7299a0bf528SMauro Carvalho Chehab (3 << 10) | (pll->modulo << 8) | 7309a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7319a0bf528SMauro Carvalho Chehab } else { 7329a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, (!pll->pll_reset<<13) | 7339a0bf528SMauro Carvalho Chehab (pll->pll_range<<12) | (pll->pll_ratio<<6) | 7349a0bf528SMauro Carvalho Chehab (pll->pll_prediv)); 7359a0bf528SMauro Carvalho Chehab 7369a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1857); 7379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15)); 7389a0bf528SMauro Carvalho Chehab 7399a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */ 7409a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1858, reg | 1); 7419a0bf528SMauro Carvalho Chehab 7429a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (pll->modulo << 8)); 7439a0bf528SMauro Carvalho Chehab } 7449a0bf528SMauro Carvalho Chehab 7459a0bf528SMauro Carvalho Chehab dib8000_reset_pll_common(state, pll); 7469a0bf528SMauro Carvalho Chehab } 7479a0bf528SMauro Carvalho Chehab 748d44913c1SMauro Carvalho Chehab static int dib8000_update_pll(struct dvb_frontend *fe, 749173a64cbSPatrick Boettcher struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio) 7509a0bf528SMauro Carvalho Chehab { 7519a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 7529a0bf528SMauro Carvalho Chehab u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856); 753173a64cbSPatrick Boettcher u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ; 7549a0bf528SMauro Carvalho Chehab u32 internal, xtal; 7559a0bf528SMauro Carvalho Chehab 7569a0bf528SMauro Carvalho Chehab /* get back old values */ 7579a0bf528SMauro Carvalho Chehab prediv = reg_1856 & 0x3f; 7589a0bf528SMauro Carvalho Chehab loopdiv = (reg_1856 >> 6) & 0x3f; 7599a0bf528SMauro Carvalho Chehab 760173a64cbSPatrick Boettcher if ((pll == NULL) || (pll->pll_prediv == prediv && 761173a64cbSPatrick Boettcher pll->pll_ratio == loopdiv)) 762173a64cbSPatrick Boettcher return -EINVAL; 763173a64cbSPatrick Boettcher 7648af16adfSMauro Carvalho Chehab dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); 765173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 7669a0bf528SMauro Carvalho Chehab reg_1856 &= 0xf000; 7679a0bf528SMauro Carvalho Chehab reg_1857 = dib8000_read_word(state, 1857); 7689a0bf528SMauro Carvalho Chehab /* disable PLL */ 7699a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15)); 7709a0bf528SMauro Carvalho Chehab 7719a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, reg_1856 | 7729a0bf528SMauro Carvalho Chehab ((pll->pll_ratio & 0x3f) << 6) | 7739a0bf528SMauro Carvalho Chehab (pll->pll_prediv & 0x3f)); 7749a0bf528SMauro Carvalho Chehab 7759a0bf528SMauro Carvalho Chehab /* write new system clk into P_sec_len */ 7769a0bf528SMauro Carvalho Chehab internal = dib8000_read32(state, 23) / 1000; 7778af16adfSMauro Carvalho Chehab dprintk("Old Internal = %d\n", internal); 7789a0bf528SMauro Carvalho Chehab xtal = 2 * (internal / loopdiv) * prediv; 7799a0bf528SMauro Carvalho Chehab internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio; 7808af16adfSMauro Carvalho Chehab dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d\n", xtal, internal/1000, internal/2000, internal/8000); 7818af16adfSMauro Carvalho Chehab dprintk("New Internal = %d\n", internal); 7829a0bf528SMauro Carvalho Chehab 7839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, 7849a0bf528SMauro Carvalho Chehab (u16) (((internal / 2) >> 16) & 0xffff)); 7859a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff)); 7869a0bf528SMauro Carvalho Chehab /* enable PLL */ 7879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 | (1 << 15)); 7889a0bf528SMauro Carvalho Chehab 7899a0bf528SMauro Carvalho Chehab while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1) 7908af16adfSMauro Carvalho Chehab dprintk("Waiting for PLL to lock\n"); 7919a0bf528SMauro Carvalho Chehab 7929a0bf528SMauro Carvalho Chehab /* verify */ 7939a0bf528SMauro Carvalho Chehab reg_1856 = dib8000_read_word(state, 1856); 7948af16adfSMauro Carvalho Chehab dprintk("PLL Updated with prediv = %d and loopdiv = %d\n", 7959a0bf528SMauro Carvalho Chehab reg_1856&0x3f, (reg_1856>>6)&0x3f); 796173a64cbSPatrick Boettcher } else { 797173a64cbSPatrick Boettcher if (bw != state->current_demod_bw) { 798173a64cbSPatrick Boettcher /** Bandwidth change => force PLL update **/ 7998af16adfSMauro Carvalho Chehab dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)\n", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv); 800173a64cbSPatrick Boettcher 801173a64cbSPatrick Boettcher if (state->cfg.pll->pll_prediv != oldprediv) { 802173a64cbSPatrick Boettcher /** Full PLL change only if prediv is changed **/ 803173a64cbSPatrick Boettcher 804173a64cbSPatrick Boettcher /** full update => bypass and reconfigure **/ 8058af16adfSMauro Carvalho Chehab dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)\n", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio); 806173a64cbSPatrick Boettcher dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */ 807173a64cbSPatrick Boettcher dib8000_reset_pll(state); 808173a64cbSPatrick Boettcher dib8000_write_word(state, 898, 0x0004); /* sad */ 809173a64cbSPatrick Boettcher } else 810173a64cbSPatrick Boettcher ratio = state->cfg.pll->pll_ratio; 811173a64cbSPatrick Boettcher 812173a64cbSPatrick Boettcher state->current_demod_bw = bw; 813173a64cbSPatrick Boettcher } 814173a64cbSPatrick Boettcher 815173a64cbSPatrick Boettcher if (ratio != 0) { 816173a64cbSPatrick Boettcher /** ratio update => only change ratio **/ 8178af16adfSMauro Carvalho Chehab dprintk("PLL: Update ratio (prediv: %d, ratio: %d)\n", state->cfg.pll->pll_prediv, ratio); 818173a64cbSPatrick Boettcher dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ 819173a64cbSPatrick Boettcher } 820173a64cbSPatrick Boettcher } 8219a0bf528SMauro Carvalho Chehab 8229a0bf528SMauro Carvalho Chehab return 0; 8239a0bf528SMauro Carvalho Chehab } 8249a0bf528SMauro Carvalho Chehab 8259a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st) 8269a0bf528SMauro Carvalho Chehab { 8279a0bf528SMauro Carvalho Chehab /* reset the GPIOs */ 8289a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir); 8299a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val); 8309a0bf528SMauro Carvalho Chehab 8319a0bf528SMauro Carvalho Chehab /* TODO 782 is P_gpio_od */ 8329a0bf528SMauro Carvalho Chehab 8339a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos); 8349a0bf528SMauro Carvalho Chehab 8359a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1037, st->cfg.pwm_freq_div); 8369a0bf528SMauro Carvalho Chehab return 0; 8379a0bf528SMauro Carvalho Chehab } 8389a0bf528SMauro Carvalho Chehab 8399a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val) 8409a0bf528SMauro Carvalho Chehab { 8419a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir = dib8000_read_word(st, 1029); 8429a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */ 8439a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */ 8449a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir); 8459a0bf528SMauro Carvalho Chehab 8469a0bf528SMauro Carvalho Chehab st->cfg.gpio_val = dib8000_read_word(st, 1030); 8479a0bf528SMauro Carvalho Chehab st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */ 8489a0bf528SMauro Carvalho Chehab st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */ 8499a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val); 8509a0bf528SMauro Carvalho Chehab 8518af16adfSMauro Carvalho Chehab dprintk("gpio dir: %x: gpio val: %x\n", st->cfg.gpio_dir, st->cfg.gpio_val); 8529a0bf528SMauro Carvalho Chehab 8539a0bf528SMauro Carvalho Chehab return 0; 8549a0bf528SMauro Carvalho Chehab } 8559a0bf528SMauro Carvalho Chehab 856d44913c1SMauro Carvalho Chehab static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) 8579a0bf528SMauro Carvalho Chehab { 8589a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 8599a0bf528SMauro Carvalho Chehab return dib8000_cfg_gpio(state, num, dir, val); 8609a0bf528SMauro Carvalho Chehab } 8619a0bf528SMauro Carvalho Chehab 8629a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = { 8639a0bf528SMauro Carvalho Chehab /* auto search configuration - lock0 by default waiting 8649a0bf528SMauro Carvalho Chehab * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */ 8659a0bf528SMauro Carvalho Chehab 3, 7, 8669a0bf528SMauro Carvalho Chehab 0x0004, 8679a0bf528SMauro Carvalho Chehab 0x0400, 8689a0bf528SMauro Carvalho Chehab 0x0814, 8699a0bf528SMauro Carvalho Chehab 8709a0bf528SMauro Carvalho Chehab 12, 11, 8719a0bf528SMauro Carvalho Chehab 0x001b, 8729a0bf528SMauro Carvalho Chehab 0x7740, 8739a0bf528SMauro Carvalho Chehab 0x005b, 8749a0bf528SMauro Carvalho Chehab 0x8d80, 8759a0bf528SMauro Carvalho Chehab 0x01c9, 8769a0bf528SMauro Carvalho Chehab 0xc380, 8779a0bf528SMauro Carvalho Chehab 0x0000, 8789a0bf528SMauro Carvalho Chehab 0x0080, 8799a0bf528SMauro Carvalho Chehab 0x0000, 8809a0bf528SMauro Carvalho Chehab 0x0090, 8819a0bf528SMauro Carvalho Chehab 0x0001, 8829a0bf528SMauro Carvalho Chehab 0xd4c0, 8839a0bf528SMauro Carvalho Chehab 8849a0bf528SMauro Carvalho Chehab /*1, 32, 8859a0bf528SMauro Carvalho Chehab 0x6680 // P_corm_thres Lock algorithms configuration */ 8869a0bf528SMauro Carvalho Chehab 8879a0bf528SMauro Carvalho Chehab 11, 80, /* set ADC level to -16 */ 8889a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117, 8899a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117, 8909a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117, 8919a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117, 8929a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117, 8939a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117, 8949a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117, 8959a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117, 8969a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117, 8979a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117, 8989a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117, 8999a0bf528SMauro Carvalho Chehab 9009a0bf528SMauro Carvalho Chehab 4, 108, 9019a0bf528SMauro Carvalho Chehab 0, 9029a0bf528SMauro Carvalho Chehab 0, 9039a0bf528SMauro Carvalho Chehab 0, 9049a0bf528SMauro Carvalho Chehab 0, 9059a0bf528SMauro Carvalho Chehab 9069a0bf528SMauro Carvalho Chehab 1, 175, 9079a0bf528SMauro Carvalho Chehab 0x0410, 9089a0bf528SMauro Carvalho Chehab 1, 179, 9099a0bf528SMauro Carvalho Chehab 8192, // P_fft_nb_to_cut 9109a0bf528SMauro Carvalho Chehab 9119a0bf528SMauro Carvalho Chehab 6, 181, 9129a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800 9139a0bf528SMauro Carvalho Chehab 0x2800, 9149a0bf528SMauro Carvalho Chehab 0x2800, 9159a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800 9169a0bf528SMauro Carvalho Chehab 0x2800, 9179a0bf528SMauro Carvalho Chehab 0x2800, 9189a0bf528SMauro Carvalho Chehab 9199a0bf528SMauro Carvalho Chehab 2, 193, 9209a0bf528SMauro Carvalho Chehab 0x0666, // P_pha3_thres 9219a0bf528SMauro Carvalho Chehab 0x0000, // P_cti_use_cpe, P_cti_use_prog 9229a0bf528SMauro Carvalho Chehab 9239a0bf528SMauro Carvalho Chehab 2, 205, 9249a0bf528SMauro Carvalho Chehab 0x200f, // P_cspu_regul, P_cspu_win_cut 9259a0bf528SMauro Carvalho Chehab 0x000f, // P_des_shift_work 9269a0bf528SMauro Carvalho Chehab 9279a0bf528SMauro Carvalho Chehab 5, 215, 9289a0bf528SMauro Carvalho Chehab 0x023d, // P_adp_regul_cnt 9299a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_noise_cnt 9309a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_regul_ext 9319a0bf528SMauro Carvalho Chehab 0x7ff0, // P_adp_noise_ext 9329a0bf528SMauro Carvalho Chehab 0x3ccc, // P_adp_fil 9339a0bf528SMauro Carvalho Chehab 9349a0bf528SMauro Carvalho Chehab 1, 230, 9359a0bf528SMauro Carvalho Chehab 0x0000, // P_2d_byp_ti_num 9369a0bf528SMauro Carvalho Chehab 9379a0bf528SMauro Carvalho Chehab 1, 263, 9389a0bf528SMauro Carvalho Chehab 0x800, //P_equal_thres_wgn 9399a0bf528SMauro Carvalho Chehab 9409a0bf528SMauro Carvalho Chehab 1, 268, 9419a0bf528SMauro Carvalho Chehab (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode 9429a0bf528SMauro Carvalho Chehab 9439a0bf528SMauro Carvalho Chehab 1, 270, 9449a0bf528SMauro Carvalho Chehab 0x0001, // P_div_lock0_wait 9459a0bf528SMauro Carvalho Chehab 1, 285, 9469a0bf528SMauro Carvalho Chehab 0x0020, //p_fec_ 9479a0bf528SMauro Carvalho Chehab 1, 299, 9489a0bf528SMauro Carvalho Chehab 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */ 9499a0bf528SMauro Carvalho Chehab 9509a0bf528SMauro Carvalho Chehab 1, 338, 9519a0bf528SMauro Carvalho Chehab (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 9529a0bf528SMauro Carvalho Chehab (1 << 10) | 9539a0bf528SMauro Carvalho Chehab (0 << 9) | /* P_ctrl_pre_freq_inh=0 */ 9549a0bf528SMauro Carvalho Chehab (3 << 5) | /* P_ctrl_pre_freq_step=3 */ 9559a0bf528SMauro Carvalho Chehab (1 << 0), /* P_pre_freq_win_len=1 */ 9569a0bf528SMauro Carvalho Chehab 9579a0bf528SMauro Carvalho Chehab 0, 9589a0bf528SMauro Carvalho Chehab }; 9599a0bf528SMauro Carvalho Chehab 9609a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client) 9619a0bf528SMauro Carvalho Chehab { 9629a0bf528SMauro Carvalho Chehab u16 value; 9639a0bf528SMauro Carvalho Chehab 9649a0bf528SMauro Carvalho Chehab //because of glitches sometimes 9659a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 896); 9669a0bf528SMauro Carvalho Chehab 9679a0bf528SMauro Carvalho Chehab if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) { 9688af16adfSMauro Carvalho Chehab dprintk("wrong Vendor ID (read=0x%x)\n", value); 9699a0bf528SMauro Carvalho Chehab return 0; 9709a0bf528SMauro Carvalho Chehab } 9719a0bf528SMauro Carvalho Chehab 9729a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 897); 9739a0bf528SMauro Carvalho Chehab if (value != 0x8000 && value != 0x8001 && 9749a0bf528SMauro Carvalho Chehab value != 0x8002 && value != 0x8090) { 9758af16adfSMauro Carvalho Chehab dprintk("wrong Device ID (%x)\n", value); 9769a0bf528SMauro Carvalho Chehab return 0; 9779a0bf528SMauro Carvalho Chehab } 9789a0bf528SMauro Carvalho Chehab 9799a0bf528SMauro Carvalho Chehab switch (value) { 9809a0bf528SMauro Carvalho Chehab case 0x8000: 9818af16adfSMauro Carvalho Chehab dprintk("found DiB8000A\n"); 9829a0bf528SMauro Carvalho Chehab break; 9839a0bf528SMauro Carvalho Chehab case 0x8001: 9848af16adfSMauro Carvalho Chehab dprintk("found DiB8000B\n"); 9859a0bf528SMauro Carvalho Chehab break; 9869a0bf528SMauro Carvalho Chehab case 0x8002: 9878af16adfSMauro Carvalho Chehab dprintk("found DiB8000C\n"); 9889a0bf528SMauro Carvalho Chehab break; 9899a0bf528SMauro Carvalho Chehab case 0x8090: 9908af16adfSMauro Carvalho Chehab dprintk("found DiB8096P\n"); 9919a0bf528SMauro Carvalho Chehab break; 9929a0bf528SMauro Carvalho Chehab } 9939a0bf528SMauro Carvalho Chehab return value; 9949a0bf528SMauro Carvalho Chehab } 9959a0bf528SMauro Carvalho Chehab 9967a9d85d5SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc); 9977a9d85d5SMauro Carvalho Chehab 9986ef06e78SMauro Carvalho Chehab static void dib8000_reset_stats(struct dvb_frontend *fe) 9996ef06e78SMauro Carvalho Chehab { 10006ef06e78SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 10016ef06e78SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 10027a9d85d5SMauro Carvalho Chehab u32 ucb; 10036ef06e78SMauro Carvalho Chehab 10046ef06e78SMauro Carvalho Chehab memset(&c->strength, 0, sizeof(c->strength)); 10056ef06e78SMauro Carvalho Chehab memset(&c->cnr, 0, sizeof(c->cnr)); 10066ef06e78SMauro Carvalho Chehab memset(&c->post_bit_error, 0, sizeof(c->post_bit_error)); 10076ef06e78SMauro Carvalho Chehab memset(&c->post_bit_count, 0, sizeof(c->post_bit_count)); 10086ef06e78SMauro Carvalho Chehab memset(&c->block_error, 0, sizeof(c->block_error)); 10096ef06e78SMauro Carvalho Chehab 10106ef06e78SMauro Carvalho Chehab c->strength.len = 1; 10116ef06e78SMauro Carvalho Chehab c->cnr.len = 1; 10126ef06e78SMauro Carvalho Chehab c->block_error.len = 1; 10130400c535SMauro Carvalho Chehab c->block_count.len = 1; 10146ef06e78SMauro Carvalho Chehab c->post_bit_error.len = 1; 10156ef06e78SMauro Carvalho Chehab c->post_bit_count.len = 1; 10166ef06e78SMauro Carvalho Chehab 1017b4600d70SMauro Carvalho Chehab c->strength.stat[0].scale = FE_SCALE_DECIBEL; 10186ef06e78SMauro Carvalho Chehab c->strength.stat[0].uvalue = 0; 10196ef06e78SMauro Carvalho Chehab 10206ef06e78SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10216ef06e78SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10220400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10236ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10246ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10257a9d85d5SMauro Carvalho Chehab 10267a9d85d5SMauro Carvalho Chehab dib8000_read_unc_blocks(fe, &ucb); 1027704f01bbSMauro Carvalho Chehab 10287a9d85d5SMauro Carvalho Chehab state->init_ucb = -ucb; 10290400c535SMauro Carvalho Chehab state->ber_jiffies_stats = 0; 10300400c535SMauro Carvalho Chehab state->per_jiffies_stats = 0; 10310400c535SMauro Carvalho Chehab memset(&state->ber_jiffies_stats_layer, 0, 10320400c535SMauro Carvalho Chehab sizeof(state->ber_jiffies_stats_layer)); 10336ef06e78SMauro Carvalho Chehab } 10346ef06e78SMauro Carvalho Chehab 10359a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe) 10369a0bf528SMauro Carvalho Chehab { 10379a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 10389a0bf528SMauro Carvalho Chehab 10399a0bf528SMauro Carvalho Chehab if ((state->revision = dib8000_identify(&state->i2c)) == 0) 10409a0bf528SMauro Carvalho Chehab return -EINVAL; 10419a0bf528SMauro Carvalho Chehab 10429a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */ 10439a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 10449a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, 0x0003); 10459a0bf528SMauro Carvalho Chehab 10469a0bf528SMauro Carvalho Chehab if (state->revision == 0x8000) 10478af16adfSMauro Carvalho Chehab dprintk("error : dib8000 MA not supported\n"); 10489a0bf528SMauro Carvalho Chehab 10499a0bf528SMauro Carvalho Chehab dibx000_reset_i2c_master(&state->i2c_master); 10509a0bf528SMauro Carvalho Chehab 10519a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 10529a0bf528SMauro Carvalho Chehab 10539a0bf528SMauro Carvalho Chehab /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ 1054173a64cbSPatrick Boettcher dib8000_set_adc_state(state, DIBX000_ADC_OFF); 10559a0bf528SMauro Carvalho Chehab 10569a0bf528SMauro Carvalho Chehab /* restart all parts */ 10579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0xffff); 10589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0xffff); 10599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0xfffc); 10606d38454aSMauro Carvalho Chehab dib8000_write_word(state, 898, 0x000c); /* restart sad */ 10619a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 10629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0045); 10639a0bf528SMauro Carvalho Chehab else 10649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x004d); 10659a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x000c); 10669a0bf528SMauro Carvalho Chehab 10679a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000); 10689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0x0000); 10699a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0x0000); 10709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004); // sad 10719a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0000); 10729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x0000); 10739a0bf528SMauro Carvalho Chehab 10749a0bf528SMauro Carvalho Chehab /* drives */ 10759a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 10769a0bf528SMauro Carvalho Chehab if (state->cfg.drives) 10779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, state->cfg.drives); 10789a0bf528SMauro Carvalho Chehab else { 10798af16adfSMauro Carvalho Chehab dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.\n"); 10809a0bf528SMauro Carvalho Chehab /* min drive SDRAM - not optimal - adjust */ 10819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, 0x2d98); 10829a0bf528SMauro Carvalho Chehab } 10839a0bf528SMauro Carvalho Chehab } 10849a0bf528SMauro Carvalho Chehab 10859a0bf528SMauro Carvalho Chehab dib8000_reset_pll(state); 10869a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 10879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004); 10889a0bf528SMauro Carvalho Chehab 10899a0bf528SMauro Carvalho Chehab if (dib8000_reset_gpio(state) != 0) 10908af16adfSMauro Carvalho Chehab dprintk("GPIO reset was not successful.\n"); 10919a0bf528SMauro Carvalho Chehab 10929a0bf528SMauro Carvalho Chehab if ((state->revision != 0x8090) && 10939a0bf528SMauro Carvalho Chehab (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)) 10948af16adfSMauro Carvalho Chehab dprintk("OUTPUT_MODE could not be resetted.\n"); 10959a0bf528SMauro Carvalho Chehab 10969a0bf528SMauro Carvalho Chehab state->current_agc = NULL; 10979a0bf528SMauro Carvalho Chehab 10989a0bf528SMauro Carvalho Chehab // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... 10999a0bf528SMauro Carvalho Chehab /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */ 11009a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ifreq == 0) 11019a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */ 11029a0bf528SMauro Carvalho Chehab else 11039a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */ 11049a0bf528SMauro Carvalho Chehab 11059a0bf528SMauro Carvalho Chehab { 11069a0bf528SMauro Carvalho Chehab u16 l = 0, r; 11079a0bf528SMauro Carvalho Chehab const u16 *n; 11089a0bf528SMauro Carvalho Chehab n = dib8000_defaults; 11099a0bf528SMauro Carvalho Chehab l = *n++; 11109a0bf528SMauro Carvalho Chehab while (l) { 11119a0bf528SMauro Carvalho Chehab r = *n++; 11129a0bf528SMauro Carvalho Chehab do { 11139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, r, *n++); 11149a0bf528SMauro Carvalho Chehab r++; 11159a0bf528SMauro Carvalho Chehab } while (--l); 11169a0bf528SMauro Carvalho Chehab l = *n++; 11179a0bf528SMauro Carvalho Chehab } 11189a0bf528SMauro Carvalho Chehab } 1119173a64cbSPatrick Boettcher 11209a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0; 11219a0bf528SMauro Carvalho Chehab 11229a0bf528SMauro Carvalho Chehab //div_cfg override for special configs 1123173a64cbSPatrick Boettcher if ((state->revision != 8090) && (state->cfg.div_cfg != 0)) 11249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 903, state->cfg.div_cfg); 11259a0bf528SMauro Carvalho Chehab 11269a0bf528SMauro Carvalho Chehab /* unforce divstr regardless whether i2c enumeration was done or not */ 11279a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1)); 11289a0bf528SMauro Carvalho Chehab 11299a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(fe, 6000); 11309a0bf528SMauro Carvalho Chehab 11319a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); 11329a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state); 1133173a64cbSPatrick Boettcher if (state->revision != 0x8090) 11349a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); 1135173a64cbSPatrick Boettcher 1136173a64cbSPatrick Boettcher /* ber_rs_len = 3 */ 1137173a64cbSPatrick Boettcher dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); 11389a0bf528SMauro Carvalho Chehab 11399a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); 11409a0bf528SMauro Carvalho Chehab 11416ef06e78SMauro Carvalho Chehab dib8000_reset_stats(fe); 11426ef06e78SMauro Carvalho Chehab 11439a0bf528SMauro Carvalho Chehab return 0; 11449a0bf528SMauro Carvalho Chehab } 11459a0bf528SMauro Carvalho Chehab 11469a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state) 11479a0bf528SMauro Carvalho Chehab { 11489a0bf528SMauro Carvalho Chehab // P_restart_iqc & P_restart_agc 11499a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0a00); 11509a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000); 11519a0bf528SMauro Carvalho Chehab } 11529a0bf528SMauro Carvalho Chehab 11539a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state) 11549a0bf528SMauro Carvalho Chehab { 11559a0bf528SMauro Carvalho Chehab u16 dyn_gain; 11569a0bf528SMauro Carvalho Chehab 11579a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna) { 11589a0bf528SMauro Carvalho Chehab // read dyn_gain here (because it is demod-dependent and not tuner) 11599a0bf528SMauro Carvalho Chehab dyn_gain = dib8000_read_word(state, 390); 11609a0bf528SMauro Carvalho Chehab 11619a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna(state->fe[0], dyn_gain)) { 11629a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state); 11639a0bf528SMauro Carvalho Chehab return 1; 11649a0bf528SMauro Carvalho Chehab } 11659a0bf528SMauro Carvalho Chehab } 11669a0bf528SMauro Carvalho Chehab return 0; 11679a0bf528SMauro Carvalho Chehab } 11689a0bf528SMauro Carvalho Chehab 11699a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) 11709a0bf528SMauro Carvalho Chehab { 11719a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *agc = NULL; 11729a0bf528SMauro Carvalho Chehab int i; 11739a0bf528SMauro Carvalho Chehab u16 reg; 11749a0bf528SMauro Carvalho Chehab 11759a0bf528SMauro Carvalho Chehab if (state->current_band == band && state->current_agc != NULL) 11769a0bf528SMauro Carvalho Chehab return 0; 11779a0bf528SMauro Carvalho Chehab state->current_band = band; 11789a0bf528SMauro Carvalho Chehab 11799a0bf528SMauro Carvalho Chehab for (i = 0; i < state->cfg.agc_config_count; i++) 11809a0bf528SMauro Carvalho Chehab if (state->cfg.agc[i].band_caps & band) { 11819a0bf528SMauro Carvalho Chehab agc = &state->cfg.agc[i]; 11829a0bf528SMauro Carvalho Chehab break; 11839a0bf528SMauro Carvalho Chehab } 11849a0bf528SMauro Carvalho Chehab 11859a0bf528SMauro Carvalho Chehab if (agc == NULL) { 11868af16adfSMauro Carvalho Chehab dprintk("no valid AGC configuration found for band 0x%02x\n", band); 11879a0bf528SMauro Carvalho Chehab return -EINVAL; 11889a0bf528SMauro Carvalho Chehab } 11899a0bf528SMauro Carvalho Chehab 11909a0bf528SMauro Carvalho Chehab state->current_agc = agc; 11919a0bf528SMauro Carvalho Chehab 11929a0bf528SMauro Carvalho Chehab /* AGC */ 11939a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 76, agc->setup); 11949a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 77, agc->inv_gain); 11959a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 78, agc->time_stabiliz); 11969a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock); 11979a0bf528SMauro Carvalho Chehab 11989a0bf528SMauro Carvalho Chehab // Demod AGC loop configuration 11999a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp); 12009a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp); 12019a0bf528SMauro Carvalho Chehab 12028af16adfSMauro Carvalho Chehab dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", 12039a0bf528SMauro Carvalho Chehab state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); 12049a0bf528SMauro Carvalho Chehab 12059a0bf528SMauro Carvalho Chehab /* AGC continued */ 12069a0bf528SMauro Carvalho Chehab if (state->wbd_ref != 0) 12079a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, state->wbd_ref); 12089a0bf528SMauro Carvalho Chehab else // use default 12099a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, agc->wbd_ref); 12109a0bf528SMauro Carvalho Chehab 12119a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 12129a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 922) & (0x3 << 2); 12139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2)); 12149a0bf528SMauro Carvalho Chehab } 12159a0bf528SMauro Carvalho Chehab 12169a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); 12179a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 108, agc->agc1_max); 12189a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 109, agc->agc1_min); 12199a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 110, agc->agc2_max); 12209a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 111, agc->agc2_min); 12219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2); 12229a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); 12239a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); 12249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); 12259a0bf528SMauro Carvalho Chehab 12269a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 75, agc->agc1_pt3); 12279a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 12289a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, 12299a0bf528SMauro Carvalho Chehab (dib8000_read_word(state, 923) & 0xffe3) | 12309a0bf528SMauro Carvalho Chehab (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); 12319a0bf528SMauro Carvalho Chehab 12329a0bf528SMauro Carvalho Chehab return 0; 12339a0bf528SMauro Carvalho Chehab } 12349a0bf528SMauro Carvalho Chehab 1235d44913c1SMauro Carvalho Chehab static void dib8000_pwm_agc_reset(struct dvb_frontend *fe) 12369a0bf528SMauro Carvalho Chehab { 12379a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 12389a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 12399a0bf528SMauro Carvalho Chehab dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); 12409a0bf528SMauro Carvalho Chehab } 12419a0bf528SMauro Carvalho Chehab 12429a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state) 12439a0bf528SMauro Carvalho Chehab { 12449a0bf528SMauro Carvalho Chehab u16 agc, split_offset; 12459a0bf528SMauro Carvalho Chehab 12469a0bf528SMauro Carvalho Chehab if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) 1247d6c62b76SMauro Carvalho Chehab return 0; 12489a0bf528SMauro Carvalho Chehab 12499a0bf528SMauro Carvalho Chehab // n_agc_global 12509a0bf528SMauro Carvalho Chehab agc = dib8000_read_word(state, 390); 12519a0bf528SMauro Carvalho Chehab 12529a0bf528SMauro Carvalho Chehab if (agc > state->current_agc->split.min_thres) 12539a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.min; 12549a0bf528SMauro Carvalho Chehab else if (agc < state->current_agc->split.max_thres) 12559a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max; 12569a0bf528SMauro Carvalho Chehab else 12579a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max * 12589a0bf528SMauro Carvalho Chehab (agc - state->current_agc->split.min_thres) / 12599a0bf528SMauro Carvalho Chehab (state->current_agc->split.max_thres - state->current_agc->split.min_thres); 12609a0bf528SMauro Carvalho Chehab 12618af16adfSMauro Carvalho Chehab dprintk("AGC split_offset: %d\n", split_offset); 12629a0bf528SMauro Carvalho Chehab 12639a0bf528SMauro Carvalho Chehab // P_agc_force_split and P_agc_split_offset 12649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset); 12659a0bf528SMauro Carvalho Chehab return 5000; 12669a0bf528SMauro Carvalho Chehab } 12679a0bf528SMauro Carvalho Chehab 12689a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe) 12699a0bf528SMauro Carvalho Chehab { 12709a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 12719a0bf528SMauro Carvalho Chehab enum frontend_tune_state *tune_state = &state->tune_state; 12729a0bf528SMauro Carvalho Chehab int ret = 0; 1273901c4ad6SMauro Carvalho Chehab u16 reg; 1274901c4ad6SMauro Carvalho Chehab u32 upd_demod_gain_period = 0x8000; 12759a0bf528SMauro Carvalho Chehab 12769a0bf528SMauro Carvalho Chehab switch (*tune_state) { 12779a0bf528SMauro Carvalho Chehab case CT_AGC_START: 12789a0bf528SMauro Carvalho Chehab // set power-up level: interf+analog+AGC 12799a0bf528SMauro Carvalho Chehab 12809a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 12819a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 12829a0bf528SMauro Carvalho Chehab else { 12839a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 12849a0bf528SMauro Carvalho Chehab 12859a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1947)&0xff00; 12869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1946, 12879a0bf528SMauro Carvalho Chehab upd_demod_gain_period & 0xFFFF); 12889a0bf528SMauro Carvalho Chehab /* bit 14 = enDemodGain */ 12899a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1947, reg | (1<<14) | 12909a0bf528SMauro Carvalho Chehab ((upd_demod_gain_period >> 16) & 0xFF)); 12919a0bf528SMauro Carvalho Chehab 12929a0bf528SMauro Carvalho Chehab /* enable adc i & q */ 12939a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1920); 12949a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1920, (reg | 0x3) & 12959a0bf528SMauro Carvalho Chehab (~(1 << 7))); 12969a0bf528SMauro Carvalho Chehab } 12979a0bf528SMauro Carvalho Chehab 12989a0bf528SMauro Carvalho Chehab if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { 12999a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP; 13009a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_TUNE_FAILED; 13019a0bf528SMauro Carvalho Chehab break; 13029a0bf528SMauro Carvalho Chehab } 13039a0bf528SMauro Carvalho Chehab 13049a0bf528SMauro Carvalho Chehab ret = 70; 13059a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_0; 13069a0bf528SMauro Carvalho Chehab break; 13079a0bf528SMauro Carvalho Chehab 13089a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_0: 13099a0bf528SMauro Carvalho Chehab //AGC initialization 13109a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 13119a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 1); 13129a0bf528SMauro Carvalho Chehab 13139a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state); 13149a0bf528SMauro Carvalho Chehab 13159a0bf528SMauro Carvalho Chehab // wait AGC rough lock time 13169a0bf528SMauro Carvalho Chehab ret = 50; 13179a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_1; 13189a0bf528SMauro Carvalho Chehab break; 13199a0bf528SMauro Carvalho Chehab 13209a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_1: 13219a0bf528SMauro Carvalho Chehab // wait AGC accurate lock time 13229a0bf528SMauro Carvalho Chehab ret = 70; 13239a0bf528SMauro Carvalho Chehab 13249a0bf528SMauro Carvalho Chehab if (dib8000_update_lna(state)) 13259a0bf528SMauro Carvalho Chehab // wait only AGC rough lock time 13269a0bf528SMauro Carvalho Chehab ret = 50; 13279a0bf528SMauro Carvalho Chehab else 13289a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_2; 13299a0bf528SMauro Carvalho Chehab break; 13309a0bf528SMauro Carvalho Chehab 13319a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_2: 13329a0bf528SMauro Carvalho Chehab dib8000_agc_soft_split(state); 13339a0bf528SMauro Carvalho Chehab 13349a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 13359a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 0); 13369a0bf528SMauro Carvalho Chehab 13379a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP; 13389a0bf528SMauro Carvalho Chehab break; 13399a0bf528SMauro Carvalho Chehab default: 13409a0bf528SMauro Carvalho Chehab ret = dib8000_agc_soft_split(state); 13419a0bf528SMauro Carvalho Chehab break; 13429a0bf528SMauro Carvalho Chehab } 13439a0bf528SMauro Carvalho Chehab return ret; 13449a0bf528SMauro Carvalho Chehab 13459a0bf528SMauro Carvalho Chehab } 13469a0bf528SMauro Carvalho Chehab 13479a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive) 13489a0bf528SMauro Carvalho Chehab { 13499a0bf528SMauro Carvalho Chehab u16 reg; 13509a0bf528SMauro Carvalho Chehab 13519a0bf528SMauro Carvalho Chehab drive &= 0x7; 13529a0bf528SMauro Carvalho Chehab 13539a0bf528SMauro Carvalho Chehab /* drive host bus 2, 3, 4 */ 13549a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1798) & 13559a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13569a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1798, reg); 13589a0bf528SMauro Carvalho Chehab 13599a0bf528SMauro Carvalho Chehab /* drive host bus 5,6 */ 13609a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); 13619a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2); 13629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1799, reg); 13639a0bf528SMauro Carvalho Chehab 13649a0bf528SMauro Carvalho Chehab /* drive host bus 7, 8, 9 */ 13659a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1800) & 13669a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13679a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1800, reg); 13699a0bf528SMauro Carvalho Chehab 13709a0bf528SMauro Carvalho Chehab /* drive host bus 10, 11 */ 13719a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); 13729a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2); 13739a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1801, reg); 13749a0bf528SMauro Carvalho Chehab 13759a0bf528SMauro Carvalho Chehab /* drive host bus 12, 13, 14 */ 13769a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1802) & 13779a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13789a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13799a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1802, reg); 13809a0bf528SMauro Carvalho Chehab } 13819a0bf528SMauro Carvalho Chehab 13829a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout, 13839a0bf528SMauro Carvalho Chehab u32 insertExtSynchro, u32 syncSize) 13849a0bf528SMauro Carvalho Chehab { 13859a0bf528SMauro Carvalho Chehab u32 quantif = 3; 13869a0bf528SMauro Carvalho Chehab u32 nom = (insertExtSynchro * P_Kin+syncSize); 13879a0bf528SMauro Carvalho Chehab u32 denom = P_Kout; 13889a0bf528SMauro Carvalho Chehab u32 syncFreq = ((nom << quantif) / denom); 13899a0bf528SMauro Carvalho Chehab 13909a0bf528SMauro Carvalho Chehab if ((syncFreq & ((1 << quantif) - 1)) != 0) 13919a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif) + 1; 13929a0bf528SMauro Carvalho Chehab else 13939a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif); 13949a0bf528SMauro Carvalho Chehab 13959a0bf528SMauro Carvalho Chehab if (syncFreq != 0) 13969a0bf528SMauro Carvalho Chehab syncFreq = syncFreq - 1; 13979a0bf528SMauro Carvalho Chehab 13989a0bf528SMauro Carvalho Chehab return syncFreq; 13999a0bf528SMauro Carvalho Chehab } 14009a0bf528SMauro Carvalho Chehab 14019a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin, 14029a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, 14039a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize) 14049a0bf528SMauro Carvalho Chehab { 14058af16adfSMauro Carvalho Chehab dprintk("Configure DibStream Tx\n"); 14069a0bf528SMauro Carvalho Chehab 14079a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 1); 14089a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1603, P_Kin); 14099a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1605, P_Kout); 14109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1606, insertExtSynchro); 14119a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1608, synchroMode); 14129a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff); 14139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1610, syncWord & 0xffff); 14149a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1612, syncSize); 14159a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 0); 14169a0bf528SMauro Carvalho Chehab } 14179a0bf528SMauro Carvalho Chehab 14189a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin, 14199a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, 14209a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize, u32 dataOutRate) 14219a0bf528SMauro Carvalho Chehab { 14229a0bf528SMauro Carvalho Chehab u32 syncFreq; 14239a0bf528SMauro Carvalho Chehab 14248af16adfSMauro Carvalho Chehab dprintk("Configure DibStream Rx synchroMode = %d\n", synchroMode); 14259a0bf528SMauro Carvalho Chehab 14269a0bf528SMauro Carvalho Chehab if ((P_Kin != 0) && (P_Kout != 0)) { 14279a0bf528SMauro Carvalho Chehab syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout, 14289a0bf528SMauro Carvalho Chehab insertExtSynchro, syncSize); 14299a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1542, syncFreq); 14309a0bf528SMauro Carvalho Chehab } 14319a0bf528SMauro Carvalho Chehab 14329a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 1); 14339a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1536, P_Kin); 14349a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1537, P_Kout); 14359a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1539, synchroMode); 14369a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff); 14379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1541, syncWord & 0xffff); 14389a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1543, syncSize); 14399a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1544, dataOutRate); 14409a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 0); 14419a0bf528SMauro Carvalho Chehab } 14429a0bf528SMauro Carvalho Chehab 14439a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff) 14449a0bf528SMauro Carvalho Chehab { 14459a0bf528SMauro Carvalho Chehab u16 reg_1287; 14469a0bf528SMauro Carvalho Chehab 14479a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287); 14489a0bf528SMauro Carvalho Chehab 14499a0bf528SMauro Carvalho Chehab switch (onoff) { 14509a0bf528SMauro Carvalho Chehab case 1: 14519a0bf528SMauro Carvalho Chehab reg_1287 &= ~(1 << 8); 14529a0bf528SMauro Carvalho Chehab break; 14539a0bf528SMauro Carvalho Chehab case 0: 14549a0bf528SMauro Carvalho Chehab reg_1287 |= (1 << 8); 14559a0bf528SMauro Carvalho Chehab break; 14569a0bf528SMauro Carvalho Chehab } 14579a0bf528SMauro Carvalho Chehab 14589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 14599a0bf528SMauro Carvalho Chehab } 14609a0bf528SMauro Carvalho Chehab 14619a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state, 14629a0bf528SMauro Carvalho Chehab u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) 14639a0bf528SMauro Carvalho Chehab { 14649a0bf528SMauro Carvalho Chehab u16 reg_1287; 14659a0bf528SMauro Carvalho Chehab 14668af16adfSMauro Carvalho Chehab dprintk("Enable Mpeg mux\n"); 14679a0bf528SMauro Carvalho Chehab 14689a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 14699a0bf528SMauro Carvalho Chehab 14709a0bf528SMauro Carvalho Chehab /* If the input mode is MPEG do not divide the serial clock */ 14719a0bf528SMauro Carvalho Chehab if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) 14729a0bf528SMauro Carvalho Chehab enSerialClkDiv2 = 0; 14739a0bf528SMauro Carvalho Chehab 14749a0bf528SMauro Carvalho Chehab reg_1287 = ((pulseWidth & 0x1f) << 3) | 14759a0bf528SMauro Carvalho Chehab ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1); 14769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 14779a0bf528SMauro Carvalho Chehab 14789a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 1); 14799a0bf528SMauro Carvalho Chehab } 14809a0bf528SMauro Carvalho Chehab 14819a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode) 14829a0bf528SMauro Carvalho Chehab { 14839a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7); 14849a0bf528SMauro Carvalho Chehab 14859a0bf528SMauro Carvalho Chehab switch (mode) { 14869a0bf528SMauro Carvalho Chehab case MPEG_ON_DIBTX: 14878af16adfSMauro Carvalho Chehab dprintk("SET MPEG ON DIBSTREAM TX\n"); 14889a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); 14899a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 9); break; 14909a0bf528SMauro Carvalho Chehab case DIV_ON_DIBTX: 14918af16adfSMauro Carvalho Chehab dprintk("SET DIV_OUT ON DIBSTREAM TX\n"); 14929a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); 14939a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 8); break; 14949a0bf528SMauro Carvalho Chehab case ADC_ON_DIBTX: 14958af16adfSMauro Carvalho Chehab dprintk("SET ADC_OUT ON DIBSTREAM TX\n"); 14969a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); 14979a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 7); break; 14989a0bf528SMauro Carvalho Chehab default: 14999a0bf528SMauro Carvalho Chehab break; 15009a0bf528SMauro Carvalho Chehab } 15019a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288); 15029a0bf528SMauro Carvalho Chehab } 15039a0bf528SMauro Carvalho Chehab 15049a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode) 15059a0bf528SMauro Carvalho Chehab { 15069a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4); 15079a0bf528SMauro Carvalho Chehab 15089a0bf528SMauro Carvalho Chehab switch (mode) { 15099a0bf528SMauro Carvalho Chehab case DEMOUT_ON_HOSTBUS: 15108af16adfSMauro Carvalho Chehab dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n"); 15119a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 15129a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 6); 15139a0bf528SMauro Carvalho Chehab break; 15149a0bf528SMauro Carvalho Chehab case DIBTX_ON_HOSTBUS: 15158af16adfSMauro Carvalho Chehab dprintk("SET DIBSTREAM TX ON HOST BUS\n"); 15169a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 15179a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 5); 15189a0bf528SMauro Carvalho Chehab break; 15199a0bf528SMauro Carvalho Chehab case MPEG_ON_HOSTBUS: 15208af16adfSMauro Carvalho Chehab dprintk("SET MPEG MUX ON HOST BUS\n"); 15219a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 4); 15229a0bf528SMauro Carvalho Chehab break; 15239a0bf528SMauro Carvalho Chehab default: 15249a0bf528SMauro Carvalho Chehab break; 15259a0bf528SMauro Carvalho Chehab } 15269a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288); 15279a0bf528SMauro Carvalho Chehab } 15289a0bf528SMauro Carvalho Chehab 15299a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff) 15309a0bf528SMauro Carvalho Chehab { 15319a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 15329a0bf528SMauro Carvalho Chehab u16 reg_1287; 15339a0bf528SMauro Carvalho Chehab 15349a0bf528SMauro Carvalho Chehab switch (onoff) { 15359a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */ 15368af16adfSMauro Carvalho Chehab dprintk("%s mode OFF : by default Enable Mpeg INPUT\n", 15379a0bf528SMauro Carvalho Chehab __func__); 15389a0bf528SMauro Carvalho Chehab /* outputRate = 8 */ 15399a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); 15409a0bf528SMauro Carvalho Chehab 15419a0bf528SMauro Carvalho Chehab /* Do not divide the serial clock of MPEG MUX in 15429a0bf528SMauro Carvalho Chehab SERIAL MODE in case input mode MPEG is used */ 15439a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287); 15449a0bf528SMauro Carvalho Chehab /* enSerialClkDiv2 == 1 ? */ 15459a0bf528SMauro Carvalho Chehab if ((reg_1287 & 0x1) == 1) { 15469a0bf528SMauro Carvalho Chehab /* force enSerialClkDiv2 = 0 */ 15479a0bf528SMauro Carvalho Chehab reg_1287 &= ~0x1; 15489a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 15499a0bf528SMauro Carvalho Chehab } 15509a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 1; 15519a0bf528SMauro Carvalho Chehab break; 15529a0bf528SMauro Carvalho Chehab case 1: /* both ways */ 15539a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */ 15548af16adfSMauro Carvalho Chehab dprintk("%s ON : Enable diversity INPUT\n", __func__); 15559a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); 15569a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 0; 15579a0bf528SMauro Carvalho Chehab break; 15589a0bf528SMauro Carvalho Chehab } 15599a0bf528SMauro Carvalho Chehab 15609a0bf528SMauro Carvalho Chehab dib8000_set_diversity_in(state->fe[0], onoff); 15619a0bf528SMauro Carvalho Chehab return 0; 15629a0bf528SMauro Carvalho Chehab } 15639a0bf528SMauro Carvalho Chehab 15649a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) 15659a0bf528SMauro Carvalho Chehab { 15669a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 15679a0bf528SMauro Carvalho Chehab u16 outreg, smo_mode, fifo_threshold; 15689a0bf528SMauro Carvalho Chehab u8 prefer_mpeg_mux_use = 1; 15699a0bf528SMauro Carvalho Chehab int ret = 0; 15709a0bf528SMauro Carvalho Chehab 1571173a64cbSPatrick Boettcher state->output_mode = mode; 15729a0bf528SMauro Carvalho Chehab dib8096p_host_bus_drive(state, 1); 15739a0bf528SMauro Carvalho Chehab 15749a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 15759a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); 15769a0bf528SMauro Carvalho Chehab outreg = dib8000_read_word(state, 1286) & 15779a0bf528SMauro Carvalho Chehab ~((1 << 10) | (0x7 << 6) | (1 << 1)); 15789a0bf528SMauro Carvalho Chehab 15799a0bf528SMauro Carvalho Chehab switch (mode) { 15809a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: 15819a0bf528SMauro Carvalho Chehab outreg = 0; 15829a0bf528SMauro Carvalho Chehab break; 15839a0bf528SMauro Carvalho Chehab 15849a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 15859a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 15868af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux\n"); 15879a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 3, 1, 1); 15889a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); 15899a0bf528SMauro Carvalho Chehab } else {/* Use Smooth block */ 15908af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc\n"); 15919a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, 15929a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS); 15939a0bf528SMauro Carvalho Chehab outreg |= (2 << 6) | (0 << 1); 15949a0bf528SMauro Carvalho Chehab } 15959a0bf528SMauro Carvalho Chehab break; 15969a0bf528SMauro Carvalho Chehab 15979a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 15989a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 15998af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux\n"); 16009a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 2, 0, 0); 16019a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); 16029a0bf528SMauro Carvalho Chehab } else { /* Use Smooth block */ 16038af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block\n"); 16049a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, 16059a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS); 16069a0bf528SMauro Carvalho Chehab outreg |= (0 << 6); 16079a0bf528SMauro Carvalho Chehab } 16089a0bf528SMauro Carvalho Chehab break; 16099a0bf528SMauro Carvalho Chehab 16109a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ 16118af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block\n"); 16129a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 16139a0bf528SMauro Carvalho Chehab outreg |= (1 << 6); 16149a0bf528SMauro Carvalho Chehab break; 16159a0bf528SMauro Carvalho Chehab 16169a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: 16179a0bf528SMauro Carvalho Chehab /* Using Smooth block because not supported 16189a0bf528SMauro Carvalho Chehab by new Mpeg Mux bloc */ 16198af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_FIFO using Smooth block\n"); 16209a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 16219a0bf528SMauro Carvalho Chehab outreg |= (5 << 6); 16229a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 16239a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 16249a0bf528SMauro Carvalho Chehab break; 16259a0bf528SMauro Carvalho Chehab 16269a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 16278af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_DIVERSITY\n"); 16289a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, DIV_ON_DIBTX); 16299a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 16309a0bf528SMauro Carvalho Chehab break; 16319a0bf528SMauro Carvalho Chehab 16329a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 16338af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_ANALOG_ADC\n"); 16349a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, ADC_ON_DIBTX); 16359a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 16369a0bf528SMauro Carvalho Chehab break; 16379a0bf528SMauro Carvalho Chehab } 16389a0bf528SMauro Carvalho Chehab 16399a0bf528SMauro Carvalho Chehab if (mode != OUTMODE_HIGH_Z) 16409a0bf528SMauro Carvalho Chehab outreg |= (1<<10); 16419a0bf528SMauro Carvalho Chehab 16428af16adfSMauro Carvalho Chehab dprintk("output_mpeg2_in_188_bytes = %d\n", 16439a0bf528SMauro Carvalho Chehab state->cfg.output_mpeg2_in_188_bytes); 16449a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 16459a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 16469a0bf528SMauro Carvalho Chehab 16479a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299, smo_mode); 16489a0bf528SMauro Carvalho Chehab /* synchronous fread */ 16499a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299 + 1, fifo_threshold); 16509a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 1286, outreg); 16519a0bf528SMauro Carvalho Chehab 16529a0bf528SMauro Carvalho Chehab return ret; 16539a0bf528SMauro Carvalho Chehab } 16549a0bf528SMauro Carvalho Chehab 16559a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg) 16569a0bf528SMauro Carvalho Chehab { 16579a0bf528SMauro Carvalho Chehab if (msg->buf[0] <= 15) 16589a0bf528SMauro Carvalho Chehab msg->buf[0] -= 1; 16599a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 17) 16609a0bf528SMauro Carvalho Chehab msg->buf[0] = 15; 16619a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 16) 16629a0bf528SMauro Carvalho Chehab msg->buf[0] = 17; 16639a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 19) 16649a0bf528SMauro Carvalho Chehab msg->buf[0] = 16; 16659a0bf528SMauro Carvalho Chehab else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) 16669a0bf528SMauro Carvalho Chehab msg->buf[0] -= 3; 16679a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 28) 16689a0bf528SMauro Carvalho Chehab msg->buf[0] = 23; 16699a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 99) 16709a0bf528SMauro Carvalho Chehab msg->buf[0] = 99; 16719a0bf528SMauro Carvalho Chehab else 16729a0bf528SMauro Carvalho Chehab return -EINVAL; 16739a0bf528SMauro Carvalho Chehab return 0; 16749a0bf528SMauro Carvalho Chehab } 16759a0bf528SMauro Carvalho Chehab 16769a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap, 16779a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 16789a0bf528SMauro Carvalho Chehab { 16799a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 16809a0bf528SMauro Carvalho Chehab u8 n_overflow = 1; 16819a0bf528SMauro Carvalho Chehab u16 i = 1000; 16829a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 16839a0bf528SMauro Carvalho Chehab 16849a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 16859a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; 16869a0bf528SMauro Carvalho Chehab i--; 16879a0bf528SMauro Carvalho Chehab if (i == 0) 16888af16adfSMauro Carvalho Chehab dprintk("Tuner ITF: write busy (overflow)\n"); 16899a0bf528SMauro Carvalho Chehab } 16909a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); 16919a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); 16929a0bf528SMauro Carvalho Chehab 16939a0bf528SMauro Carvalho Chehab return num; 16949a0bf528SMauro Carvalho Chehab } 16959a0bf528SMauro Carvalho Chehab 16969a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap, 16979a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 16989a0bf528SMauro Carvalho Chehab { 16999a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 17009a0bf528SMauro Carvalho Chehab u8 n_overflow = 1, n_empty = 1; 17019a0bf528SMauro Carvalho Chehab u16 i = 1000; 17029a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 17039a0bf528SMauro Carvalho Chehab u16 read_word; 17049a0bf528SMauro Carvalho Chehab 17059a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 17069a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; 17079a0bf528SMauro Carvalho Chehab i--; 17089a0bf528SMauro Carvalho Chehab if (i == 0) 17098af16adfSMauro Carvalho Chehab dprintk("TunerITF: read busy (overflow)\n"); 17109a0bf528SMauro Carvalho Chehab } 17119a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f)); 17129a0bf528SMauro Carvalho Chehab 17139a0bf528SMauro Carvalho Chehab i = 1000; 17149a0bf528SMauro Carvalho Chehab while (n_empty == 1 && i) { 17159a0bf528SMauro Carvalho Chehab n_empty = dib8000_read_word(state, 1984)&0x1; 17169a0bf528SMauro Carvalho Chehab i--; 17179a0bf528SMauro Carvalho Chehab if (i == 0) 17188af16adfSMauro Carvalho Chehab dprintk("TunerITF: read busy (empty)\n"); 17199a0bf528SMauro Carvalho Chehab } 17209a0bf528SMauro Carvalho Chehab 17219a0bf528SMauro Carvalho Chehab read_word = dib8000_read_word(state, 1987); 17229a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (read_word >> 8) & 0xff; 17239a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (read_word) & 0xff; 17249a0bf528SMauro Carvalho Chehab 17259a0bf528SMauro Carvalho Chehab return num; 17269a0bf528SMauro Carvalho Chehab } 17279a0bf528SMauro Carvalho Chehab 17289a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, 17299a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 17309a0bf528SMauro Carvalho Chehab { 17319a0bf528SMauro Carvalho Chehab if (map_addr_to_serpar_number(&msg[0]) == 0) { 17329a0bf528SMauro Carvalho Chehab if (num == 1) /* write */ 17339a0bf528SMauro Carvalho Chehab return dib8096p_tuner_write_serpar(i2c_adap, msg, 1); 17349a0bf528SMauro Carvalho Chehab else /* read */ 17359a0bf528SMauro Carvalho Chehab return dib8096p_tuner_read_serpar(i2c_adap, msg, 2); 17369a0bf528SMauro Carvalho Chehab } 17379a0bf528SMauro Carvalho Chehab return num; 17389a0bf528SMauro Carvalho Chehab } 17399a0bf528SMauro Carvalho Chehab 17409a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap, 17419a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num, u16 apb_address) 17429a0bf528SMauro Carvalho Chehab { 17439a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 17449a0bf528SMauro Carvalho Chehab u16 word; 17459a0bf528SMauro Carvalho Chehab 17469a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 17479a0bf528SMauro Carvalho Chehab dib8000_write_word(state, apb_address, 17489a0bf528SMauro Carvalho Chehab ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); 17499a0bf528SMauro Carvalho Chehab } else { 17509a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, apb_address); 17519a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 17529a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 17539a0bf528SMauro Carvalho Chehab } 17549a0bf528SMauro Carvalho Chehab return num; 17559a0bf528SMauro Carvalho Chehab } 17569a0bf528SMauro Carvalho Chehab 17579a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap, 17589a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 17599a0bf528SMauro Carvalho Chehab { 17609a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 17619a0bf528SMauro Carvalho Chehab u16 apb_address = 0, word; 17629a0bf528SMauro Carvalho Chehab int i = 0; 17639a0bf528SMauro Carvalho Chehab 17649a0bf528SMauro Carvalho Chehab switch (msg[0].buf[0]) { 17659a0bf528SMauro Carvalho Chehab case 0x12: 17669a0bf528SMauro Carvalho Chehab apb_address = 1920; 17679a0bf528SMauro Carvalho Chehab break; 17689a0bf528SMauro Carvalho Chehab case 0x14: 17699a0bf528SMauro Carvalho Chehab apb_address = 1921; 17709a0bf528SMauro Carvalho Chehab break; 17719a0bf528SMauro Carvalho Chehab case 0x24: 17729a0bf528SMauro Carvalho Chehab apb_address = 1922; 17739a0bf528SMauro Carvalho Chehab break; 17749a0bf528SMauro Carvalho Chehab case 0x1a: 17759a0bf528SMauro Carvalho Chehab apb_address = 1923; 17769a0bf528SMauro Carvalho Chehab break; 17779a0bf528SMauro Carvalho Chehab case 0x22: 17789a0bf528SMauro Carvalho Chehab apb_address = 1924; 17799a0bf528SMauro Carvalho Chehab break; 17809a0bf528SMauro Carvalho Chehab case 0x33: 17819a0bf528SMauro Carvalho Chehab apb_address = 1926; 17829a0bf528SMauro Carvalho Chehab break; 17839a0bf528SMauro Carvalho Chehab case 0x34: 17849a0bf528SMauro Carvalho Chehab apb_address = 1927; 17859a0bf528SMauro Carvalho Chehab break; 17869a0bf528SMauro Carvalho Chehab case 0x35: 17879a0bf528SMauro Carvalho Chehab apb_address = 1928; 17889a0bf528SMauro Carvalho Chehab break; 17899a0bf528SMauro Carvalho Chehab case 0x36: 17909a0bf528SMauro Carvalho Chehab apb_address = 1929; 17919a0bf528SMauro Carvalho Chehab break; 17929a0bf528SMauro Carvalho Chehab case 0x37: 17939a0bf528SMauro Carvalho Chehab apb_address = 1930; 17949a0bf528SMauro Carvalho Chehab break; 17959a0bf528SMauro Carvalho Chehab case 0x38: 17969a0bf528SMauro Carvalho Chehab apb_address = 1931; 17979a0bf528SMauro Carvalho Chehab break; 17989a0bf528SMauro Carvalho Chehab case 0x39: 17999a0bf528SMauro Carvalho Chehab apb_address = 1932; 18009a0bf528SMauro Carvalho Chehab break; 18019a0bf528SMauro Carvalho Chehab case 0x2a: 18029a0bf528SMauro Carvalho Chehab apb_address = 1935; 18039a0bf528SMauro Carvalho Chehab break; 18049a0bf528SMauro Carvalho Chehab case 0x2b: 18059a0bf528SMauro Carvalho Chehab apb_address = 1936; 18069a0bf528SMauro Carvalho Chehab break; 18079a0bf528SMauro Carvalho Chehab case 0x2c: 18089a0bf528SMauro Carvalho Chehab apb_address = 1937; 18099a0bf528SMauro Carvalho Chehab break; 18109a0bf528SMauro Carvalho Chehab case 0x2d: 18119a0bf528SMauro Carvalho Chehab apb_address = 1938; 18129a0bf528SMauro Carvalho Chehab break; 18139a0bf528SMauro Carvalho Chehab case 0x2e: 18149a0bf528SMauro Carvalho Chehab apb_address = 1939; 18159a0bf528SMauro Carvalho Chehab break; 18169a0bf528SMauro Carvalho Chehab case 0x2f: 18179a0bf528SMauro Carvalho Chehab apb_address = 1940; 18189a0bf528SMauro Carvalho Chehab break; 18199a0bf528SMauro Carvalho Chehab case 0x30: 18209a0bf528SMauro Carvalho Chehab apb_address = 1941; 18219a0bf528SMauro Carvalho Chehab break; 18229a0bf528SMauro Carvalho Chehab case 0x31: 18239a0bf528SMauro Carvalho Chehab apb_address = 1942; 18249a0bf528SMauro Carvalho Chehab break; 18259a0bf528SMauro Carvalho Chehab case 0x32: 18269a0bf528SMauro Carvalho Chehab apb_address = 1943; 18279a0bf528SMauro Carvalho Chehab break; 18289a0bf528SMauro Carvalho Chehab case 0x3e: 18299a0bf528SMauro Carvalho Chehab apb_address = 1944; 18309a0bf528SMauro Carvalho Chehab break; 18319a0bf528SMauro Carvalho Chehab case 0x3f: 18329a0bf528SMauro Carvalho Chehab apb_address = 1945; 18339a0bf528SMauro Carvalho Chehab break; 18349a0bf528SMauro Carvalho Chehab case 0x40: 18359a0bf528SMauro Carvalho Chehab apb_address = 1948; 18369a0bf528SMauro Carvalho Chehab break; 18379a0bf528SMauro Carvalho Chehab case 0x25: 18389a0bf528SMauro Carvalho Chehab apb_address = 936; 18399a0bf528SMauro Carvalho Chehab break; 18409a0bf528SMauro Carvalho Chehab case 0x26: 18419a0bf528SMauro Carvalho Chehab apb_address = 937; 18429a0bf528SMauro Carvalho Chehab break; 18439a0bf528SMauro Carvalho Chehab case 0x27: 18449a0bf528SMauro Carvalho Chehab apb_address = 938; 18459a0bf528SMauro Carvalho Chehab break; 18469a0bf528SMauro Carvalho Chehab case 0x28: 18479a0bf528SMauro Carvalho Chehab apb_address = 939; 18489a0bf528SMauro Carvalho Chehab break; 18499a0bf528SMauro Carvalho Chehab case 0x1d: 18509a0bf528SMauro Carvalho Chehab /* get sad sel request */ 18519a0bf528SMauro Carvalho Chehab i = ((dib8000_read_word(state, 921) >> 12)&0x3); 18529a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, 924+i); 18539a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 18549a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 18559a0bf528SMauro Carvalho Chehab return num; 18569a0bf528SMauro Carvalho Chehab case 0x1f: 18579a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 18589a0bf528SMauro Carvalho Chehab word = (u16) ((msg[0].buf[1] << 8) | 18599a0bf528SMauro Carvalho Chehab msg[0].buf[2]); 18609a0bf528SMauro Carvalho Chehab /* in the VGAMODE Sel are located on bit 0/1 */ 18619a0bf528SMauro Carvalho Chehab word &= 0x3; 18629a0bf528SMauro Carvalho Chehab word = (dib8000_read_word(state, 921) & 18639a0bf528SMauro Carvalho Chehab ~(3<<12)) | (word<<12); 18649a0bf528SMauro Carvalho Chehab /* Set the proper input */ 18659a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, word); 18669a0bf528SMauro Carvalho Chehab return num; 18679a0bf528SMauro Carvalho Chehab } 18689a0bf528SMauro Carvalho Chehab } 18699a0bf528SMauro Carvalho Chehab 18709a0bf528SMauro Carvalho Chehab if (apb_address != 0) /* R/W acces via APB */ 18719a0bf528SMauro Carvalho Chehab return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address); 18729a0bf528SMauro Carvalho Chehab else /* R/W access via SERPAR */ 18739a0bf528SMauro Carvalho Chehab return dib8096p_tuner_rw_serpar(i2c_adap, msg, num); 18749a0bf528SMauro Carvalho Chehab 18759a0bf528SMauro Carvalho Chehab return 0; 18769a0bf528SMauro Carvalho Chehab } 18779a0bf528SMauro Carvalho Chehab 18789a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter) 18799a0bf528SMauro Carvalho Chehab { 18809a0bf528SMauro Carvalho Chehab return I2C_FUNC_I2C; 18819a0bf528SMauro Carvalho Chehab } 18829a0bf528SMauro Carvalho Chehab 18839a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = { 18849a0bf528SMauro Carvalho Chehab .master_xfer = dib8096p_tuner_xfer, 18859a0bf528SMauro Carvalho Chehab .functionality = dib8096p_i2c_func, 18869a0bf528SMauro Carvalho Chehab }; 18879a0bf528SMauro Carvalho Chehab 1888d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) 18899a0bf528SMauro Carvalho Chehab { 18909a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 18919a0bf528SMauro Carvalho Chehab return &st->dib8096p_tuner_adap; 18929a0bf528SMauro Carvalho Chehab } 18939a0bf528SMauro Carvalho Chehab 1894d44913c1SMauro Carvalho Chehab static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) 18959a0bf528SMauro Carvalho Chehab { 18969a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 18979a0bf528SMauro Carvalho Chehab u16 en_cur_state; 18989a0bf528SMauro Carvalho Chehab 18998af16adfSMauro Carvalho Chehab dprintk("sleep dib8096p: %d\n", onoff); 19009a0bf528SMauro Carvalho Chehab 19019a0bf528SMauro Carvalho Chehab en_cur_state = dib8000_read_word(state, 1922); 19029a0bf528SMauro Carvalho Chehab 19039a0bf528SMauro Carvalho Chehab /* LNAs and MIX are ON and therefore it is a valid configuration */ 19049a0bf528SMauro Carvalho Chehab if (en_cur_state > 0xff) 19059a0bf528SMauro Carvalho Chehab state->tuner_enable = en_cur_state ; 19069a0bf528SMauro Carvalho Chehab 19079a0bf528SMauro Carvalho Chehab if (onoff) 19089a0bf528SMauro Carvalho Chehab en_cur_state &= 0x00ff; 19099a0bf528SMauro Carvalho Chehab else { 19109a0bf528SMauro Carvalho Chehab if (state->tuner_enable != 0) 19119a0bf528SMauro Carvalho Chehab en_cur_state = state->tuner_enable; 19129a0bf528SMauro Carvalho Chehab } 19139a0bf528SMauro Carvalho Chehab 19149a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1922, en_cur_state); 19159a0bf528SMauro Carvalho Chehab 19169a0bf528SMauro Carvalho Chehab return 0; 19179a0bf528SMauro Carvalho Chehab } 19189a0bf528SMauro Carvalho Chehab 19199a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = 19209a0bf528SMauro Carvalho Chehab { 19219a0bf528SMauro Carvalho Chehab 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 19229a0bf528SMauro Carvalho Chehab }; 19239a0bf528SMauro Carvalho Chehab 1924d44913c1SMauro Carvalho Chehab static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) 19259a0bf528SMauro Carvalho Chehab { 19269a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 19279a0bf528SMauro Carvalho Chehab u32 ix = 0, tmp_val = 0, exp = 0, mant = 0; 19289a0bf528SMauro Carvalho Chehab s32 val; 19299a0bf528SMauro Carvalho Chehab 19309a0bf528SMauro Carvalho Chehab val = dib8000_read32(state, 384); 19319a0bf528SMauro Carvalho Chehab if (mode) { 19329a0bf528SMauro Carvalho Chehab tmp_val = val; 19339a0bf528SMauro Carvalho Chehab while (tmp_val >>= 1) 19349a0bf528SMauro Carvalho Chehab exp++; 19359a0bf528SMauro Carvalho Chehab mant = (val * 1000 / (1<<exp)); 19369a0bf528SMauro Carvalho Chehab ix = (u8)((mant-1000)/100); /* index of the LUT */ 19379a0bf528SMauro Carvalho Chehab val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); 19389a0bf528SMauro Carvalho Chehab val = (val*256)/1000; 19399a0bf528SMauro Carvalho Chehab } 19409a0bf528SMauro Carvalho Chehab return val; 19419a0bf528SMauro Carvalho Chehab } 19429a0bf528SMauro Carvalho Chehab 1943d44913c1SMauro Carvalho Chehab static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) 19449a0bf528SMauro Carvalho Chehab { 19459a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 19469a0bf528SMauro Carvalho Chehab int val = 0; 19479a0bf528SMauro Carvalho Chehab 19489a0bf528SMauro Carvalho Chehab switch (IQ) { 19499a0bf528SMauro Carvalho Chehab case 1: 19509a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 403); 19519a0bf528SMauro Carvalho Chehab break; 19529a0bf528SMauro Carvalho Chehab case 0: 19539a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 404); 19549a0bf528SMauro Carvalho Chehab break; 19559a0bf528SMauro Carvalho Chehab } 19569a0bf528SMauro Carvalho Chehab if (val & 0x200) 19579a0bf528SMauro Carvalho Chehab val -= 1024; 19589a0bf528SMauro Carvalho Chehab 19599a0bf528SMauro Carvalho Chehab return val; 19609a0bf528SMauro Carvalho Chehab } 19619a0bf528SMauro Carvalho Chehab 19629a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state) 19639a0bf528SMauro Carvalho Chehab { 19649a0bf528SMauro Carvalho Chehab u32 timf = state->timf = dib8000_read32(state, 435); 19659a0bf528SMauro Carvalho Chehab 19669a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) (timf >> 16)); 19679a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) (timf & 0xffff)); 19688af16adfSMauro Carvalho Chehab dprintk("Updated timing frequency: %d (default: %d)\n", state->timf, state->timf_default); 19699a0bf528SMauro Carvalho Chehab } 19709a0bf528SMauro Carvalho Chehab 1971d44913c1SMauro Carvalho Chehab static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) 19729a0bf528SMauro Carvalho Chehab { 19739a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 19749a0bf528SMauro Carvalho Chehab 19759a0bf528SMauro Carvalho Chehab switch (op) { 19769a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_SET: 19779a0bf528SMauro Carvalho Chehab state->timf = timf; 19789a0bf528SMauro Carvalho Chehab break; 19799a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_UPDATE: 19809a0bf528SMauro Carvalho Chehab dib8000_update_timf(state); 19819a0bf528SMauro Carvalho Chehab break; 19829a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_GET: 19839a0bf528SMauro Carvalho Chehab break; 19849a0bf528SMauro Carvalho Chehab } 19859a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(state->fe[0], 6000); 19869a0bf528SMauro Carvalho Chehab 19879a0bf528SMauro Carvalho Chehab return state->timf; 19889a0bf528SMauro Carvalho Chehab } 19899a0bf528SMauro Carvalho Chehab 19909a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = { 1991a768f90eSMauro Carvalho Chehab 7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574 19929a0bf528SMauro Carvalho Chehab }; 1993a768f90eSMauro Carvalho Chehab 19949a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; 19959a0bf528SMauro Carvalho Chehab 1996173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation) 19979a0bf528SMauro Carvalho Chehab { 1998173a64cbSPatrick Boettcher u8 cr, constellation, time_intlv; 1999c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 20009a0bf528SMauro Carvalho Chehab 2001c82056d0SMauro Carvalho Chehab switch (c->layer[layer_index].modulation) { 20029a0bf528SMauro Carvalho Chehab case DQPSK: 20039a0bf528SMauro Carvalho Chehab constellation = 0; 20049a0bf528SMauro Carvalho Chehab break; 20059a0bf528SMauro Carvalho Chehab case QPSK: 20069a0bf528SMauro Carvalho Chehab constellation = 1; 20079a0bf528SMauro Carvalho Chehab break; 20089a0bf528SMauro Carvalho Chehab case QAM_16: 20099a0bf528SMauro Carvalho Chehab constellation = 2; 20109a0bf528SMauro Carvalho Chehab break; 20119a0bf528SMauro Carvalho Chehab case QAM_64: 20129a0bf528SMauro Carvalho Chehab default: 20139a0bf528SMauro Carvalho Chehab constellation = 3; 20149a0bf528SMauro Carvalho Chehab break; 20159a0bf528SMauro Carvalho Chehab } 20169a0bf528SMauro Carvalho Chehab 2017c82056d0SMauro Carvalho Chehab switch (c->layer[layer_index].fec) { 20189a0bf528SMauro Carvalho Chehab case FEC_1_2: 2019173a64cbSPatrick Boettcher cr = 1; 20209a0bf528SMauro Carvalho Chehab break; 20219a0bf528SMauro Carvalho Chehab case FEC_2_3: 2022173a64cbSPatrick Boettcher cr = 2; 20239a0bf528SMauro Carvalho Chehab break; 20249a0bf528SMauro Carvalho Chehab case FEC_3_4: 2025173a64cbSPatrick Boettcher cr = 3; 20269a0bf528SMauro Carvalho Chehab break; 20279a0bf528SMauro Carvalho Chehab case FEC_5_6: 2028173a64cbSPatrick Boettcher cr = 5; 20299a0bf528SMauro Carvalho Chehab break; 20309a0bf528SMauro Carvalho Chehab case FEC_7_8: 20319a0bf528SMauro Carvalho Chehab default: 2032173a64cbSPatrick Boettcher cr = 7; 20339a0bf528SMauro Carvalho Chehab break; 20349a0bf528SMauro Carvalho Chehab } 20359a0bf528SMauro Carvalho Chehab 203634ba2e65SMauro Carvalho Chehab time_intlv = fls(c->layer[layer_index].interleaving); 203734ba2e65SMauro Carvalho Chehab if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1)) 2038173a64cbSPatrick Boettcher time_intlv = 0; 2039173a64cbSPatrick Boettcher 2040c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv); 2041c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].segment_count > 0) { 20429a0bf528SMauro Carvalho Chehab switch (max_constellation) { 20439a0bf528SMauro Carvalho Chehab case DQPSK: 20449a0bf528SMauro Carvalho Chehab case QPSK: 2045c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64) 2046c82056d0SMauro Carvalho Chehab max_constellation = c->layer[layer_index].modulation; 20479a0bf528SMauro Carvalho Chehab break; 20489a0bf528SMauro Carvalho Chehab case QAM_16: 2049c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].modulation == QAM_64) 2050c82056d0SMauro Carvalho Chehab max_constellation = c->layer[layer_index].modulation; 20519a0bf528SMauro Carvalho Chehab break; 20529a0bf528SMauro Carvalho Chehab } 20539a0bf528SMauro Carvalho Chehab } 2054173a64cbSPatrick Boettcher 2055173a64cbSPatrick Boettcher return max_constellation; 20569a0bf528SMauro Carvalho Chehab } 20579a0bf528SMauro Carvalho Chehab 2058173a64cbSPatrick Boettcher static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */ 2059173a64cbSPatrick Boettcher static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */ 2060173a64cbSPatrick Boettcher static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3, P_adp_noise_cnt -0.01, P_adp_regul_ext 0.1, P_adp_noise_ext -0.002 */ 2061173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation) 2062173a64cbSPatrick Boettcher { 2063173a64cbSPatrick Boettcher u16 i, ana_gain = 0; 2064173a64cbSPatrick Boettcher const u16 *adp; 20659a0bf528SMauro Carvalho Chehab 2066173a64cbSPatrick Boettcher /* channel estimation fine configuration */ 2067173a64cbSPatrick Boettcher switch (max_constellation) { 2068173a64cbSPatrick Boettcher case QAM_64: 2069173a64cbSPatrick Boettcher ana_gain = 0x7; 2070173a64cbSPatrick Boettcher adp = &adp_Q64[0]; 2071173a64cbSPatrick Boettcher break; 2072173a64cbSPatrick Boettcher case QAM_16: 2073173a64cbSPatrick Boettcher ana_gain = 0x7; 2074173a64cbSPatrick Boettcher adp = &adp_Q16[0]; 2075173a64cbSPatrick Boettcher break; 2076173a64cbSPatrick Boettcher default: 2077173a64cbSPatrick Boettcher ana_gain = 0; 2078173a64cbSPatrick Boettcher adp = &adp_Qdefault[0]; 2079173a64cbSPatrick Boettcher break; 20809a0bf528SMauro Carvalho Chehab } 20819a0bf528SMauro Carvalho Chehab 2082173a64cbSPatrick Boettcher for (i = 0; i < 4; i++) 2083173a64cbSPatrick Boettcher dib8000_write_word(state, 215 + i, adp[i]); 20849a0bf528SMauro Carvalho Chehab 2085173a64cbSPatrick Boettcher return ana_gain; 2086173a64cbSPatrick Boettcher } 20879a0bf528SMauro Carvalho Chehab 2088173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain) 2089173a64cbSPatrick Boettcher { 2090173a64cbSPatrick Boettcher u16 i; 20919a0bf528SMauro Carvalho Chehab 2092173a64cbSPatrick Boettcher dib8000_write_word(state, 116, ana_gain); 20939a0bf528SMauro Carvalho Chehab 2094173a64cbSPatrick Boettcher /* update ADC target depending on ana_gain */ 2095173a64cbSPatrick Boettcher if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */ 2096173a64cbSPatrick Boettcher for (i = 0; i < 10; i++) 2097173a64cbSPatrick Boettcher dib8000_write_word(state, 80 + i, adc_target_16dB[i]); 2098173a64cbSPatrick Boettcher } else { /* set -22dB ADC target for ana_gain=0 */ 2099173a64cbSPatrick Boettcher for (i = 0; i < 10; i++) 2100173a64cbSPatrick Boettcher dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355); 2101173a64cbSPatrick Boettcher } 2102173a64cbSPatrick Boettcher } 21039a0bf528SMauro Carvalho Chehab 2104173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe) 2105173a64cbSPatrick Boettcher { 2106173a64cbSPatrick Boettcher u16 mode = 0; 21079a0bf528SMauro Carvalho Chehab 2108173a64cbSPatrick Boettcher if (state->isdbt_cfg_loaded == 0) 2109173a64cbSPatrick Boettcher for (mode = 0; mode < 24; mode++) 2110173a64cbSPatrick Boettcher dib8000_write_word(state, 117 + mode, ana_fe[mode]); 2111173a64cbSPatrick Boettcher } 21129a0bf528SMauro Carvalho Chehab 2113173a64cbSPatrick Boettcher static const u16 lut_prbs_2k[14] = { 2114173a64cbSPatrick Boettcher 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213 2115173a64cbSPatrick Boettcher }; 2116173a64cbSPatrick Boettcher static const u16 lut_prbs_4k[14] = { 2117173a64cbSPatrick Boettcher 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E 2118173a64cbSPatrick Boettcher }; 2119173a64cbSPatrick Boettcher static const u16 lut_prbs_8k[14] = { 2120173a64cbSPatrick Boettcher 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684 2121173a64cbSPatrick Boettcher }; 2122173a64cbSPatrick Boettcher 2123173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel) 2124173a64cbSPatrick Boettcher { 2125173a64cbSPatrick Boettcher int sub_channel_prbs_group = 0; 2126173a64cbSPatrick Boettcher 2127173a64cbSPatrick Boettcher sub_channel_prbs_group = (subchannel / 3) + 1; 21288af16adfSMauro Carvalho Chehab dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]); 2129173a64cbSPatrick Boettcher 21309a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) { 21319a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 2132173a64cbSPatrick Boettcher return lut_prbs_2k[sub_channel_prbs_group]; 21339a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 2134173a64cbSPatrick Boettcher return lut_prbs_4k[sub_channel_prbs_group]; 21359a0bf528SMauro Carvalho Chehab default: 2136173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2137173a64cbSPatrick Boettcher return lut_prbs_8k[sub_channel_prbs_group]; 21389a0bf528SMauro Carvalho Chehab } 21399a0bf528SMauro Carvalho Chehab } 21409a0bf528SMauro Carvalho Chehab 2141173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state) 2142173a64cbSPatrick Boettcher { 2143173a64cbSPatrick Boettcher u16 i; 2144173a64cbSPatrick Boettcher u16 coff_pow = 0x2800; 21459a0bf528SMauro Carvalho Chehab 2146173a64cbSPatrick Boettcher state->seg_mask = 0x1fff; /* All 13 segments enabled */ 21479a0bf528SMauro Carvalho Chehab 2148173a64cbSPatrick Boettcher /* ---- COFF ---- Carloff, the most robust --- */ 2149173a64cbSPatrick Boettcher if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */ 21509a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 180, (16 << 6) | 9); 21519a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2); 21529a0bf528SMauro Carvalho Chehab coff_pow = 0x2800; 21539a0bf528SMauro Carvalho Chehab for (i = 0; i < 6; i++) 21549a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 181+i, coff_pow); 21559a0bf528SMauro Carvalho Chehab 2156173a64cbSPatrick Boettcher /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */ 2157173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */ 21589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1); 21599a0bf528SMauro Carvalho Chehab 2160173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */ 21619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 340, (8 << 6) | (6 << 0)); 2162173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */ 21639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); 21649a0bf528SMauro Carvalho Chehab 2165173a64cbSPatrick Boettcher dib8000_write_word(state, 228, 0); /* default value */ 2166173a64cbSPatrick Boettcher dib8000_write_word(state, 265, 31); /* default value */ 2167173a64cbSPatrick Boettcher dib8000_write_word(state, 205, 0x200f); /* init value */ 2168173a64cbSPatrick Boettcher } 2169173a64cbSPatrick Boettcher 2170173a64cbSPatrick Boettcher /* 2171173a64cbSPatrick Boettcher * make the cpil_coff_lock more robust but slower p_coff_winlen 21729a0bf528SMauro Carvalho Chehab * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) 21739a0bf528SMauro Carvalho Chehab */ 21749a0bf528SMauro Carvalho Chehab 2175173a64cbSPatrick Boettcher if (state->cfg.pll->ifreq == 0) 2176173a64cbSPatrick Boettcher dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ 21779a0bf528SMauro Carvalho Chehab 2178173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg); 2179173a64cbSPatrick Boettcher } 21809a0bf528SMauro Carvalho Chehab 2181173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs) 2182173a64cbSPatrick Boettcher { 2183173a64cbSPatrick Boettcher u16 reg_1; 21849a0bf528SMauro Carvalho Chehab 2185173a64cbSPatrick Boettcher reg_1 = dib8000_read_word(state, 1); 2186173a64cbSPatrick Boettcher dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */ 2187173a64cbSPatrick Boettcher } 21889a0bf528SMauro Carvalho Chehab 2189173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state) 2190173a64cbSPatrick Boettcher { 2191173a64cbSPatrick Boettcher u16 i; 2192173a64cbSPatrick Boettcher const s16 *ncoeff; 2193c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 21949a0bf528SMauro Carvalho Chehab 2195173a64cbSPatrick Boettcher dib8000_write_word(state, 352, state->seg_diff_mask); 2196173a64cbSPatrick Boettcher dib8000_write_word(state, 353, state->seg_mask); 21979a0bf528SMauro Carvalho Chehab 2198173a64cbSPatrick Boettcher /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */ 2199c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5); 2200173a64cbSPatrick Boettcher 2201c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2202173a64cbSPatrick Boettcher /* ---- SMALL ---- */ 2203c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2204173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2205c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */ 2206c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */ 2207173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_1seg_dqpsk; 2208173a64cbSPatrick Boettcher else /* QPSK or QAM */ 2209173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_1seg; 2210173a64cbSPatrick Boettcher } else { /* 3-segments */ 2211c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ 2212c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2213173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; 2214173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2215173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_0dqpsk; 2216173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */ 2217c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2218173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_1dqpsk; 2219173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2220173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg; 2221173a64cbSPatrick Boettcher } 2222173a64cbSPatrick Boettcher } 22239a0bf528SMauro Carvalho Chehab break; 22249a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 2225c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */ 2226c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */ 2227173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_1seg_dqpsk; 2228173a64cbSPatrick Boettcher else /* QPSK or QAM */ 2229173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_1seg; 2230173a64cbSPatrick Boettcher } else { /* 3-segments */ 2231c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ 2232c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2233173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; 2234173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2235173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_0dqpsk; 2236173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */ 2237c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2238173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_1dqpsk; 2239173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2240173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg; 2241173a64cbSPatrick Boettcher } 2242173a64cbSPatrick Boettcher } 22439a0bf528SMauro Carvalho Chehab break; 2244173a64cbSPatrick Boettcher case TRANSMISSION_MODE_AUTO: 2245173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 22469a0bf528SMauro Carvalho Chehab default: 2247c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */ 2248c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */ 2249173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_1seg_dqpsk; 2250173a64cbSPatrick Boettcher else /* QPSK or QAM */ 2251173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_1seg; 2252173a64cbSPatrick Boettcher } else { /* 3-segments */ 2253c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ 2254c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2255173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; 2256173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2257173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_0dqpsk; 2258173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */ 2259c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2260173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_1dqpsk; 2261173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2262173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg; 2263173a64cbSPatrick Boettcher } 2264173a64cbSPatrick Boettcher } 22659a0bf528SMauro Carvalho Chehab break; 22669a0bf528SMauro Carvalho Chehab } 2267173a64cbSPatrick Boettcher 2268173a64cbSPatrick Boettcher for (i = 0; i < 8; i++) 2269173a64cbSPatrick Boettcher dib8000_write_word(state, 343 + i, ncoeff[i]); 2270173a64cbSPatrick Boettcher } 2271173a64cbSPatrick Boettcher } 2272173a64cbSPatrick Boettcher 2273173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80}; 2274173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250}; 2275173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state) 2276173a64cbSPatrick Boettcher { 2277c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2278173a64cbSPatrick Boettcher const u16 *coff; 2279173a64cbSPatrick Boettcher u16 i; 2280173a64cbSPatrick Boettcher 2281c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) { 2282173a64cbSPatrick Boettcher dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */ 2283173a64cbSPatrick Boettcher dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */ 2284173a64cbSPatrick Boettcher } else { 2285173a64cbSPatrick Boettcher dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */ 2286173a64cbSPatrick Boettcher dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */ 2287173a64cbSPatrick Boettcher } 2288173a64cbSPatrick Boettcher 2289c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 1) /* 3-segments */ 2290173a64cbSPatrick Boettcher state->seg_mask = 0x00E0; 2291173a64cbSPatrick Boettcher else /* 1-segment */ 2292173a64cbSPatrick Boettcher state->seg_mask = 0x0040; 2293173a64cbSPatrick Boettcher 2294173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); 2295173a64cbSPatrick Boettcher 2296173a64cbSPatrick Boettcher /* ---- COFF ---- Carloff, the most robust --- */ 2297173a64cbSPatrick Boettcher /* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */ 2298c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3); 2299173a64cbSPatrick Boettcher 2300173a64cbSPatrick Boettcher dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */ 2301173a64cbSPatrick Boettcher dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */ 2302173a64cbSPatrick Boettcher 2303173a64cbSPatrick Boettcher /* Sound Broadcasting mode 1 seg */ 2304c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { 2305173a64cbSPatrick Boettcher /* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */ 2306173a64cbSPatrick Boettcher if (state->mode == 3) 2307173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14)); 23089a0bf528SMauro Carvalho Chehab else 2309173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14)); 2310173a64cbSPatrick Boettcher 2311173a64cbSPatrick Boettcher /* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */ 2312173a64cbSPatrick Boettcher dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4); 2313173a64cbSPatrick Boettcher coff = &coff_thres_1seg[0]; 2314173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2315173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); 2316173a64cbSPatrick Boettcher /* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */ 2317173a64cbSPatrick Boettcher dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4); 2318173a64cbSPatrick Boettcher coff = &coff_thres_3seg[0]; 2319173a64cbSPatrick Boettcher } 2320173a64cbSPatrick Boettcher 2321173a64cbSPatrick Boettcher dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */ 2322173a64cbSPatrick Boettcher dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */ 2323173a64cbSPatrick Boettcher 2324c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K) 2325173a64cbSPatrick Boettcher dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */ 2326173a64cbSPatrick Boettcher 2327173a64cbSPatrick Boettcher /* Write COFF thres */ 2328173a64cbSPatrick Boettcher for (i = 0 ; i < 3; i++) { 2329173a64cbSPatrick Boettcher dib8000_write_word(state, 181+i, coff[i]); 2330173a64cbSPatrick Boettcher dib8000_write_word(state, 184+i, coff[i]); 2331173a64cbSPatrick Boettcher } 2332173a64cbSPatrick Boettcher 2333173a64cbSPatrick Boettcher /* 2334173a64cbSPatrick Boettcher * make the cpil_coff_lock more robust but slower p_coff_winlen 2335173a64cbSPatrick Boettcher * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) 2336173a64cbSPatrick Boettcher */ 2337173a64cbSPatrick Boettcher 2338173a64cbSPatrick Boettcher dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */ 2339173a64cbSPatrick Boettcher 2340c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) 2341173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */ 2342173a64cbSPatrick Boettcher else 2343173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ 2344173a64cbSPatrick Boettcher } 2345173a64cbSPatrick Boettcher 2346173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching) 2347173a64cbSPatrick Boettcher { 2348173a64cbSPatrick Boettcher u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0; 2349173a64cbSPatrick Boettcher u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ; 2350173a64cbSPatrick Boettcher u16 max_constellation = DQPSK; 2351173a64cbSPatrick Boettcher int init_prbs; 2352c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2353173a64cbSPatrick Boettcher 2354dde8e115SMauro Carvalho Chehab if (autosearching) 2355dde8e115SMauro Carvalho Chehab c->isdbt_partial_reception = 1; 2356dde8e115SMauro Carvalho Chehab 2357173a64cbSPatrick Boettcher /* P_mode */ 2358173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (seq << 4)); 2359173a64cbSPatrick Boettcher 2360173a64cbSPatrick Boettcher /* init mode */ 2361173a64cbSPatrick Boettcher state->mode = fft_to_mode(state); 2362173a64cbSPatrick Boettcher 2363173a64cbSPatrick Boettcher /* set guard */ 2364173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 1); 2365c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3)); 2366173a64cbSPatrick Boettcher 2367c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((c->isdbt_partial_reception & 1) << 5) | ((c->isdbt_sb_mode & 1) << 4)); 2368173a64cbSPatrick Boettcher 2369173a64cbSPatrick Boettcher /* signal optimization parameter */ 2370c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) { 2371c82056d0SMauro Carvalho Chehab state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0]; 2372173a64cbSPatrick Boettcher for (i = 1; i < 3; i++) 2373c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; 2374173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++) 2375173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i+1]; 2376173a64cbSPatrick Boettcher } else { 2377173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) 2378c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; 2379173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++) 2380173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i]; 2381173a64cbSPatrick Boettcher } 2382173a64cbSPatrick Boettcher 2383173a64cbSPatrick Boettcher if (state->seg_diff_mask) 2384173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); 2385173a64cbSPatrick Boettcher else 2386173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */ 2387173a64cbSPatrick Boettcher 2388173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) 2389173a64cbSPatrick Boettcher max_constellation = dib8000_set_layer(state, i, max_constellation); 2390173a64cbSPatrick Boettcher if (autosearching == 0) { 2391c82056d0SMauro Carvalho Chehab state->layer_b_nb_seg = c->layer[1].segment_count; 2392c82056d0SMauro Carvalho Chehab state->layer_c_nb_seg = c->layer[2].segment_count; 2393173a64cbSPatrick Boettcher } 2394173a64cbSPatrick Boettcher 2395173a64cbSPatrick Boettcher /* WRITE: Mode & Diff mask */ 2396173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask); 2397173a64cbSPatrick Boettcher 2398173a64cbSPatrick Boettcher state->differential_constellation = (state->seg_diff_mask != 0); 23999a0bf528SMauro Carvalho Chehab 24009a0bf528SMauro Carvalho Chehab /* channel estimation fine configuration */ 2401173a64cbSPatrick Boettcher ana_gain = dib8000_adp_fine_tune(state, max_constellation); 24029a0bf528SMauro Carvalho Chehab 2403173a64cbSPatrick Boettcher /* update ana_gain depending on max constellation */ 2404173a64cbSPatrick Boettcher dib8000_update_ana_gain(state, ana_gain); 24059a0bf528SMauro Carvalho Chehab 2406173a64cbSPatrick Boettcher /* ---- ANA_FE ---- */ 2407c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) /* 3-segments */ 2408173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg); 2409173a64cbSPatrick Boettcher else 2410173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */ 2411173a64cbSPatrick Boettcher 2412173a64cbSPatrick Boettcher /* TSB or ISDBT ? apply it now */ 2413c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2414173a64cbSPatrick Boettcher dib8000_set_sb_channel(state); 2415746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_subchannel < 14) 2416c82056d0SMauro Carvalho Chehab init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel); 2417173a64cbSPatrick Boettcher else 2418173a64cbSPatrick Boettcher init_prbs = 0; 2419173a64cbSPatrick Boettcher } else { 2420173a64cbSPatrick Boettcher dib8000_set_13seg_channel(state); 2421173a64cbSPatrick Boettcher init_prbs = 0xfff; 2422173a64cbSPatrick Boettcher } 24239a0bf528SMauro Carvalho Chehab 2424173a64cbSPatrick Boettcher /* SMALL */ 2425173a64cbSPatrick Boettcher dib8000_small_fine_tune(state); 24269a0bf528SMauro Carvalho Chehab 2427173a64cbSPatrick Boettcher dib8000_set_subchannel_prbs(state, init_prbs); 2428173a64cbSPatrick Boettcher 2429173a64cbSPatrick Boettcher /* ---- CHAN_BLK ---- */ 24309a0bf528SMauro Carvalho Chehab for (i = 0; i < 13; i++) { 2431173a64cbSPatrick Boettcher if ((((~state->seg_diff_mask) >> i) & 1) == 1) { 2432173a64cbSPatrick Boettcher p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0)); 2433173a64cbSPatrick Boettcher p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0)); 24349a0bf528SMauro Carvalho Chehab } 24359a0bf528SMauro Carvalho Chehab } 2436173a64cbSPatrick Boettcher dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */ 2437173a64cbSPatrick Boettcher dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */ 2438173a64cbSPatrick Boettcher /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */ 24399a0bf528SMauro Carvalho Chehab 2440173a64cbSPatrick Boettcher dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */ 2441173a64cbSPatrick Boettcher dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */ 2442173a64cbSPatrick Boettcher dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */ 2443173a64cbSPatrick Boettcher 2444173a64cbSPatrick Boettcher if (!autosearching) 2445173a64cbSPatrick Boettcher dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ 2446173a64cbSPatrick Boettcher else 2447173a64cbSPatrick Boettcher dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */ 2448173a64cbSPatrick Boettcher 2449173a64cbSPatrick Boettcher dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */ 2450173a64cbSPatrick Boettcher dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */ 2451173a64cbSPatrick Boettcher 2452173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ 2453173a64cbSPatrick Boettcher 2454173a64cbSPatrick Boettcher /* ---- TMCC ---- */ 24559a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) 2456c82056d0SMauro Carvalho Chehab tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ; 2457173a64cbSPatrick Boettcher 2458173a64cbSPatrick Boettcher /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */ 2459173a64cbSPatrick Boettcher /* Threshold is set at 1/4 of max power. */ 24609a0bf528SMauro Carvalho Chehab tmcc_pow *= (1 << (9-2)); 2461173a64cbSPatrick Boettcher dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */ 2462173a64cbSPatrick Boettcher dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */ 2463173a64cbSPatrick Boettcher dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */ 2464173a64cbSPatrick Boettcher /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */ 24659a0bf528SMauro Carvalho Chehab 2466173a64cbSPatrick Boettcher /* ---- PHA3 ---- */ 24679a0bf528SMauro Carvalho Chehab if (state->isdbt_cfg_loaded == 0) 24689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */ 24699a0bf528SMauro Carvalho Chehab 24709a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0; 2471173a64cbSPatrick Boettcher } 24729a0bf528SMauro Carvalho Chehab 24736f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, 24746f7ee06fSMauro Carvalho Chehab u32 wait0_ms, u32 wait1_ms, u32 wait2_ms) 2475173a64cbSPatrick Boettcher { 247613122f98SMauro Carvalho Chehab u32 value = 0; /* P_search_end0 wait time */ 2477173a64cbSPatrick Boettcher u16 reg = 11; /* P_search_end0 start addr */ 2478173a64cbSPatrick Boettcher 2479173a64cbSPatrick Boettcher for (reg = 11; reg < 16; reg += 2) { 2480173a64cbSPatrick Boettcher if (reg == 11) { 2481173a64cbSPatrick Boettcher if (state->revision == 0x8090) 248213122f98SMauro Carvalho Chehab value = internal * wait1_ms; 2483173a64cbSPatrick Boettcher else 248413122f98SMauro Carvalho Chehab value = internal * wait0_ms; 2485173a64cbSPatrick Boettcher } else if (reg == 13) 248613122f98SMauro Carvalho Chehab value = internal * wait1_ms; 2487173a64cbSPatrick Boettcher else if (reg == 15) 248813122f98SMauro Carvalho Chehab value = internal * wait2_ms; 2489173a64cbSPatrick Boettcher dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff)); 2490173a64cbSPatrick Boettcher dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff)); 2491173a64cbSPatrick Boettcher } 2492173a64cbSPatrick Boettcher return value; 24939a0bf528SMauro Carvalho Chehab } 24949a0bf528SMauro Carvalho Chehab 24959a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe) 24969a0bf528SMauro Carvalho Chehab { 24979a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 2498c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2499173a64cbSPatrick Boettcher u8 slist = 0; 2500173a64cbSPatrick Boettcher u32 value, internal = state->cfg.pll->internal; 25019a0bf528SMauro Carvalho Chehab 2502173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2503173a64cbSPatrick Boettcher internal = dib8000_read32(state, 23) / 1000; 25049a0bf528SMauro Carvalho Chehab 2505d67350f8SOlivier Grenie if ((state->revision >= 0x8002) && 2506d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) { 2507173a64cbSPatrick Boettcher dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ 2508173a64cbSPatrick Boettcher dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ 2509173a64cbSPatrick Boettcher 2510173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */ 2511173a64cbSPatrick Boettcher dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */ 2512173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */ 2513173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */ 2514173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */ 2515173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */ 2516173a64cbSPatrick Boettcher 2517173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2518173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2519173a64cbSPatrick Boettcher else 2520173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2521173a64cbSPatrick Boettcher 2522173a64cbSPatrick Boettcher dib8000_write_word(state, 17, 0); 2523173a64cbSPatrick Boettcher dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */ 2524173a64cbSPatrick Boettcher dib8000_write_word(state, 19, 0); 2525173a64cbSPatrick Boettcher dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */ 2526173a64cbSPatrick Boettcher dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */ 2527173a64cbSPatrick Boettcher dib8000_write_word(state, 22, value & 0xffff); 2528173a64cbSPatrick Boettcher 2529173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2530173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */ 2531173a64cbSPatrick Boettcher else 2532173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */ 2533173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */ 2534173a64cbSPatrick Boettcher 2535173a64cbSPatrick Boettcher /* P_search_param_select = (1 | 1<<4 | 1 << 8) */ 2536173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0); 2537173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0x111); 2538173a64cbSPatrick Boettcher 2539173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ 2540173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ 2541173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ 2542d67350f8SOlivier Grenie } else if ((state->revision >= 0x8002) && 2543d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_GUARD)) { 2544c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 2545c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 2546c82056d0SMauro Carvalho Chehab c->inversion = 0; 2547c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64; 2548c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3; 2549c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0; 2550c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 25519a0bf528SMauro Carvalho Chehab 2552173a64cbSPatrick Boettcher slist = 16; 2553c82056d0SMauro Carvalho Chehab c->transmission_mode = state->found_nfft; 2554173a64cbSPatrick Boettcher 2555173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1); 2556173a64cbSPatrick Boettcher 2557173a64cbSPatrick Boettcher /* set lock_mask values */ 2558173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0x4); 2559173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2560173a64cbSPatrick Boettcher dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */ 2561173a64cbSPatrick Boettcher else 2562173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0x8); 2563173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0x1000); 2564173a64cbSPatrick Boettcher 2565173a64cbSPatrick Boettcher /* set lock_mask wait time values */ 2566173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2567173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2568173a64cbSPatrick Boettcher else 2569173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2570173a64cbSPatrick Boettcher 2571173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */ 2572173a64cbSPatrick Boettcher 2573173a64cbSPatrick Boettcher /* P_search_param_select = 0xf; look for the 4 different guard intervals */ 2574173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0); 2575173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0xf); 2576173a64cbSPatrick Boettcher 2577173a64cbSPatrick Boettcher value = dib8000_read_word(state, 0); 2578173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)((1 << 15) | value)); 2579173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ 2580173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)value); 2581173a64cbSPatrick Boettcher } else { 2582c82056d0SMauro Carvalho Chehab c->inversion = 0; 2583c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64; 2584c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3; 2585c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0; 2586c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 2587c82056d0SMauro Carvalho Chehab if (!c->isdbt_sb_mode) 2588c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 2589173a64cbSPatrick Boettcher 2590173a64cbSPatrick Boettcher /* choose the right list, in sb, always do everything */ 2591c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 25929a0bf528SMauro Carvalho Chehab slist = 7; 25939a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); 25949a0bf528SMauro Carvalho Chehab } else { 2595c82056d0SMauro Carvalho Chehab if (c->guard_interval == GUARD_INTERVAL_AUTO) { 2596c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 2597c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 2598c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 25999a0bf528SMauro Carvalho Chehab slist = 7; 2600173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */ 2601173a64cbSPatrick Boettcher } else { 2602c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 26039a0bf528SMauro Carvalho Chehab slist = 3; 2604173a64cbSPatrick Boettcher } 26059a0bf528SMauro Carvalho Chehab } else { 2606c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 2607c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 26089a0bf528SMauro Carvalho Chehab slist = 2; 2609173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */ 26109a0bf528SMauro Carvalho Chehab } else 26119a0bf528SMauro Carvalho Chehab slist = 0; 26129a0bf528SMauro Carvalho Chehab } 2613173a64cbSPatrick Boettcher } 26148af16adfSMauro Carvalho Chehab dprintk("Using list for autosearch : %d\n", slist); 26159a0bf528SMauro Carvalho Chehab 2616173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1); 26179a0bf528SMauro Carvalho Chehab 2618173a64cbSPatrick Boettcher /* set lock_mask values */ 26199a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 6, 0x4); 2620173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2621173a64cbSPatrick Boettcher dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10)); 2622173a64cbSPatrick Boettcher else 26239a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 7, 0x8); 26249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 8, 0x1000); 26259a0bf528SMauro Carvalho Chehab 2626173a64cbSPatrick Boettcher /* set lock_mask wait time values */ 2627173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2628173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2629173a64cbSPatrick Boettcher else 2630173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 26319a0bf528SMauro Carvalho Chehab 26329a0bf528SMauro Carvalho Chehab value = dib8000_read_word(state, 0); 26339a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)((1 << 15) | value)); 2634173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ 26359a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)value); 26369a0bf528SMauro Carvalho Chehab } 26379a0bf528SMauro Carvalho Chehab return 0; 26389a0bf528SMauro Carvalho Chehab } 26399a0bf528SMauro Carvalho Chehab 26409a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe) 26419a0bf528SMauro Carvalho Chehab { 26429a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 26439a0bf528SMauro Carvalho Chehab u16 irq_pending = dib8000_read_word(state, 1284); 26449a0bf528SMauro Carvalho Chehab 2645d67350f8SOlivier Grenie if ((state->revision >= 0x8002) && 2646d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) { 2647173a64cbSPatrick Boettcher if (irq_pending & 0x1) { 26488af16adfSMauro Carvalho Chehab dprintk("dib8000_autosearch_irq: max correlation result available\n"); 2649173a64cbSPatrick Boettcher return 3; 2650173a64cbSPatrick Boettcher } 2651173a64cbSPatrick Boettcher } else { 2652173a64cbSPatrick Boettcher if (irq_pending & 0x1) { /* failed */ 26538af16adfSMauro Carvalho Chehab dprintk("dib8000_autosearch_irq failed\n"); 26549a0bf528SMauro Carvalho Chehab return 1; 26559a0bf528SMauro Carvalho Chehab } 26569a0bf528SMauro Carvalho Chehab 2657173a64cbSPatrick Boettcher if (irq_pending & 0x2) { /* succeeded */ 26588af16adfSMauro Carvalho Chehab dprintk("dib8000_autosearch_irq succeeded\n"); 26599a0bf528SMauro Carvalho Chehab return 2; 26609a0bf528SMauro Carvalho Chehab } 2661173a64cbSPatrick Boettcher } 26629a0bf528SMauro Carvalho Chehab 26639a0bf528SMauro Carvalho Chehab return 0; // still pending 26649a0bf528SMauro Carvalho Chehab } 26659a0bf528SMauro Carvalho Chehab 2666173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff) 2667173a64cbSPatrick Boettcher { 2668173a64cbSPatrick Boettcher u16 tmp; 2669173a64cbSPatrick Boettcher 2670173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 771); 2671173a64cbSPatrick Boettcher if (onoff) /* start P_restart_chd : channel_decoder */ 2672173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp & 0xfffd); 2673173a64cbSPatrick Boettcher else /* stop P_restart_chd : channel_decoder */ 2674173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp | (1<<1)); 2675173a64cbSPatrick Boettcher } 2676173a64cbSPatrick Boettcher 2677173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) 2678173a64cbSPatrick Boettcher { 2679173a64cbSPatrick Boettcher s16 unit_khz_dds_val; 2680173a64cbSPatrick Boettcher u32 abs_offset_khz = ABS(offset_khz); 2681173a64cbSPatrick Boettcher u32 dds = state->cfg.pll->ifreq & 0x1ffffff; 2682173a64cbSPatrick Boettcher u8 invert = !!(state->cfg.pll->ifreq & (1 << 25)); 2683173a64cbSPatrick Boettcher u8 ratio; 2684173a64cbSPatrick Boettcher 2685173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 2686173a64cbSPatrick Boettcher ratio = 4; 2687173a64cbSPatrick Boettcher unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000); 2688173a64cbSPatrick Boettcher if (offset_khz < 0) 2689173a64cbSPatrick Boettcher dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val); 2690173a64cbSPatrick Boettcher else 2691173a64cbSPatrick Boettcher dds = (abs_offset_khz * unit_khz_dds_val); 2692173a64cbSPatrick Boettcher 2693173a64cbSPatrick Boettcher if (invert) 2694173a64cbSPatrick Boettcher dds = (1<<26) - dds; 2695173a64cbSPatrick Boettcher } else { 2696173a64cbSPatrick Boettcher ratio = 2; 2697173a64cbSPatrick Boettcher unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal); 2698173a64cbSPatrick Boettcher 2699173a64cbSPatrick Boettcher if (offset_khz < 0) 2700173a64cbSPatrick Boettcher unit_khz_dds_val *= -1; 2701173a64cbSPatrick Boettcher 2702173a64cbSPatrick Boettcher /* IF tuner */ 2703173a64cbSPatrick Boettcher if (invert) 2704173a64cbSPatrick Boettcher dds -= abs_offset_khz * unit_khz_dds_val; 2705173a64cbSPatrick Boettcher else 2706173a64cbSPatrick Boettcher dds += abs_offset_khz * unit_khz_dds_val; 2707173a64cbSPatrick Boettcher } 2708173a64cbSPatrick Boettcher 27098af16adfSMauro Carvalho Chehab dprintk("setting a DDS frequency offset of %c%dkHz\n", invert ? '-' : ' ', dds / unit_khz_dds_val); 2710173a64cbSPatrick Boettcher 2711173a64cbSPatrick Boettcher if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) { 2712173a64cbSPatrick Boettcher /* Max dds offset is the half of the demod freq */ 2713173a64cbSPatrick Boettcher dib8000_write_word(state, 26, invert); 2714173a64cbSPatrick Boettcher dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff); 2715173a64cbSPatrick Boettcher dib8000_write_word(state, 28, (u16)(dds & 0xffff)); 2716173a64cbSPatrick Boettcher } 2717173a64cbSPatrick Boettcher } 2718173a64cbSPatrick Boettcher 2719173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state) 2720173a64cbSPatrick Boettcher { 2721c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2722173a64cbSPatrick Boettcher int i; 2723173a64cbSPatrick Boettcher u32 current_rf; 2724173a64cbSPatrick Boettcher int total_dds_offset_khz; 2725173a64cbSPatrick Boettcher 2726173a64cbSPatrick Boettcher if (state->fe[0]->ops.tuner_ops.get_frequency) 2727173a64cbSPatrick Boettcher state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], ¤t_rf); 2728173a64cbSPatrick Boettcher else 2729c82056d0SMauro Carvalho Chehab current_rf = c->frequency; 2730173a64cbSPatrick Boettcher current_rf /= 1000; 2731c82056d0SMauro Carvalho Chehab total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000; 2732173a64cbSPatrick Boettcher 2733c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2734c82056d0SMauro Carvalho Chehab state->subchannel = c->isdbt_sb_subchannel; 2735173a64cbSPatrick Boettcher 2736173a64cbSPatrick Boettcher i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */ 2737c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 26, c->inversion ^ i); 2738173a64cbSPatrick Boettcher 2739173a64cbSPatrick Boettcher if (state->cfg.pll->ifreq == 0) { /* low if tuner */ 2740c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0) 2741173a64cbSPatrick Boettcher dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); 2742173a64cbSPatrick Boettcher } else { 2743c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0) 2744173a64cbSPatrick Boettcher total_dds_offset_khz *= -1; 2745173a64cbSPatrick Boettcher } 2746173a64cbSPatrick Boettcher } 2747173a64cbSPatrick Boettcher 27488af16adfSMauro Carvalho Chehab dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d\n", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz); 2749173a64cbSPatrick Boettcher 2750173a64cbSPatrick Boettcher /* apply dds offset now */ 2751173a64cbSPatrick Boettcher dib8000_set_dds(state, total_dds_offset_khz); 2752173a64cbSPatrick Boettcher } 2753173a64cbSPatrick Boettcher 2754173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 }; 27556f7ee06fSMauro Carvalho Chehab 27566f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state) 2757173a64cbSPatrick Boettcher { 2758c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2759173a64cbSPatrick Boettcher u16 i; 2760173a64cbSPatrick Boettcher 2761c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2762173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2763173a64cbSPatrick Boettcher i = 0; 2764173a64cbSPatrick Boettcher break; 2765173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K: 2766173a64cbSPatrick Boettcher i = 2; 2767173a64cbSPatrick Boettcher break; 2768173a64cbSPatrick Boettcher default: 2769173a64cbSPatrick Boettcher case TRANSMISSION_MODE_AUTO: 2770173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2771173a64cbSPatrick Boettcher i = 1; 2772173a64cbSPatrick Boettcher break; 2773173a64cbSPatrick Boettcher } 2774173a64cbSPatrick Boettcher 2775c82056d0SMauro Carvalho Chehab return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1; 2776173a64cbSPatrick Boettcher } 2777173a64cbSPatrick Boettcher 2778173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step) 2779173a64cbSPatrick Boettcher { 2780c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2781173a64cbSPatrick Boettcher u16 reg_32 = 0, reg_37 = 0; 2782173a64cbSPatrick Boettcher 2783173a64cbSPatrick Boettcher switch (loop_step) { 2784173a64cbSPatrick Boettcher case LOOP_TUNE_1: 2785c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2786c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { 2787173a64cbSPatrick Boettcher reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */ 2788173a64cbSPatrick Boettcher reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */ 2789173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2790173a64cbSPatrick Boettcher reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */ 2791173a64cbSPatrick Boettcher reg_37 = (3 << 5) | (0 << 4) | (9 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (9-P_mode) */ 2792173a64cbSPatrick Boettcher } 2793173a64cbSPatrick Boettcher } else { /* 13-seg start conf offset loop parameters */ 2794173a64cbSPatrick Boettcher reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ 2795173a64cbSPatrick Boettcher reg_37 = (3 << 5) | (0 << 4) | (8 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */ 2796173a64cbSPatrick Boettcher } 2797173a64cbSPatrick Boettcher break; 2798173a64cbSPatrick Boettcher case LOOP_TUNE_2: 2799c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2800c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */ 2801173a64cbSPatrick Boettcher reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/ 2802173a64cbSPatrick Boettcher reg_37 = (12-state->mode) | ((5 + state->mode) << 5); 2803173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2804173a64cbSPatrick Boettcher reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */ 2805173a64cbSPatrick Boettcher reg_37 = (11-state->mode) | ((5 + state->mode) << 5); 2806173a64cbSPatrick Boettcher } 2807173a64cbSPatrick Boettcher } else { /* 13 seg */ 2808173a64cbSPatrick Boettcher reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */ 2809173a64cbSPatrick Boettcher reg_37 = ((5+state->mode) << 5) | (10 - state->mode); 2810173a64cbSPatrick Boettcher } 2811173a64cbSPatrick Boettcher break; 2812173a64cbSPatrick Boettcher } 2813173a64cbSPatrick Boettcher dib8000_write_word(state, 32, reg_32); 2814173a64cbSPatrick Boettcher dib8000_write_word(state, 37, reg_37); 2815173a64cbSPatrick Boettcher } 2816173a64cbSPatrick Boettcher 2817173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state) 2818173a64cbSPatrick Boettcher { 2819173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x4000); 2820173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x0000); 2821173a64cbSPatrick Boettcher return; 2822173a64cbSPatrick Boettcher } 2823173a64cbSPatrick Boettcher 2824173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state) 2825173a64cbSPatrick Boettcher { 2826c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2827173a64cbSPatrick Boettcher u16 sync_wait = 64; 2828173a64cbSPatrick Boettcher 2829173a64cbSPatrick Boettcher /* P_dvsy_sync_wait - reuse mode */ 2830c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2831173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2832173a64cbSPatrick Boettcher sync_wait = 256; 2833173a64cbSPatrick Boettcher break; 2834173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K: 2835173a64cbSPatrick Boettcher sync_wait = 128; 2836173a64cbSPatrick Boettcher break; 2837173a64cbSPatrick Boettcher default: 2838173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2839173a64cbSPatrick Boettcher sync_wait = 64; 2840173a64cbSPatrick Boettcher break; 2841173a64cbSPatrick Boettcher } 2842173a64cbSPatrick Boettcher 2843173a64cbSPatrick Boettcher if (state->cfg.diversity_delay == 0) 2844c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */ 2845173a64cbSPatrick Boettcher else 2846c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */ 2847173a64cbSPatrick Boettcher 2848173a64cbSPatrick Boettcher dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4)); 2849173a64cbSPatrick Boettcher } 2850173a64cbSPatrick Boettcher 2851d6c62b76SMauro Carvalho Chehab static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode) 2852173a64cbSPatrick Boettcher { 2853173a64cbSPatrick Boettcher if (mode == SYMBOL_DEPENDENT_ON) 2854d6c62b76SMauro Carvalho Chehab delay *= state->symbol_duration; 2855d6c62b76SMauro Carvalho Chehab 2856d6c62b76SMauro Carvalho Chehab return jiffies + usecs_to_jiffies(delay * 100); 2857173a64cbSPatrick Boettcher } 2858173a64cbSPatrick Boettcher 2859173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe) 2860173a64cbSPatrick Boettcher { 2861173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2862173a64cbSPatrick Boettcher return state->status; 2863173a64cbSPatrick Boettcher } 2864173a64cbSPatrick Boettcher 2865d44913c1SMauro Carvalho Chehab static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) 2866173a64cbSPatrick Boettcher { 2867173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2868173a64cbSPatrick Boettcher return state->tune_state; 2869173a64cbSPatrick Boettcher } 2870173a64cbSPatrick Boettcher 2871d44913c1SMauro Carvalho Chehab static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) 2872173a64cbSPatrick Boettcher { 2873173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2874173a64cbSPatrick Boettcher 2875173a64cbSPatrick Boettcher state->tune_state = tune_state; 2876173a64cbSPatrick Boettcher return 0; 2877173a64cbSPatrick Boettcher } 2878173a64cbSPatrick Boettcher 2879173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe) 2880173a64cbSPatrick Boettcher { 2881173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2882173a64cbSPatrick Boettcher 2883173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING; 2884173a64cbSPatrick Boettcher state->tune_state = CT_DEMOD_START; 2885173a64cbSPatrick Boettcher return 0; 2886173a64cbSPatrick Boettcher } 2887173a64cbSPatrick Boettcher 2888173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe) 2889173a64cbSPatrick Boettcher { 2890173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2891173a64cbSPatrick Boettcher 2892173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2893173a64cbSPatrick Boettcher return dib8000_read_word(state, 570); 2894173a64cbSPatrick Boettcher return dib8000_read_word(state, 568); 2895173a64cbSPatrick Boettcher } 2896173a64cbSPatrick Boettcher 2897173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state) 2898173a64cbSPatrick Boettcher { 2899173a64cbSPatrick Boettcher u16 reg = 0; 29008af16adfSMauro Carvalho Chehab dprintk("init sdram\n"); 2901173a64cbSPatrick Boettcher 2902173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 274) & 0xfff0; 2903173a64cbSPatrick Boettcher dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */ 2904173a64cbSPatrick Boettcher 2905173a64cbSPatrick Boettcher dib8000_write_word(state, 1803, (7 << 2)); 2906173a64cbSPatrick Boettcher 2907173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 1280); 2908173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */ 2909173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */ 2910173a64cbSPatrick Boettcher 2911173a64cbSPatrick Boettcher return 0; 2912173a64cbSPatrick Boettcher } 2913173a64cbSPatrick Boettcher 2914ad976187SMauro Carvalho Chehab /** 2915ad976187SMauro Carvalho Chehab * is_manual_mode - Check if TMCC should be used for parameters settings 2916ad976187SMauro Carvalho Chehab * @c: struct dvb_frontend_properties 2917ad976187SMauro Carvalho Chehab * 2918ad976187SMauro Carvalho Chehab * By default, TMCC table should be used for parameter settings on most 2919ad976187SMauro Carvalho Chehab * usercases. However, sometimes it is desirable to lock the demod to 2920ad976187SMauro Carvalho Chehab * use the manual parameters. 2921ad976187SMauro Carvalho Chehab * 2922ad976187SMauro Carvalho Chehab * On manual mode, the current dib8000_tune state machine is very restrict: 2923ad976187SMauro Carvalho Chehab * It requires that both per-layer and per-transponder parameters to be 2924ad976187SMauro Carvalho Chehab * properly specified, otherwise the device won't lock. 2925ad976187SMauro Carvalho Chehab * 2926ad976187SMauro Carvalho Chehab * Check if all those conditions are properly satisfied before allowing 2927ad976187SMauro Carvalho Chehab * the device to use the manual frequency lock mode. 2928ad976187SMauro Carvalho Chehab */ 2929ad976187SMauro Carvalho Chehab static int is_manual_mode(struct dtv_frontend_properties *c) 2930ad976187SMauro Carvalho Chehab { 2931ad976187SMauro Carvalho Chehab int i, n_segs = 0; 2932ad976187SMauro Carvalho Chehab 2933ad976187SMauro Carvalho Chehab /* Use auto mode on DVB-T compat mode */ 2934ad976187SMauro Carvalho Chehab if (c->delivery_system != SYS_ISDBT) 2935ad976187SMauro Carvalho Chehab return 0; 2936ad976187SMauro Carvalho Chehab 2937ad976187SMauro Carvalho Chehab /* 2938ad976187SMauro Carvalho Chehab * Transmission mode is only detected on auto mode, currently 2939ad976187SMauro Carvalho Chehab */ 2940ad976187SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 29418af16adfSMauro Carvalho Chehab dprintk("transmission mode auto\n"); 2942ad976187SMauro Carvalho Chehab return 0; 2943ad976187SMauro Carvalho Chehab } 2944ad976187SMauro Carvalho Chehab 2945ad976187SMauro Carvalho Chehab /* 2946ad976187SMauro Carvalho Chehab * Guard interval is only detected on auto mode, currently 2947ad976187SMauro Carvalho Chehab */ 2948ad976187SMauro Carvalho Chehab if (c->guard_interval == GUARD_INTERVAL_AUTO) { 29498af16adfSMauro Carvalho Chehab dprintk("guard interval auto\n"); 2950ad976187SMauro Carvalho Chehab return 0; 2951ad976187SMauro Carvalho Chehab } 2952ad976187SMauro Carvalho Chehab 2953ad976187SMauro Carvalho Chehab /* 2954ad976187SMauro Carvalho Chehab * If no layer is enabled, assume auto mode, as at least one 2955ad976187SMauro Carvalho Chehab * layer should be enabled 2956ad976187SMauro Carvalho Chehab */ 2957ad976187SMauro Carvalho Chehab if (!c->isdbt_layer_enabled) { 29588af16adfSMauro Carvalho Chehab dprintk("no layer modulation specified\n"); 2959ad976187SMauro Carvalho Chehab return 0; 2960ad976187SMauro Carvalho Chehab } 2961ad976187SMauro Carvalho Chehab 2962ad976187SMauro Carvalho Chehab /* 2963ad976187SMauro Carvalho Chehab * Check if the per-layer parameters aren't auto and 2964ad976187SMauro Carvalho Chehab * disable a layer if segment count is 0 or invalid. 2965ad976187SMauro Carvalho Chehab */ 2966ad976187SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 2967ad976187SMauro Carvalho Chehab if (!(c->isdbt_layer_enabled & 1 << i)) 2968ad976187SMauro Carvalho Chehab continue; 2969ad976187SMauro Carvalho Chehab 2970ad976187SMauro Carvalho Chehab if ((c->layer[i].segment_count > 13) || 2971ad976187SMauro Carvalho Chehab (c->layer[i].segment_count == 0)) { 2972ad976187SMauro Carvalho Chehab c->isdbt_layer_enabled &= ~(1 << i); 2973ad976187SMauro Carvalho Chehab continue; 2974ad976187SMauro Carvalho Chehab } 2975ad976187SMauro Carvalho Chehab 2976ad976187SMauro Carvalho Chehab n_segs += c->layer[i].segment_count; 2977ad976187SMauro Carvalho Chehab 2978ad976187SMauro Carvalho Chehab if ((c->layer[i].modulation == QAM_AUTO) || 2979ad976187SMauro Carvalho Chehab (c->layer[i].fec == FEC_AUTO)) { 29808af16adfSMauro Carvalho Chehab dprintk("layer %c has either modulation or FEC auto\n", 2981ad976187SMauro Carvalho Chehab 'A' + i); 2982ad976187SMauro Carvalho Chehab return 0; 2983ad976187SMauro Carvalho Chehab } 2984ad976187SMauro Carvalho Chehab } 2985ad976187SMauro Carvalho Chehab 2986ad976187SMauro Carvalho Chehab /* 2987ad976187SMauro Carvalho Chehab * Userspace specified a wrong number of segments. 2988ad976187SMauro Carvalho Chehab * fallback to auto mode. 2989ad976187SMauro Carvalho Chehab */ 2990ad976187SMauro Carvalho Chehab if (n_segs == 0 || n_segs > 13) { 29918af16adfSMauro Carvalho Chehab dprintk("number of segments is invalid\n"); 2992ad976187SMauro Carvalho Chehab return 0; 2993ad976187SMauro Carvalho Chehab } 2994ad976187SMauro Carvalho Chehab 2995ad976187SMauro Carvalho Chehab /* Everything looks ok for manual mode */ 2996ad976187SMauro Carvalho Chehab return 1; 2997ad976187SMauro Carvalho Chehab } 2998ad976187SMauro Carvalho Chehab 29999a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe) 30009a0bf528SMauro Carvalho Chehab { 30019a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 3002c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 3003173a64cbSPatrick Boettcher enum frontend_tune_state *tune_state = &state->tune_state; 30049a0bf528SMauro Carvalho Chehab 3005173a64cbSPatrick Boettcher u16 locks, deeper_interleaver = 0, i; 3006173a64cbSPatrick Boettcher int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */ 30079a0bf528SMauro Carvalho Chehab 3008d6c62b76SMauro Carvalho Chehab unsigned long *timeout = &state->timeout; 3009d6c62b76SMauro Carvalho Chehab unsigned long now = jiffies; 3010173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 3011173a64cbSPatrick Boettcher u16 agc1, agc2; 3012173a64cbSPatrick Boettcher #endif 30139a0bf528SMauro Carvalho Chehab 3014173a64cbSPatrick Boettcher u32 corm[4] = {0, 0, 0, 0}; 3015173a64cbSPatrick Boettcher u8 find_index, max_value; 30169a0bf528SMauro Carvalho Chehab 3017173a64cbSPatrick Boettcher #if 0 3018173a64cbSPatrick Boettcher if (*tune_state < CT_DEMOD_STOP) 30198af16adfSMauro Carvalho Chehab dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu\n", 3020d6c62b76SMauro Carvalho Chehab state->channel_parameters_set, *tune_state, state->autosearch_state, now); 3021173a64cbSPatrick Boettcher #endif 30229a0bf528SMauro Carvalho Chehab 3023173a64cbSPatrick Boettcher switch (*tune_state) { 3024173a64cbSPatrick Boettcher case CT_DEMOD_START: /* 30 */ 30256ef06e78SMauro Carvalho Chehab dib8000_reset_stats(fe); 30266ef06e78SMauro Carvalho Chehab 3027173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3028173a64cbSPatrick Boettcher dib8090p_init_sdram(state); 3029173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING; 3030ad976187SMauro Carvalho Chehab state->channel_parameters_set = is_manual_mode(c); 3031ad976187SMauro Carvalho Chehab 30328af16adfSMauro Carvalho Chehab dprintk("Tuning channel on %s search mode\n", 3033ad976187SMauro Carvalho Chehab state->channel_parameters_set ? "manual" : "auto"); 30349a0bf528SMauro Carvalho Chehab 3035173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 0); /* force chan dec in restart */ 30369a0bf528SMauro Carvalho Chehab 3037ad976187SMauro Carvalho Chehab /* Layer monitor */ 3038173a64cbSPatrick Boettcher dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); 3039173a64cbSPatrick Boettcher 3040173a64cbSPatrick Boettcher dib8000_set_frequency_offset(state); 3041c82056d0SMauro Carvalho Chehab dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000); 3042173a64cbSPatrick Boettcher 3043173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */ 3044173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 3045173a64cbSPatrick Boettcher if (state->revision != 0x8090) { 3046173a64cbSPatrick Boettcher state->agc1_max = dib8000_read_word(state, 108); 3047173a64cbSPatrick Boettcher state->agc1_min = dib8000_read_word(state, 109); 3048173a64cbSPatrick Boettcher state->agc2_max = dib8000_read_word(state, 110); 3049173a64cbSPatrick Boettcher state->agc2_min = dib8000_read_word(state, 111); 3050173a64cbSPatrick Boettcher agc1 = dib8000_read_word(state, 388); 3051173a64cbSPatrick Boettcher agc2 = dib8000_read_word(state, 389); 3052173a64cbSPatrick Boettcher dib8000_write_word(state, 108, agc1); 3053173a64cbSPatrick Boettcher dib8000_write_word(state, 109, agc1); 3054173a64cbSPatrick Boettcher dib8000_write_word(state, 110, agc2); 3055173a64cbSPatrick Boettcher dib8000_write_word(state, 111, agc2); 3056173a64cbSPatrick Boettcher } 3057173a64cbSPatrick Boettcher #endif 3058173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_FFT; 3059173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_AUTO; 3060173a64cbSPatrick Boettcher state->found_guard = GUARD_INTERVAL_AUTO; 3061173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT; 3062173a64cbSPatrick Boettcher } else { /* we already know the channel struct so TUNE only ! */ 3063173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3064173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 3065173a64cbSPatrick Boettcher } 3066173a64cbSPatrick Boettcher state->symbol_duration = dib8000_get_symbol_duration(state); 3067173a64cbSPatrick Boettcher break; 3068173a64cbSPatrick Boettcher 3069173a64cbSPatrick Boettcher case CT_DEMOD_SEARCH_NEXT: /* 51 */ 3070173a64cbSPatrick Boettcher dib8000_autosearch_start(fe); 3071173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3072173a64cbSPatrick Boettcher ret = 50; 3073173a64cbSPatrick Boettcher else 3074173a64cbSPatrick Boettcher ret = 15; 3075173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_1; 3076173a64cbSPatrick Boettcher break; 3077173a64cbSPatrick Boettcher 3078173a64cbSPatrick Boettcher case CT_DEMOD_STEP_1: /* 31 */ 3079173a64cbSPatrick Boettcher switch (dib8000_autosearch_irq(fe)) { 3080173a64cbSPatrick Boettcher case 1: /* fail */ 3081173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3082173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3083173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */ 3084173a64cbSPatrick Boettcher break; 3085173a64cbSPatrick Boettcher case 2: /* Succes */ 3086173a64cbSPatrick Boettcher state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */ 3087173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 3088173a64cbSPatrick Boettcher if (state->autosearch_state == AS_SEARCHING_GUARD) 3089173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2; 3090173a64cbSPatrick Boettcher else 3091173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3092173a64cbSPatrick Boettcher break; 3093173a64cbSPatrick Boettcher case 3: /* Autosearch FFT max correlation endded */ 3094173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2; 3095173a64cbSPatrick Boettcher break; 3096173a64cbSPatrick Boettcher } 3097173a64cbSPatrick Boettcher break; 3098173a64cbSPatrick Boettcher 3099173a64cbSPatrick Boettcher case CT_DEMOD_STEP_2: 3100173a64cbSPatrick Boettcher switch (state->autosearch_state) { 3101173a64cbSPatrick Boettcher case AS_SEARCHING_FFT: 3102173a64cbSPatrick Boettcher /* searching for the correct FFT */ 3103173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 3104173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); 3105173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); 3106173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601)); 3107173a64cbSPatrick Boettcher } else { 3108173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595)); 3109173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); 3110173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); 3111173a64cbSPatrick Boettcher } 31128af16adfSMauro Carvalho Chehab /* dprintk("corm fft: %u %u %u\n", corm[0], corm[1], corm[2]); */ 3113173a64cbSPatrick Boettcher 3114173a64cbSPatrick Boettcher max_value = 0; 3115173a64cbSPatrick Boettcher for (find_index = 1 ; find_index < 3 ; find_index++) { 3116173a64cbSPatrick Boettcher if (corm[max_value] < corm[find_index]) 3117173a64cbSPatrick Boettcher max_value = find_index ; 31189a0bf528SMauro Carvalho Chehab } 31199a0bf528SMauro Carvalho Chehab 3120173a64cbSPatrick Boettcher switch (max_value) { 3121173a64cbSPatrick Boettcher case 0: 3122173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_2K; 3123173a64cbSPatrick Boettcher break; 3124173a64cbSPatrick Boettcher case 1: 3125173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_4K; 3126173a64cbSPatrick Boettcher break; 3127173a64cbSPatrick Boettcher case 2: 3128173a64cbSPatrick Boettcher default: 3129173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_8K; 3130173a64cbSPatrick Boettcher break; 3131173a64cbSPatrick Boettcher } 31328af16adfSMauro Carvalho Chehab /* dprintk("Autosearch FFT has found Mode %d\n", max_value + 1); */ 3133173a64cbSPatrick Boettcher 3134173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT; 3135173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_GUARD; 3136173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3137173a64cbSPatrick Boettcher ret = 50; 3138173a64cbSPatrick Boettcher else 3139173a64cbSPatrick Boettcher ret = 10; 3140173a64cbSPatrick Boettcher break; 3141173a64cbSPatrick Boettcher case AS_SEARCHING_GUARD: 3142173a64cbSPatrick Boettcher /* searching for the correct guard interval */ 3143173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3144173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 572) & 0x3; 3145173a64cbSPatrick Boettcher else 3146173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 570) & 0x3; 31478af16adfSMauro Carvalho Chehab /* dprintk("guard interval found=%i\n", state->found_guard); */ 3148173a64cbSPatrick Boettcher 3149173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 3150173a64cbSPatrick Boettcher break; 3151173a64cbSPatrick Boettcher default: 3152173a64cbSPatrick Boettcher /* the demod should never be in this state */ 3153173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3154173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3155173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */ 3156173a64cbSPatrick Boettcher break; 3157173a64cbSPatrick Boettcher } 3158173a64cbSPatrick Boettcher break; 3159173a64cbSPatrick Boettcher 3160173a64cbSPatrick Boettcher case CT_DEMOD_STEP_3: /* 33 */ 3161173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1); 3162173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */ 3163173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_4; 3164173a64cbSPatrick Boettcher break; 3165173a64cbSPatrick Boettcher 3166173a64cbSPatrick Boettcher case CT_DEMOD_STEP_4: /* (34) */ 3167173a64cbSPatrick Boettcher dib8000_demod_restart(state); 3168173a64cbSPatrick Boettcher 3169173a64cbSPatrick Boettcher dib8000_set_sync_wait(state); 3170173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); 3171173a64cbSPatrick Boettcher 3172173a64cbSPatrick Boettcher locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */ 317339c1cb2bSJonathan McCrohan /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */ 3174173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON); 3175173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_5; 3176173a64cbSPatrick Boettcher break; 3177173a64cbSPatrick Boettcher 3178173a64cbSPatrick Boettcher case CT_DEMOD_STEP_5: /* (35) */ 3179173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3180173a64cbSPatrick Boettcher if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */ 3181173a64cbSPatrick Boettcher dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */ 3182173a64cbSPatrick Boettcher if (!state->differential_constellation) { 3183173a64cbSPatrick Boettcher /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */ 3184173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON); 3185173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_7; 3186173a64cbSPatrick Boettcher } else { 3187173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; 3188173a64cbSPatrick Boettcher } 3189d6c62b76SMauro Carvalho Chehab } else if (time_after(now, *timeout)) { 3190173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ 3191173a64cbSPatrick Boettcher } 3192173a64cbSPatrick Boettcher break; 3193173a64cbSPatrick Boettcher 3194173a64cbSPatrick Boettcher case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */ 3195173a64cbSPatrick Boettcher if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { 3196173a64cbSPatrick Boettcher /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */ 3197173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ 3198173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ 3199173a64cbSPatrick Boettcher else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */ 3200173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ 3201173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3202173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3203173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3204173a64cbSPatrick Boettcher } 3205173a64cbSPatrick Boettcher } else { 3206173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3207173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3208173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ 3209173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3210173a64cbSPatrick Boettcher } 3211173a64cbSPatrick Boettcher break; 3212173a64cbSPatrick Boettcher 3213173a64cbSPatrick Boettcher case CT_DEMOD_STEP_7: /* 37 */ 3214173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3215173a64cbSPatrick Boettcher if (locks & (1<<10)) { /* lmod4_lock */ 3216173a64cbSPatrick Boettcher ret = 14; /* wait for 14 symbols */ 3217173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; 3218d6c62b76SMauro Carvalho Chehab } else if (time_after(now, *timeout)) 3219173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ 3220173a64cbSPatrick Boettcher break; 3221173a64cbSPatrick Boettcher 3222173a64cbSPatrick Boettcher case CT_DEMOD_STEP_8: /* 38 */ 3223173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3224173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3225173a64cbSPatrick Boettcher 3226173a64cbSPatrick Boettcher /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ 3227746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3228746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3229746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) { 3230173a64cbSPatrick Boettcher state->subchannel = 0; 3231173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11; 3232173a64cbSPatrick Boettcher } else { 3233173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9; 3234173a64cbSPatrick Boettcher state->status = FE_STATUS_LOCKED; 3235173a64cbSPatrick Boettcher } 3236173a64cbSPatrick Boettcher break; 3237173a64cbSPatrick Boettcher 3238173a64cbSPatrick Boettcher case CT_DEMOD_STEP_9: /* 39 */ 3239173a64cbSPatrick Boettcher if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */ 324039c1cb2bSJonathan McCrohan /* defines timeout for mpeg lock depending on interleaver length of longest layer */ 3241173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) { 3242c82056d0SMauro Carvalho Chehab if (c->layer[i].interleaving >= deeper_interleaver) { 32438af16adfSMauro Carvalho Chehab dprintk("layer%i: time interleaver = %d\n", i, c->layer[i].interleaving); 3244c82056d0SMauro Carvalho Chehab if (c->layer[i].segment_count > 0) { /* valid layer */ 3245c82056d0SMauro Carvalho Chehab deeper_interleaver = c->layer[0].interleaving; 3246173a64cbSPatrick Boettcher state->longest_intlv_layer = i; 3247173a64cbSPatrick Boettcher } 3248173a64cbSPatrick Boettcher } 3249173a64cbSPatrick Boettcher } 3250173a64cbSPatrick Boettcher 3251173a64cbSPatrick Boettcher if (deeper_interleaver == 0) 3252173a64cbSPatrick Boettcher locks = 2; /* locks is the tmp local variable name */ 3253173a64cbSPatrick Boettcher else if (deeper_interleaver == 3) 3254173a64cbSPatrick Boettcher locks = 8; 3255173a64cbSPatrick Boettcher else 3256173a64cbSPatrick Boettcher locks = 2 * deeper_interleaver; 3257173a64cbSPatrick Boettcher 3258173a64cbSPatrick Boettcher if (state->diversity_onoff != 0) /* because of diversity sync */ 3259173a64cbSPatrick Boettcher locks *= 2; 3260173a64cbSPatrick Boettcher 3261d6c62b76SMauro Carvalho Chehab *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */ 32628af16adfSMauro Carvalho Chehab dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld\n", 3263d6c62b76SMauro Carvalho Chehab deeper_interleaver, state->longest_intlv_layer, locks, *timeout); 3264173a64cbSPatrick Boettcher 3265173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_10; 3266173a64cbSPatrick Boettcher } else 3267173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3268173a64cbSPatrick Boettcher break; 3269173a64cbSPatrick Boettcher 3270173a64cbSPatrick Boettcher case CT_DEMOD_STEP_10: /* 40 */ 3271173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3272173a64cbSPatrick Boettcher if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ 32738af16adfSMauro Carvalho Chehab dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s\n", 32743c0d394eSMauro Carvalho Chehab c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", 32753c0d394eSMauro Carvalho Chehab c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", 32763c0d394eSMauro Carvalho Chehab c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled"); 3277746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3278746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3279746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) 3280173a64cbSPatrick Boettcher /* signal to the upper layer, that there was a channel found and the parameters can be read */ 3281173a64cbSPatrick Boettcher state->status = FE_STATUS_DEMOD_SUCCESS; 3282173a64cbSPatrick Boettcher else 3283173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED; 3284173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3285d6c62b76SMauro Carvalho Chehab } else if (time_after(now, *timeout)) { 3286746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3287746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3288746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) { /* continue to try init prbs autosearch */ 3289173a64cbSPatrick Boettcher state->subchannel += 3; 3290173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11; 3291173a64cbSPatrick Boettcher } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */ 3292173a64cbSPatrick Boettcher if (locks & (0x7 << 5)) { 32938af16adfSMauro Carvalho Chehab dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s\n", 32943c0d394eSMauro Carvalho Chehab jiffies_to_msecs(now - *timeout), 32953c0d394eSMauro Carvalho Chehab c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", 32963c0d394eSMauro Carvalho Chehab c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", 32973c0d394eSMauro Carvalho Chehab c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled"); 32983c0d394eSMauro Carvalho Chehab 3299173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED; 3300173a64cbSPatrick Boettcher } else 3301173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3302173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3303173a64cbSPatrick Boettcher } 3304173a64cbSPatrick Boettcher } 3305173a64cbSPatrick Boettcher break; 3306173a64cbSPatrick Boettcher 3307173a64cbSPatrick Boettcher case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */ 3308173a64cbSPatrick Boettcher if (state->subchannel <= 41) { 3309173a64cbSPatrick Boettcher dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); 3310173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9; 3311173a64cbSPatrick Boettcher } else { 3312173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3313173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3314173a64cbSPatrick Boettcher } 3315173a64cbSPatrick Boettcher break; 3316173a64cbSPatrick Boettcher 3317173a64cbSPatrick Boettcher default: 3318173a64cbSPatrick Boettcher break; 3319173a64cbSPatrick Boettcher } 3320173a64cbSPatrick Boettcher 3321173a64cbSPatrick Boettcher /* tuning is finished - cleanup the demod */ 3322173a64cbSPatrick Boettcher switch (*tune_state) { 3323173a64cbSPatrick Boettcher case CT_DEMOD_STOP: /* (42) */ 3324173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 3325173a64cbSPatrick Boettcher if ((state->revision != 0x8090) && (state->agc1_max != 0)) { 3326173a64cbSPatrick Boettcher dib8000_write_word(state, 108, state->agc1_max); 3327173a64cbSPatrick Boettcher dib8000_write_word(state, 109, state->agc1_min); 3328173a64cbSPatrick Boettcher dib8000_write_word(state, 110, state->agc2_max); 3329173a64cbSPatrick Boettcher dib8000_write_word(state, 111, state->agc2_min); 3330173a64cbSPatrick Boettcher state->agc1_max = 0; 3331173a64cbSPatrick Boettcher state->agc1_min = 0; 3332173a64cbSPatrick Boettcher state->agc2_max = 0; 3333173a64cbSPatrick Boettcher state->agc2_min = 0; 3334173a64cbSPatrick Boettcher } 3335173a64cbSPatrick Boettcher #endif 3336d6c62b76SMauro Carvalho Chehab ret = 0; 3337173a64cbSPatrick Boettcher break; 3338173a64cbSPatrick Boettcher default: 3339173a64cbSPatrick Boettcher break; 3340173a64cbSPatrick Boettcher } 3341173a64cbSPatrick Boettcher 3342173a64cbSPatrick Boettcher if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3)) 3343173a64cbSPatrick Boettcher return ret * state->symbol_duration; 3344173a64cbSPatrick Boettcher if ((ret > 0) && (ret < state->symbol_duration)) 3345173a64cbSPatrick Boettcher return state->symbol_duration; /* at least one symbol */ 33469a0bf528SMauro Carvalho Chehab return ret; 33479a0bf528SMauro Carvalho Chehab } 33489a0bf528SMauro Carvalho Chehab 33499a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe) 33509a0bf528SMauro Carvalho Chehab { 33519a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 33529a0bf528SMauro Carvalho Chehab u8 index_frontend; 33539a0bf528SMauro Carvalho Chehab int ret; 33549a0bf528SMauro Carvalho Chehab 33559a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 33569a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 33579a0bf528SMauro Carvalho Chehab if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) 33588af16adfSMauro Carvalho Chehab dprintk("could not start Slow ADC\n"); 33599a0bf528SMauro Carvalho Chehab 3360173a64cbSPatrick Boettcher if (state->revision == 0x8090) 33619a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state); 33629a0bf528SMauro Carvalho Chehab 33639a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 33649a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); 33659a0bf528SMauro Carvalho Chehab if (ret < 0) 33669a0bf528SMauro Carvalho Chehab return ret; 33679a0bf528SMauro Carvalho Chehab } 33689a0bf528SMauro Carvalho Chehab 33699a0bf528SMauro Carvalho Chehab return 0; 33709a0bf528SMauro Carvalho Chehab } 33719a0bf528SMauro Carvalho Chehab 33729a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe) 33739a0bf528SMauro Carvalho Chehab { 33749a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 33759a0bf528SMauro Carvalho Chehab u8 index_frontend; 33769a0bf528SMauro Carvalho Chehab int ret; 33779a0bf528SMauro Carvalho Chehab 33789a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 33799a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); 33809a0bf528SMauro Carvalho Chehab if (ret < 0) 33819a0bf528SMauro Carvalho Chehab return ret; 33829a0bf528SMauro Carvalho Chehab } 33839a0bf528SMauro Carvalho Chehab 33849a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 33859a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); 33869a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); 33879a0bf528SMauro Carvalho Chehab return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); 33889a0bf528SMauro Carvalho Chehab } 33899a0bf528SMauro Carvalho Chehab 33900df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat); 339170315b3eSMauro Carvalho Chehab 33927e3e68bcSMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe, 33937e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *c) 33949a0bf528SMauro Carvalho Chehab { 33959a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 33969a0bf528SMauro Carvalho Chehab u16 i, val = 0; 33970df289a2SMauro Carvalho Chehab enum fe_status stat = 0; 33989a0bf528SMauro Carvalho Chehab u8 index_frontend, sub_index_frontend; 33999a0bf528SMauro Carvalho Chehab 34007e3e68bcSMauro Carvalho Chehab c->bandwidth_hz = 6000000; 34019a0bf528SMauro Carvalho Chehab 340270315b3eSMauro Carvalho Chehab /* 340370315b3eSMauro Carvalho Chehab * If called to early, get_frontend makes dib8000_tune to either 340470315b3eSMauro Carvalho Chehab * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail. 340570315b3eSMauro Carvalho Chehab * So, let's just return if frontend 0 has not locked. 340670315b3eSMauro Carvalho Chehab */ 340770315b3eSMauro Carvalho Chehab dib8000_read_status(fe, &stat); 340870315b3eSMauro Carvalho Chehab if (!(stat & FE_HAS_SYNC)) 340970315b3eSMauro Carvalho Chehab return 0; 341070315b3eSMauro Carvalho Chehab 34118af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: TMCC lock\n"); 34129a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 34139a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); 34149a0bf528SMauro Carvalho Chehab if (stat&FE_HAS_SYNC) { 34158af16adfSMauro Carvalho Chehab dprintk("TMCC lock on the slave%i\n", index_frontend); 34169a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 34177e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c); 34189a0bf528SMauro Carvalho Chehab for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { 34199a0bf528SMauro Carvalho Chehab if (sub_index_frontend != index_frontend) { 34209a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; 34219a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; 34229a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; 34239a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; 34249a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; 34259a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 34269a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; 34279a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; 34289a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; 34299a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; 34309a0bf528SMauro Carvalho Chehab } 34319a0bf528SMauro Carvalho Chehab } 34329a0bf528SMauro Carvalho Chehab } 34339a0bf528SMauro Carvalho Chehab return 0; 34349a0bf528SMauro Carvalho Chehab } 34359a0bf528SMauro Carvalho Chehab } 34369a0bf528SMauro Carvalho Chehab 34377e3e68bcSMauro Carvalho Chehab c->isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; 34389a0bf528SMauro Carvalho Chehab 34399a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 34409a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 572); 34419a0bf528SMauro Carvalho Chehab else 34429a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 570); 34437e3e68bcSMauro Carvalho Chehab c->inversion = (val & 0x40) >> 6; 34449a0bf528SMauro Carvalho Chehab switch ((val & 0x30) >> 4) { 34459a0bf528SMauro Carvalho Chehab case 1: 34467e3e68bcSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_2K; 34478af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: transmission mode 2K\n"); 34489a0bf528SMauro Carvalho Chehab break; 34497fec1c80SMauro Carvalho Chehab case 2: 34507e3e68bcSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_4K; 34518af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: transmission mode 4K\n"); 34527fec1c80SMauro Carvalho Chehab break; 34539a0bf528SMauro Carvalho Chehab case 3: 34549a0bf528SMauro Carvalho Chehab default: 34557e3e68bcSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 34568af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: transmission mode 8K\n"); 34579a0bf528SMauro Carvalho Chehab break; 34589a0bf528SMauro Carvalho Chehab } 34599a0bf528SMauro Carvalho Chehab 34609a0bf528SMauro Carvalho Chehab switch (val & 0x3) { 34619a0bf528SMauro Carvalho Chehab case 0: 34627e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_32; 34638af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/32\n"); 34649a0bf528SMauro Carvalho Chehab break; 34659a0bf528SMauro Carvalho Chehab case 1: 34667e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_16; 34678af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/16\n"); 34689a0bf528SMauro Carvalho Chehab break; 34699a0bf528SMauro Carvalho Chehab case 2: 34708af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/8\n"); 34717e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 34729a0bf528SMauro Carvalho Chehab break; 34739a0bf528SMauro Carvalho Chehab case 3: 34748af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/4\n"); 34757e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_4; 34769a0bf528SMauro Carvalho Chehab break; 34779a0bf528SMauro Carvalho Chehab } 34789a0bf528SMauro Carvalho Chehab 34799a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 505); 34807e3e68bcSMauro Carvalho Chehab c->isdbt_partial_reception = val & 1; 34818af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: partial_reception = %d\n", c->isdbt_partial_reception); 34829a0bf528SMauro Carvalho Chehab 34839a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 3484ecc31d55SMauro Carvalho Chehab int show; 3485ecc31d55SMauro Carvalho Chehab 3486ecc31d55SMauro Carvalho Chehab val = dib8000_read_word(state, 493 + i) & 0x0f; 34877e3e68bcSMauro Carvalho Chehab c->layer[i].segment_count = val; 3488ecc31d55SMauro Carvalho Chehab 3489ecc31d55SMauro Carvalho Chehab if (val == 0 || val > 13) 3490ecc31d55SMauro Carvalho Chehab show = 0; 3491ecc31d55SMauro Carvalho Chehab else 3492ecc31d55SMauro Carvalho Chehab show = 1; 3493ecc31d55SMauro Carvalho Chehab 3494ecc31d55SMauro Carvalho Chehab if (show) 34958af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d segments = %d\n", 34967e3e68bcSMauro Carvalho Chehab i, c->layer[i].segment_count); 34979a0bf528SMauro Carvalho Chehab 349851fea113SMauro Carvalho Chehab val = dib8000_read_word(state, 499 + i) & 0x3; 349951fea113SMauro Carvalho Chehab /* Interleaving can be 0, 1, 2 or 4 */ 350051fea113SMauro Carvalho Chehab if (val == 3) 350151fea113SMauro Carvalho Chehab val = 4; 35027e3e68bcSMauro Carvalho Chehab c->layer[i].interleaving = val; 3503ecc31d55SMauro Carvalho Chehab if (show) 35048af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d time_intlv = %d\n", 35057e3e68bcSMauro Carvalho Chehab i, c->layer[i].interleaving); 35069a0bf528SMauro Carvalho Chehab 35079a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 481 + i); 35089a0bf528SMauro Carvalho Chehab switch (val & 0x7) { 35099a0bf528SMauro Carvalho Chehab case 1: 35107e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_1_2; 3511ecc31d55SMauro Carvalho Chehab if (show) 35128af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2\n", i); 35139a0bf528SMauro Carvalho Chehab break; 35149a0bf528SMauro Carvalho Chehab case 2: 35157e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_2_3; 3516ecc31d55SMauro Carvalho Chehab if (show) 35178af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3\n", i); 35189a0bf528SMauro Carvalho Chehab break; 35199a0bf528SMauro Carvalho Chehab case 3: 35207e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_3_4; 3521ecc31d55SMauro Carvalho Chehab if (show) 35228af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4\n", i); 35239a0bf528SMauro Carvalho Chehab break; 35249a0bf528SMauro Carvalho Chehab case 5: 35257e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_5_6; 3526ecc31d55SMauro Carvalho Chehab if (show) 35278af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6\n", i); 35289a0bf528SMauro Carvalho Chehab break; 35299a0bf528SMauro Carvalho Chehab default: 35307e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_7_8; 3531ecc31d55SMauro Carvalho Chehab if (show) 35328af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8\n", i); 35339a0bf528SMauro Carvalho Chehab break; 35349a0bf528SMauro Carvalho Chehab } 35359a0bf528SMauro Carvalho Chehab 35369a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 487 + i); 35379a0bf528SMauro Carvalho Chehab switch (val & 0x3) { 35389a0bf528SMauro Carvalho Chehab case 0: 35397e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = DQPSK; 3540ecc31d55SMauro Carvalho Chehab if (show) 35418af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d DQPSK\n", i); 35429a0bf528SMauro Carvalho Chehab break; 35439a0bf528SMauro Carvalho Chehab case 1: 35447e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = QPSK; 3545ecc31d55SMauro Carvalho Chehab if (show) 35468af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d QPSK\n", i); 35479a0bf528SMauro Carvalho Chehab break; 35489a0bf528SMauro Carvalho Chehab case 2: 35497e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = QAM_16; 3550ecc31d55SMauro Carvalho Chehab if (show) 35518af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d QAM16\n", i); 35529a0bf528SMauro Carvalho Chehab break; 35539a0bf528SMauro Carvalho Chehab case 3: 35549a0bf528SMauro Carvalho Chehab default: 35557e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = QAM_64; 3556ecc31d55SMauro Carvalho Chehab if (show) 35578af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d QAM64\n", i); 35589a0bf528SMauro Carvalho Chehab break; 35599a0bf528SMauro Carvalho Chehab } 35609a0bf528SMauro Carvalho Chehab } 35619a0bf528SMauro Carvalho Chehab 35629a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 35639a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 35647e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode; 35657e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion; 35667e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode; 35677e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval; 35687e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception; 35699a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 35707e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count; 35717e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving; 35727e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec; 35737e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation; 35749a0bf528SMauro Carvalho Chehab } 35759a0bf528SMauro Carvalho Chehab } 35769a0bf528SMauro Carvalho Chehab return 0; 35779a0bf528SMauro Carvalho Chehab } 35789a0bf528SMauro Carvalho Chehab 35799a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe) 35809a0bf528SMauro Carvalho Chehab { 35819a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 3582c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 3583d6c62b76SMauro Carvalho Chehab int l, i, active, time, time_slave = 0; 3584173a64cbSPatrick Boettcher u8 exit_condition, index_frontend; 3585d6c62b76SMauro Carvalho Chehab unsigned long delay, callback_time; 35869a0bf528SMauro Carvalho Chehab 3587c82056d0SMauro Carvalho Chehab if (c->frequency == 0) { 35888af16adfSMauro Carvalho Chehab dprintk("dib8000: must at least specify frequency\n"); 35899a0bf528SMauro Carvalho Chehab return 0; 35909a0bf528SMauro Carvalho Chehab } 35919a0bf528SMauro Carvalho Chehab 3592c82056d0SMauro Carvalho Chehab if (c->bandwidth_hz == 0) { 35938af16adfSMauro Carvalho Chehab dprintk("dib8000: no bandwidth specified, set to default\n"); 3594c82056d0SMauro Carvalho Chehab c->bandwidth_hz = 6000000; 35959a0bf528SMauro Carvalho Chehab } 35969a0bf528SMauro Carvalho Chehab 35979a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 35989a0bf528SMauro Carvalho Chehab /* synchronization of the cache */ 35999a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; 36009a0bf528SMauro Carvalho Chehab memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); 36019a0bf528SMauro Carvalho Chehab 3602173a64cbSPatrick Boettcher /* set output mode and diversity input */ 3603173a64cbSPatrick Boettcher if (state->revision != 0x8090) { 3604173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend], 1); 3605173a64cbSPatrick Boettcher if (index_frontend != 0) 36069a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[index_frontend], 3607173a64cbSPatrick Boettcher OUTMODE_DIVERSITY); 36089a0bf528SMauro Carvalho Chehab else 3609173a64cbSPatrick Boettcher dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); 3610173a64cbSPatrick Boettcher } else { 3611173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend], 1); 3612173a64cbSPatrick Boettcher if (index_frontend != 0) 36139a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[index_frontend], 3614173a64cbSPatrick Boettcher OUTMODE_DIVERSITY); 3615173a64cbSPatrick Boettcher else 3616173a64cbSPatrick Boettcher dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); 3617173a64cbSPatrick Boettcher } 3618173a64cbSPatrick Boettcher 3619173a64cbSPatrick Boettcher /* tune the tuner */ 36209a0bf528SMauro Carvalho Chehab if (state->fe[index_frontend]->ops.tuner_ops.set_params) 36219a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]); 36229a0bf528SMauro Carvalho Chehab 36239a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); 36249a0bf528SMauro Carvalho Chehab } 36259a0bf528SMauro Carvalho Chehab 3626173a64cbSPatrick Boettcher /* turn off the diversity of the last chip */ 3627173a64cbSPatrick Boettcher if (state->revision != 0x8090) 3628173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend - 1], 0); 3629173a64cbSPatrick Boettcher else 3630173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0); 3631173a64cbSPatrick Boettcher 36329a0bf528SMauro Carvalho Chehab /* start up the AGC */ 36339a0bf528SMauro Carvalho Chehab do { 36349a0bf528SMauro Carvalho Chehab time = dib8000_agc_startup(state->fe[0]); 36359a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 36369a0bf528SMauro Carvalho Chehab time_slave = dib8000_agc_startup(state->fe[index_frontend]); 3637d6c62b76SMauro Carvalho Chehab if (time == 0) 36389a0bf528SMauro Carvalho Chehab time = time_slave; 3639d6c62b76SMauro Carvalho Chehab else if ((time_slave != 0) && (time_slave > time)) 36409a0bf528SMauro Carvalho Chehab time = time_slave; 36419a0bf528SMauro Carvalho Chehab } 3642d6c62b76SMauro Carvalho Chehab if (time == 0) 36439a0bf528SMauro Carvalho Chehab break; 36444607bb7aSMauro Carvalho Chehab 36454607bb7aSMauro Carvalho Chehab /* 36464607bb7aSMauro Carvalho Chehab * Despite dib8000_agc_startup returns time at a 0.1 ms range, 36474607bb7aSMauro Carvalho Chehab * the actual sleep time depends on CONFIG_HZ. The worse case 36484607bb7aSMauro Carvalho Chehab * is when CONFIG_HZ=100. In such case, the minimum granularity 36494607bb7aSMauro Carvalho Chehab * is 10ms. On some real field tests, the tuner sometimes don't 36504607bb7aSMauro Carvalho Chehab * lock when this timer is lower than 10ms. So, enforce a 10ms 36514607bb7aSMauro Carvalho Chehab * granularity. 36524607bb7aSMauro Carvalho Chehab */ 36534607bb7aSMauro Carvalho Chehab time = 10 * (time + 99)/100; 36544607bb7aSMauro Carvalho Chehab usleep_range(time * 1000, (time + 1) * 1000); 36559a0bf528SMauro Carvalho Chehab exit_condition = 1; 36569a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 36579a0bf528SMauro Carvalho Chehab if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { 36589a0bf528SMauro Carvalho Chehab exit_condition = 0; 36599a0bf528SMauro Carvalho Chehab break; 36609a0bf528SMauro Carvalho Chehab } 36619a0bf528SMauro Carvalho Chehab } 36629a0bf528SMauro Carvalho Chehab } while (exit_condition == 0); 36639a0bf528SMauro Carvalho Chehab 36649a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 36659a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); 36669a0bf528SMauro Carvalho Chehab 3667173a64cbSPatrick Boettcher active = 1; 36689a0bf528SMauro Carvalho Chehab do { 3669d6c62b76SMauro Carvalho Chehab callback_time = 0; 36709a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 3671173a64cbSPatrick Boettcher delay = dib8000_tune(state->fe[index_frontend]); 3672d6c62b76SMauro Carvalho Chehab if (delay != 0) { 3673d6c62b76SMauro Carvalho Chehab delay = jiffies + usecs_to_jiffies(100 * delay); 3674d6c62b76SMauro Carvalho Chehab if (!callback_time || delay < callback_time) 3675d6c62b76SMauro Carvalho Chehab callback_time = delay; 3676d6c62b76SMauro Carvalho Chehab } 3677173a64cbSPatrick Boettcher 3678173a64cbSPatrick Boettcher /* we are in autosearch */ 3679173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* searching */ 3680173a64cbSPatrick Boettcher if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) { 36818af16adfSMauro Carvalho Chehab dprintk("autosearch succeeded on fe%i\n", index_frontend); 36827e3e68bcSMauro Carvalho Chehab dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */ 3683173a64cbSPatrick Boettcher state->channel_parameters_set = 1; 3684173a64cbSPatrick Boettcher 3685173a64cbSPatrick Boettcher for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) { 3686173a64cbSPatrick Boettcher if (l != index_frontend) { /* and for all frontend except the successful one */ 3687ecc31d55SMauro Carvalho Chehab dprintk("Restarting frontend %d\n", l); 3688173a64cbSPatrick Boettcher dib8000_tune_restart_from_demod(state->fe[l]); 3689173a64cbSPatrick Boettcher 3690173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; 3691173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; 3692173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; 3693173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; 3694173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; 3695173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) { 3696173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; 3697173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; 3698173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; 3699173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; 3700173a64cbSPatrick Boettcher } 3701173a64cbSPatrick Boettcher 37029a0bf528SMauro Carvalho Chehab } 37039a0bf528SMauro Carvalho Chehab } 37049a0bf528SMauro Carvalho Chehab } 3705173a64cbSPatrick Boettcher } 3706173a64cbSPatrick Boettcher } 3707173a64cbSPatrick Boettcher /* tuning is done when the master frontend is done (failed or success) */ 3708173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED || 3709173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED || 3710173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) { 3711173a64cbSPatrick Boettcher active = 0; 3712173a64cbSPatrick Boettcher /* we need to wait for all frontends to be finished */ 3713173a64cbSPatrick Boettcher for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 3714173a64cbSPatrick Boettcher if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP) 3715173a64cbSPatrick Boettcher active = 1; 3716173a64cbSPatrick Boettcher } 3717173a64cbSPatrick Boettcher if (active == 0) 37188af16adfSMauro Carvalho Chehab dprintk("tuning done with status %d\n", dib8000_get_status(state->fe[0])); 37199a0bf528SMauro Carvalho Chehab } 37209a0bf528SMauro Carvalho Chehab 3721d6c62b76SMauro Carvalho Chehab if ((active == 1) && (callback_time == 0)) { 37228af16adfSMauro Carvalho Chehab dprintk("strange callback time something went wrong\n"); 3723173a64cbSPatrick Boettcher active = 0; 37249a0bf528SMauro Carvalho Chehab } 37259a0bf528SMauro Carvalho Chehab 3726d6c62b76SMauro Carvalho Chehab while ((active == 1) && (time_before(jiffies, callback_time))) 3727173a64cbSPatrick Boettcher msleep(100); 3728173a64cbSPatrick Boettcher } while (active); 37299a0bf528SMauro Carvalho Chehab 3730173a64cbSPatrick Boettcher /* set output mode */ 3731173a64cbSPatrick Boettcher if (state->revision != 0x8090) 37329a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); 3733173a64cbSPatrick Boettcher else { 37349a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode); 37359a0bf528SMauro Carvalho Chehab if (state->cfg.enMpegOutput == 0) { 37369a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, MPEG_ON_DIBTX); 37379a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 37389a0bf528SMauro Carvalho Chehab } 37399a0bf528SMauro Carvalho Chehab } 37409a0bf528SMauro Carvalho Chehab 37414d8d5d92SGeert Uytterhoeven return 0; 37429a0bf528SMauro Carvalho Chehab } 37439a0bf528SMauro Carvalho Chehab 37440df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat); 37456ef06e78SMauro Carvalho Chehab 37460df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat) 37479a0bf528SMauro Carvalho Chehab { 37489a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37499a0bf528SMauro Carvalho Chehab u16 lock_slave = 0, lock; 37509a0bf528SMauro Carvalho Chehab u8 index_frontend; 37519a0bf528SMauro Carvalho Chehab 3752173a64cbSPatrick Boettcher lock = dib8000_read_lock(fe); 37539a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 37549a0bf528SMauro Carvalho Chehab lock_slave |= dib8000_read_lock(state->fe[index_frontend]); 37559a0bf528SMauro Carvalho Chehab 37569a0bf528SMauro Carvalho Chehab *stat = 0; 37579a0bf528SMauro Carvalho Chehab 37589a0bf528SMauro Carvalho Chehab if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1)) 37599a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SIGNAL; 37609a0bf528SMauro Carvalho Chehab 37619a0bf528SMauro Carvalho Chehab if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */ 37629a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_CARRIER; 37639a0bf528SMauro Carvalho Chehab 37649a0bf528SMauro Carvalho Chehab if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */ 37659a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SYNC; 37669a0bf528SMauro Carvalho Chehab 37679a0bf528SMauro Carvalho Chehab if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */ 37689a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_LOCK; 37699a0bf528SMauro Carvalho Chehab 37709a0bf528SMauro Carvalho Chehab if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) { 37719a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ 37729a0bf528SMauro Carvalho Chehab if (lock & 0x01) 37739a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 37749a0bf528SMauro Carvalho Chehab 37759a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ 37769a0bf528SMauro Carvalho Chehab if (lock & 0x01) 37779a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 37789a0bf528SMauro Carvalho Chehab 37799a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ 37809a0bf528SMauro Carvalho Chehab if (lock & 0x01) 37819a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 37829a0bf528SMauro Carvalho Chehab } 37836ef06e78SMauro Carvalho Chehab dib8000_get_stats(fe, *stat); 37849a0bf528SMauro Carvalho Chehab 37859a0bf528SMauro Carvalho Chehab return 0; 37869a0bf528SMauro Carvalho Chehab } 37879a0bf528SMauro Carvalho Chehab 37889a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) 37899a0bf528SMauro Carvalho Chehab { 37909a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37919a0bf528SMauro Carvalho Chehab 37929a0bf528SMauro Carvalho Chehab /* 13 segments */ 37939a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 37949a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 562) << 16) | 37959a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 563); 37969a0bf528SMauro Carvalho Chehab else 37979a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 560) << 16) | 37989a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 561); 37999a0bf528SMauro Carvalho Chehab return 0; 38009a0bf528SMauro Carvalho Chehab } 38019a0bf528SMauro Carvalho Chehab 38029a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) 38039a0bf528SMauro Carvalho Chehab { 38049a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 38059a0bf528SMauro Carvalho Chehab 38069a0bf528SMauro Carvalho Chehab /* packet error on 13 seg */ 38079a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 38089a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 567); 38099a0bf528SMauro Carvalho Chehab else 38109a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 565); 38119a0bf528SMauro Carvalho Chehab return 0; 38129a0bf528SMauro Carvalho Chehab } 38139a0bf528SMauro Carvalho Chehab 38149a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 38159a0bf528SMauro Carvalho Chehab { 38169a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 38179a0bf528SMauro Carvalho Chehab u8 index_frontend; 38189a0bf528SMauro Carvalho Chehab u16 val; 38199a0bf528SMauro Carvalho Chehab 38209a0bf528SMauro Carvalho Chehab *strength = 0; 38219a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 38229a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); 38239a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 38249a0bf528SMauro Carvalho Chehab *strength = 65535; 38259a0bf528SMauro Carvalho Chehab else 38269a0bf528SMauro Carvalho Chehab *strength += val; 38279a0bf528SMauro Carvalho Chehab } 38289a0bf528SMauro Carvalho Chehab 38299a0bf528SMauro Carvalho Chehab val = 65535 - dib8000_read_word(state, 390); 38309a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 38319a0bf528SMauro Carvalho Chehab *strength = 65535; 38329a0bf528SMauro Carvalho Chehab else 38339a0bf528SMauro Carvalho Chehab *strength += val; 38349a0bf528SMauro Carvalho Chehab return 0; 38359a0bf528SMauro Carvalho Chehab } 38369a0bf528SMauro Carvalho Chehab 38379a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe) 38389a0bf528SMauro Carvalho Chehab { 38399a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 38409a0bf528SMauro Carvalho Chehab u32 n, s, exp; 38419a0bf528SMauro Carvalho Chehab u16 val; 38429a0bf528SMauro Carvalho Chehab 38439a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 38449a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 542); 38459a0bf528SMauro Carvalho Chehab else 38469a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 544); 38479a0bf528SMauro Carvalho Chehab n = (val >> 6) & 0xff; 38489a0bf528SMauro Carvalho Chehab exp = (val & 0x3f); 38499a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 38509a0bf528SMauro Carvalho Chehab exp -= 0x40; 38519a0bf528SMauro Carvalho Chehab n <<= exp+16; 38529a0bf528SMauro Carvalho Chehab 38539a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 38549a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 543); 38559a0bf528SMauro Carvalho Chehab else 38569a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 545); 38579a0bf528SMauro Carvalho Chehab s = (val >> 6) & 0xff; 38589a0bf528SMauro Carvalho Chehab exp = (val & 0x3f); 38599a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 38609a0bf528SMauro Carvalho Chehab exp -= 0x40; 38619a0bf528SMauro Carvalho Chehab s <<= exp+16; 38629a0bf528SMauro Carvalho Chehab 38639a0bf528SMauro Carvalho Chehab if (n > 0) { 38649a0bf528SMauro Carvalho Chehab u32 t = (s/n) << 16; 38659a0bf528SMauro Carvalho Chehab return t + ((s << 16) - n*t) / n; 38669a0bf528SMauro Carvalho Chehab } 38679a0bf528SMauro Carvalho Chehab return 0xffffffff; 38689a0bf528SMauro Carvalho Chehab } 38699a0bf528SMauro Carvalho Chehab 38709a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) 38719a0bf528SMauro Carvalho Chehab { 38729a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 38739a0bf528SMauro Carvalho Chehab u8 index_frontend; 38749a0bf528SMauro Carvalho Chehab u32 snr_master; 38759a0bf528SMauro Carvalho Chehab 38769a0bf528SMauro Carvalho Chehab snr_master = dib8000_get_snr(fe); 38779a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 38789a0bf528SMauro Carvalho Chehab snr_master += dib8000_get_snr(state->fe[index_frontend]); 38799a0bf528SMauro Carvalho Chehab 38809a0bf528SMauro Carvalho Chehab if ((snr_master >> 16) != 0) { 38819a0bf528SMauro Carvalho Chehab snr_master = 10*intlog10(snr_master>>16); 38829a0bf528SMauro Carvalho Chehab *snr = snr_master / ((1 << 24) / 10); 38839a0bf528SMauro Carvalho Chehab } 38849a0bf528SMauro Carvalho Chehab else 38859a0bf528SMauro Carvalho Chehab *snr = 0; 38869a0bf528SMauro Carvalho Chehab 38879a0bf528SMauro Carvalho Chehab return 0; 38889a0bf528SMauro Carvalho Chehab } 38899a0bf528SMauro Carvalho Chehab 38906ef06e78SMauro Carvalho Chehab struct per_layer_regs { 38916ef06e78SMauro Carvalho Chehab u16 lock, ber, per; 38926ef06e78SMauro Carvalho Chehab }; 38936ef06e78SMauro Carvalho Chehab 38946ef06e78SMauro Carvalho Chehab static const struct per_layer_regs per_layer_regs[] = { 38956ef06e78SMauro Carvalho Chehab { 554, 560, 562 }, 38966ef06e78SMauro Carvalho Chehab { 555, 576, 578 }, 38976ef06e78SMauro Carvalho Chehab { 556, 581, 583 }, 38986ef06e78SMauro Carvalho Chehab }; 38996ef06e78SMauro Carvalho Chehab 390042ff76bdSMauro Carvalho Chehab struct linear_segments { 390142ff76bdSMauro Carvalho Chehab unsigned x; 390242ff76bdSMauro Carvalho Chehab signed y; 390342ff76bdSMauro Carvalho Chehab }; 390442ff76bdSMauro Carvalho Chehab 390542ff76bdSMauro Carvalho Chehab /* 390642ff76bdSMauro Carvalho Chehab * Table to estimate signal strength in dBm. 390742ff76bdSMauro Carvalho Chehab * This table was empirically determinated by measuring the signal 390842ff76bdSMauro Carvalho Chehab * strength generated by a DTA-2111 RF generator directly connected into 390942ff76bdSMauro Carvalho Chehab * a dib8076 device (a PixelView PV-D231U stick), using a good quality 391042ff76bdSMauro Carvalho Chehab * 3 meters RC6 cable and good RC6 connectors. 391142ff76bdSMauro Carvalho Chehab * The real value can actually be different on other devices, depending 391242ff76bdSMauro Carvalho Chehab * on several factors, like if LNA is enabled or not, if diversity is 391342ff76bdSMauro Carvalho Chehab * enabled, type of connectors, etc. 391442ff76bdSMauro Carvalho Chehab * Yet, it is better to use this measure in dB than a random non-linear 391542ff76bdSMauro Carvalho Chehab * percentage value, especially for antenna adjustments. 391642ff76bdSMauro Carvalho Chehab * On my tests, the precision of the measure using this table is about 391742ff76bdSMauro Carvalho Chehab * 0.5 dB, with sounds reasonable enough. 391842ff76bdSMauro Carvalho Chehab */ 391942ff76bdSMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = { 392042ff76bdSMauro Carvalho Chehab { 55953, 108500 }, /* -22.5 dBm */ 392142ff76bdSMauro Carvalho Chehab { 55394, 108000 }, 392242ff76bdSMauro Carvalho Chehab { 53834, 107000 }, 392342ff76bdSMauro Carvalho Chehab { 52863, 106000 }, 392442ff76bdSMauro Carvalho Chehab { 52239, 105000 }, 392542ff76bdSMauro Carvalho Chehab { 52012, 104000 }, 392642ff76bdSMauro Carvalho Chehab { 51803, 103000 }, 392742ff76bdSMauro Carvalho Chehab { 51566, 102000 }, 392842ff76bdSMauro Carvalho Chehab { 51356, 101000 }, 392942ff76bdSMauro Carvalho Chehab { 51112, 100000 }, 393042ff76bdSMauro Carvalho Chehab { 50869, 99000 }, 393142ff76bdSMauro Carvalho Chehab { 50600, 98000 }, 393242ff76bdSMauro Carvalho Chehab { 50363, 97000 }, 393342ff76bdSMauro Carvalho Chehab { 50117, 96000 }, /* -35 dBm */ 393442ff76bdSMauro Carvalho Chehab { 49889, 95000 }, 393542ff76bdSMauro Carvalho Chehab { 49680, 94000 }, 393642ff76bdSMauro Carvalho Chehab { 49493, 93000 }, 393742ff76bdSMauro Carvalho Chehab { 49302, 92000 }, 393842ff76bdSMauro Carvalho Chehab { 48929, 91000 }, 393942ff76bdSMauro Carvalho Chehab { 48416, 90000 }, 394042ff76bdSMauro Carvalho Chehab { 48035, 89000 }, 394142ff76bdSMauro Carvalho Chehab { 47593, 88000 }, 394242ff76bdSMauro Carvalho Chehab { 47282, 87000 }, 394342ff76bdSMauro Carvalho Chehab { 46953, 86000 }, 394442ff76bdSMauro Carvalho Chehab { 46698, 85000 }, 394542ff76bdSMauro Carvalho Chehab { 45617, 84000 }, 394642ff76bdSMauro Carvalho Chehab { 44773, 83000 }, 394742ff76bdSMauro Carvalho Chehab { 43845, 82000 }, 394842ff76bdSMauro Carvalho Chehab { 43020, 81000 }, 394942ff76bdSMauro Carvalho Chehab { 42010, 80000 }, /* -51 dBm */ 395042ff76bdSMauro Carvalho Chehab { 0, 0 }, 395142ff76bdSMauro Carvalho Chehab }; 395242ff76bdSMauro Carvalho Chehab 395342ff76bdSMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments, 395442ff76bdSMauro Carvalho Chehab unsigned len) 395542ff76bdSMauro Carvalho Chehab { 395642ff76bdSMauro Carvalho Chehab u64 tmp64; 395742ff76bdSMauro Carvalho Chehab u32 dx; 395842ff76bdSMauro Carvalho Chehab s32 dy; 395942ff76bdSMauro Carvalho Chehab int i, ret; 396042ff76bdSMauro Carvalho Chehab 396142ff76bdSMauro Carvalho Chehab if (value >= segments[0].x) 396242ff76bdSMauro Carvalho Chehab return segments[0].y; 396342ff76bdSMauro Carvalho Chehab if (value < segments[len-1].x) 396442ff76bdSMauro Carvalho Chehab return segments[len-1].y; 396542ff76bdSMauro Carvalho Chehab 396642ff76bdSMauro Carvalho Chehab for (i = 1; i < len - 1; i++) { 396742ff76bdSMauro Carvalho Chehab /* If value is identical, no need to interpolate */ 396842ff76bdSMauro Carvalho Chehab if (value == segments[i].x) 396942ff76bdSMauro Carvalho Chehab return segments[i].y; 397042ff76bdSMauro Carvalho Chehab if (value > segments[i].x) 397142ff76bdSMauro Carvalho Chehab break; 397242ff76bdSMauro Carvalho Chehab } 397342ff76bdSMauro Carvalho Chehab 397442ff76bdSMauro Carvalho Chehab /* Linear interpolation between the two (x,y) points */ 397542ff76bdSMauro Carvalho Chehab dy = segments[i - 1].y - segments[i].y; 397642ff76bdSMauro Carvalho Chehab dx = segments[i - 1].x - segments[i].x; 397742ff76bdSMauro Carvalho Chehab 397842ff76bdSMauro Carvalho Chehab tmp64 = value - segments[i].x; 397942ff76bdSMauro Carvalho Chehab tmp64 *= dy; 398042ff76bdSMauro Carvalho Chehab do_div(tmp64, dx); 398142ff76bdSMauro Carvalho Chehab ret = segments[i].y + tmp64; 398242ff76bdSMauro Carvalho Chehab 398342ff76bdSMauro Carvalho Chehab return ret; 398442ff76bdSMauro Carvalho Chehab } 398542ff76bdSMauro Carvalho Chehab 3986704f01bbSMauro Carvalho Chehab static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer) 3987704f01bbSMauro Carvalho Chehab { 3988704f01bbSMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 3989704f01bbSMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 3990704f01bbSMauro Carvalho Chehab int ini_layer, end_layer, i; 39914bf48150SMauro Carvalho Chehab u64 time_us, tmp64; 3992704f01bbSMauro Carvalho Chehab u32 tmp, denom; 3993e4a3bc1cSMauro Carvalho Chehab int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs; 3994e4a3bc1cSMauro Carvalho Chehab int interleaving = 0, fft_div; 3995704f01bbSMauro Carvalho Chehab 3996704f01bbSMauro Carvalho Chehab if (layer >= 0) { 3997704f01bbSMauro Carvalho Chehab ini_layer = layer; 3998704f01bbSMauro Carvalho Chehab end_layer = layer + 1; 3999704f01bbSMauro Carvalho Chehab } else { 4000704f01bbSMauro Carvalho Chehab ini_layer = 0; 4001704f01bbSMauro Carvalho Chehab end_layer = 3; 4002704f01bbSMauro Carvalho Chehab } 4003704f01bbSMauro Carvalho Chehab 4004704f01bbSMauro Carvalho Chehab switch (c->guard_interval) { 4005704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 4006704f01bbSMauro Carvalho Chehab guard = 4; 4007704f01bbSMauro Carvalho Chehab break; 4008704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 4009704f01bbSMauro Carvalho Chehab guard = 8; 4010704f01bbSMauro Carvalho Chehab break; 4011704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 4012704f01bbSMauro Carvalho Chehab guard = 16; 4013704f01bbSMauro Carvalho Chehab break; 4014704f01bbSMauro Carvalho Chehab default: 4015704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 4016704f01bbSMauro Carvalho Chehab guard = 32; 4017704f01bbSMauro Carvalho Chehab break; 4018704f01bbSMauro Carvalho Chehab } 4019704f01bbSMauro Carvalho Chehab 4020704f01bbSMauro Carvalho Chehab switch (c->transmission_mode) { 4021704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 4022704f01bbSMauro Carvalho Chehab fft_div = 4; 4023704f01bbSMauro Carvalho Chehab break; 4024704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 4025704f01bbSMauro Carvalho Chehab fft_div = 2; 4026704f01bbSMauro Carvalho Chehab break; 4027704f01bbSMauro Carvalho Chehab default: 4028704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 4029704f01bbSMauro Carvalho Chehab fft_div = 1; 4030704f01bbSMauro Carvalho Chehab break; 4031704f01bbSMauro Carvalho Chehab } 4032704f01bbSMauro Carvalho Chehab 4033704f01bbSMauro Carvalho Chehab denom = 0; 4034704f01bbSMauro Carvalho Chehab for (i = ini_layer; i < end_layer; i++) { 4035704f01bbSMauro Carvalho Chehab nsegs = c->layer[i].segment_count; 4036704f01bbSMauro Carvalho Chehab if (nsegs == 0 || nsegs > 13) 4037704f01bbSMauro Carvalho Chehab continue; 4038704f01bbSMauro Carvalho Chehab 4039704f01bbSMauro Carvalho Chehab switch (c->layer[i].modulation) { 4040704f01bbSMauro Carvalho Chehab case DQPSK: 4041704f01bbSMauro Carvalho Chehab case QPSK: 4042704f01bbSMauro Carvalho Chehab bits_per_symbol = 2; 4043704f01bbSMauro Carvalho Chehab break; 4044704f01bbSMauro Carvalho Chehab case QAM_16: 4045704f01bbSMauro Carvalho Chehab bits_per_symbol = 4; 4046704f01bbSMauro Carvalho Chehab break; 4047704f01bbSMauro Carvalho Chehab default: 4048704f01bbSMauro Carvalho Chehab case QAM_64: 4049704f01bbSMauro Carvalho Chehab bits_per_symbol = 6; 4050704f01bbSMauro Carvalho Chehab break; 4051704f01bbSMauro Carvalho Chehab } 4052704f01bbSMauro Carvalho Chehab 4053704f01bbSMauro Carvalho Chehab switch (c->layer[i].fec) { 4054704f01bbSMauro Carvalho Chehab case FEC_1_2: 4055704f01bbSMauro Carvalho Chehab rate_num = 1; 4056704f01bbSMauro Carvalho Chehab rate_denum = 2; 4057704f01bbSMauro Carvalho Chehab break; 4058704f01bbSMauro Carvalho Chehab case FEC_2_3: 4059704f01bbSMauro Carvalho Chehab rate_num = 2; 4060704f01bbSMauro Carvalho Chehab rate_denum = 3; 4061704f01bbSMauro Carvalho Chehab break; 4062704f01bbSMauro Carvalho Chehab case FEC_3_4: 4063704f01bbSMauro Carvalho Chehab rate_num = 3; 4064704f01bbSMauro Carvalho Chehab rate_denum = 4; 4065704f01bbSMauro Carvalho Chehab break; 4066704f01bbSMauro Carvalho Chehab case FEC_5_6: 4067704f01bbSMauro Carvalho Chehab rate_num = 5; 4068704f01bbSMauro Carvalho Chehab rate_denum = 6; 4069704f01bbSMauro Carvalho Chehab break; 4070704f01bbSMauro Carvalho Chehab default: 4071704f01bbSMauro Carvalho Chehab case FEC_7_8: 4072704f01bbSMauro Carvalho Chehab rate_num = 7; 4073704f01bbSMauro Carvalho Chehab rate_denum = 8; 4074704f01bbSMauro Carvalho Chehab break; 4075704f01bbSMauro Carvalho Chehab } 4076704f01bbSMauro Carvalho Chehab 4077704f01bbSMauro Carvalho Chehab interleaving = c->layer[i].interleaving; 4078704f01bbSMauro Carvalho Chehab 4079704f01bbSMauro Carvalho Chehab denom += bits_per_symbol * rate_num * fft_div * nsegs * 384; 4080704f01bbSMauro Carvalho Chehab } 4081704f01bbSMauro Carvalho Chehab 4082704f01bbSMauro Carvalho Chehab /* If all goes wrong, wait for 1s for the next stats */ 4083704f01bbSMauro Carvalho Chehab if (!denom) 4084704f01bbSMauro Carvalho Chehab return 0; 4085704f01bbSMauro Carvalho Chehab 4086704f01bbSMauro Carvalho Chehab /* Estimate the period for the total bit rate */ 4087704f01bbSMauro Carvalho Chehab time_us = rate_denum * (1008 * 1562500L); 40884bf48150SMauro Carvalho Chehab tmp64 = time_us; 40894bf48150SMauro Carvalho Chehab do_div(tmp64, guard); 40904bf48150SMauro Carvalho Chehab time_us = time_us + tmp64; 4091704f01bbSMauro Carvalho Chehab time_us += denom / 2; 4092704f01bbSMauro Carvalho Chehab do_div(time_us, denom); 4093704f01bbSMauro Carvalho Chehab 4094704f01bbSMauro Carvalho Chehab tmp = 1008 * 96 * interleaving; 4095704f01bbSMauro Carvalho Chehab time_us += tmp + tmp / guard; 4096704f01bbSMauro Carvalho Chehab 4097704f01bbSMauro Carvalho Chehab return time_us; 4098704f01bbSMauro Carvalho Chehab } 4099704f01bbSMauro Carvalho Chehab 41000df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat) 41016ef06e78SMauro Carvalho Chehab { 41026ef06e78SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 41036ef06e78SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 4104704f01bbSMauro Carvalho Chehab int i; 41050400c535SMauro Carvalho Chehab int show_per_stats = 0; 41060400c535SMauro Carvalho Chehab u32 time_us = 0, snr, val; 41070400c535SMauro Carvalho Chehab u64 blocks; 410842ff76bdSMauro Carvalho Chehab s32 db; 41096ef06e78SMauro Carvalho Chehab u16 strength; 41106ef06e78SMauro Carvalho Chehab 41116ef06e78SMauro Carvalho Chehab /* Get Signal strength */ 41126ef06e78SMauro Carvalho Chehab dib8000_read_signal_strength(fe, &strength); 411342ff76bdSMauro Carvalho Chehab val = strength; 411442ff76bdSMauro Carvalho Chehab db = interpolate_value(val, 411542ff76bdSMauro Carvalho Chehab strength_to_db_table, 411642ff76bdSMauro Carvalho Chehab ARRAY_SIZE(strength_to_db_table)) - 131000; 411742ff76bdSMauro Carvalho Chehab c->strength.stat[0].svalue = db; 41186ef06e78SMauro Carvalho Chehab 4119704f01bbSMauro Carvalho Chehab /* UCB/BER/CNR measures require lock */ 4120704f01bbSMauro Carvalho Chehab if (!(stat & FE_HAS_LOCK)) { 4121704f01bbSMauro Carvalho Chehab c->cnr.len = 1; 41220400c535SMauro Carvalho Chehab c->block_count.len = 1; 4123704f01bbSMauro Carvalho Chehab c->block_error.len = 1; 4124704f01bbSMauro Carvalho Chehab c->post_bit_error.len = 1; 4125704f01bbSMauro Carvalho Chehab c->post_bit_count.len = 1; 4126704f01bbSMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4127704f01bbSMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4128704f01bbSMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4129704f01bbSMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 41300400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 41316ef06e78SMauro Carvalho Chehab return 0; 4132704f01bbSMauro Carvalho Chehab } 4133704f01bbSMauro Carvalho Chehab 4134704f01bbSMauro Carvalho Chehab /* Check if time for stats was elapsed */ 41350400c535SMauro Carvalho Chehab if (time_after(jiffies, state->per_jiffies_stats)) { 41360400c535SMauro Carvalho Chehab state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000); 41376ef06e78SMauro Carvalho Chehab 41386ef06e78SMauro Carvalho Chehab /* Get SNR */ 41396ef06e78SMauro Carvalho Chehab snr = dib8000_get_snr(fe); 41406ef06e78SMauro Carvalho Chehab for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) { 41416ef06e78SMauro Carvalho Chehab if (state->fe[i]) 41426ef06e78SMauro Carvalho Chehab snr += dib8000_get_snr(state->fe[i]); 41436ef06e78SMauro Carvalho Chehab } 41446ef06e78SMauro Carvalho Chehab snr = snr >> 16; 41456ef06e78SMauro Carvalho Chehab 41466ef06e78SMauro Carvalho Chehab if (snr) { 41476ef06e78SMauro Carvalho Chehab snr = 10 * intlog10(snr); 41486ef06e78SMauro Carvalho Chehab snr = (1000L * snr) >> 24; 41496ef06e78SMauro Carvalho Chehab } else { 41506ef06e78SMauro Carvalho Chehab snr = 0; 41516ef06e78SMauro Carvalho Chehab } 41526ef06e78SMauro Carvalho Chehab c->cnr.stat[0].svalue = snr; 41536ef06e78SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 41546ef06e78SMauro Carvalho Chehab 41550400c535SMauro Carvalho Chehab /* Get UCB measures */ 41560400c535SMauro Carvalho Chehab dib8000_read_unc_blocks(fe, &val); 41570400c535SMauro Carvalho Chehab if (val < state->init_ucb) 41585dc8526bSMauro Carvalho Chehab state->init_ucb += 0x100000000LL; 41590400c535SMauro Carvalho Chehab 41600400c535SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_COUNTER; 41610400c535SMauro Carvalho Chehab c->block_error.stat[0].uvalue = val + state->init_ucb; 41620400c535SMauro Carvalho Chehab 41630400c535SMauro Carvalho Chehab /* Estimate the number of packets based on bitrate */ 41640400c535SMauro Carvalho Chehab if (!time_us) 41650400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, -1); 41660400c535SMauro Carvalho Chehab 41670400c535SMauro Carvalho Chehab if (time_us) { 41685dc8526bSMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL; 41690400c535SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204); 41700400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER; 41710400c535SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks; 41720400c535SMauro Carvalho Chehab } 41730400c535SMauro Carvalho Chehab 41740400c535SMauro Carvalho Chehab show_per_stats = 1; 41750400c535SMauro Carvalho Chehab } 41760400c535SMauro Carvalho Chehab 41770400c535SMauro Carvalho Chehab /* Get post-BER measures */ 41780400c535SMauro Carvalho Chehab if (time_after(jiffies, state->ber_jiffies_stats)) { 41790400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, -1); 41800400c535SMauro Carvalho Chehab state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000); 41810400c535SMauro Carvalho Chehab 41828af16adfSMauro Carvalho Chehab dprintk("Next all layers stats available in %u us.\n", time_us); 41836ef06e78SMauro Carvalho Chehab 41846ef06e78SMauro Carvalho Chehab dib8000_read_ber(fe, &val); 41856ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 41866ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].uvalue += val; 41876ef06e78SMauro Carvalho Chehab 41886ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 41896ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].uvalue += 100000000; 4190704f01bbSMauro Carvalho Chehab } 41916ef06e78SMauro Carvalho Chehab 41926ef06e78SMauro Carvalho Chehab if (state->revision < 0x8002) 41936ef06e78SMauro Carvalho Chehab return 0; 41946ef06e78SMauro Carvalho Chehab 41956ef06e78SMauro Carvalho Chehab c->block_error.len = 4; 41966ef06e78SMauro Carvalho Chehab c->post_bit_error.len = 4; 41976ef06e78SMauro Carvalho Chehab c->post_bit_count.len = 4; 41986ef06e78SMauro Carvalho Chehab 41996ef06e78SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 42000400c535SMauro Carvalho Chehab unsigned nsegs = c->layer[i].segment_count; 42010400c535SMauro Carvalho Chehab 42020400c535SMauro Carvalho Chehab if (nsegs == 0 || nsegs > 13) 4203704f01bbSMauro Carvalho Chehab continue; 4204704f01bbSMauro Carvalho Chehab 42050400c535SMauro Carvalho Chehab time_us = 0; 42060400c535SMauro Carvalho Chehab 42070400c535SMauro Carvalho Chehab if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) { 42080400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, i); 42090400c535SMauro Carvalho Chehab 42100400c535SMauro Carvalho Chehab state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000); 4211704f01bbSMauro Carvalho Chehab dprintk("Next layer %c stats will be available in %u us\n", 4212704f01bbSMauro Carvalho Chehab 'A' + i, time_us); 4213704f01bbSMauro Carvalho Chehab 42146ef06e78SMauro Carvalho Chehab val = dib8000_read_word(state, per_layer_regs[i].ber); 42156ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER; 42166ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[1 + i].uvalue += val; 42176ef06e78SMauro Carvalho Chehab 42186ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER; 42196ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[1 + i].uvalue += 100000000; 42200400c535SMauro Carvalho Chehab } 42216ef06e78SMauro Carvalho Chehab 42220400c535SMauro Carvalho Chehab if (show_per_stats) { 42236ef06e78SMauro Carvalho Chehab val = dib8000_read_word(state, per_layer_regs[i].per); 42246ef06e78SMauro Carvalho Chehab 42256ef06e78SMauro Carvalho Chehab c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER; 42266ef06e78SMauro Carvalho Chehab c->block_error.stat[1 + i].uvalue += val; 42270400c535SMauro Carvalho Chehab 42280400c535SMauro Carvalho Chehab if (!time_us) 42290400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, i); 42300400c535SMauro Carvalho Chehab if (time_us) { 42315dc8526bSMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL; 42320400c535SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204); 42330400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER; 42340400c535SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks; 42350400c535SMauro Carvalho Chehab } 42360400c535SMauro Carvalho Chehab } 42376ef06e78SMauro Carvalho Chehab } 42386ef06e78SMauro Carvalho Chehab return 0; 42396ef06e78SMauro Carvalho Chehab } 42406ef06e78SMauro Carvalho Chehab 4241d44913c1SMauro Carvalho Chehab static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) 42429a0bf528SMauro Carvalho Chehab { 42439a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 42449a0bf528SMauro Carvalho Chehab u8 index_frontend = 1; 42459a0bf528SMauro Carvalho Chehab 42469a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 42479a0bf528SMauro Carvalho Chehab index_frontend++; 42489a0bf528SMauro Carvalho Chehab if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { 42498af16adfSMauro Carvalho Chehab dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend); 42509a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = fe_slave; 42519a0bf528SMauro Carvalho Chehab return 0; 42529a0bf528SMauro Carvalho Chehab } 42539a0bf528SMauro Carvalho Chehab 42548af16adfSMauro Carvalho Chehab dprintk("too many slave frontend\n"); 42559a0bf528SMauro Carvalho Chehab return -ENOMEM; 42569a0bf528SMauro Carvalho Chehab } 42579a0bf528SMauro Carvalho Chehab 4258d44913c1SMauro Carvalho Chehab static int dib8000_remove_slave_frontend(struct dvb_frontend *fe) 42599a0bf528SMauro Carvalho Chehab { 42609a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 42619a0bf528SMauro Carvalho Chehab u8 index_frontend = 1; 42629a0bf528SMauro Carvalho Chehab 42639a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 42649a0bf528SMauro Carvalho Chehab index_frontend++; 42659a0bf528SMauro Carvalho Chehab if (index_frontend != 1) { 42668af16adfSMauro Carvalho Chehab dprintk("remove slave fe %p (index %i)\n", state->fe[index_frontend-1], index_frontend-1); 42679a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = NULL; 42689a0bf528SMauro Carvalho Chehab return 0; 42699a0bf528SMauro Carvalho Chehab } 42709a0bf528SMauro Carvalho Chehab 42718af16adfSMauro Carvalho Chehab dprintk("no frontend to be removed\n"); 42729a0bf528SMauro Carvalho Chehab return -ENODEV; 42739a0bf528SMauro Carvalho Chehab } 42749a0bf528SMauro Carvalho Chehab 4275d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) 42769a0bf528SMauro Carvalho Chehab { 42779a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 42789a0bf528SMauro Carvalho Chehab 42799a0bf528SMauro Carvalho Chehab if (slave_index >= MAX_NUMBER_OF_FRONTENDS) 42809a0bf528SMauro Carvalho Chehab return NULL; 42819a0bf528SMauro Carvalho Chehab return state->fe[slave_index]; 42829a0bf528SMauro Carvalho Chehab } 42839a0bf528SMauro Carvalho Chehab 4284d44913c1SMauro Carvalho Chehab static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, 42859a0bf528SMauro Carvalho Chehab u8 default_addr, u8 first_addr, u8 is_dib8096p) 42869a0bf528SMauro Carvalho Chehab { 42879a0bf528SMauro Carvalho Chehab int k = 0, ret = 0; 42889a0bf528SMauro Carvalho Chehab u8 new_addr = 0; 42899a0bf528SMauro Carvalho Chehab struct i2c_device client = {.adap = host }; 42909a0bf528SMauro Carvalho Chehab 42919a0bf528SMauro Carvalho Chehab client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); 42929a0bf528SMauro Carvalho Chehab if (!client.i2c_write_buffer) { 42938af16adfSMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__); 42949a0bf528SMauro Carvalho Chehab return -ENOMEM; 42959a0bf528SMauro Carvalho Chehab } 42969a0bf528SMauro Carvalho Chehab client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); 42979a0bf528SMauro Carvalho Chehab if (!client.i2c_read_buffer) { 42988af16adfSMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__); 42999a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 43009a0bf528SMauro Carvalho Chehab goto error_memory_read; 43019a0bf528SMauro Carvalho Chehab } 43029a0bf528SMauro Carvalho Chehab client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); 43039a0bf528SMauro Carvalho Chehab if (!client.i2c_buffer_lock) { 43048af16adfSMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__); 43059a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 43069a0bf528SMauro Carvalho Chehab goto error_memory_lock; 43079a0bf528SMauro Carvalho Chehab } 43089a0bf528SMauro Carvalho Chehab mutex_init(client.i2c_buffer_lock); 43099a0bf528SMauro Carvalho Chehab 43109a0bf528SMauro Carvalho Chehab for (k = no_of_demods - 1; k >= 0; k--) { 43119a0bf528SMauro Carvalho Chehab /* designated i2c address */ 43129a0bf528SMauro Carvalho Chehab new_addr = first_addr + (k << 1); 43139a0bf528SMauro Carvalho Chehab 43149a0bf528SMauro Carvalho Chehab client.addr = new_addr; 43159a0bf528SMauro Carvalho Chehab if (!is_dib8096p) 43169a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ 43179a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) { 43189a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */ 43199a0bf528SMauro Carvalho Chehab if (!is_dib8096p) 43209a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003); 43219a0bf528SMauro Carvalho Chehab client.addr = default_addr; 43229a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) { 43238af16adfSMauro Carvalho Chehab dprintk("#%d: not identified\n", k); 43249a0bf528SMauro Carvalho Chehab ret = -EINVAL; 43259a0bf528SMauro Carvalho Chehab goto error; 43269a0bf528SMauro Carvalho Chehab } 43279a0bf528SMauro Carvalho Chehab } 43289a0bf528SMauro Carvalho Chehab 43299a0bf528SMauro Carvalho Chehab /* start diversity to pull_down div_str - just for i2c-enumeration */ 43309a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6)); 43319a0bf528SMauro Carvalho Chehab 43329a0bf528SMauro Carvalho Chehab /* set new i2c address and force divstart */ 43339a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2); 43349a0bf528SMauro Carvalho Chehab client.addr = new_addr; 43359a0bf528SMauro Carvalho Chehab dib8000_identify(&client); 43369a0bf528SMauro Carvalho Chehab 43378af16adfSMauro Carvalho Chehab dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); 43389a0bf528SMauro Carvalho Chehab } 43399a0bf528SMauro Carvalho Chehab 43409a0bf528SMauro Carvalho Chehab for (k = 0; k < no_of_demods; k++) { 43419a0bf528SMauro Carvalho Chehab new_addr = first_addr | (k << 1); 43429a0bf528SMauro Carvalho Chehab client.addr = new_addr; 43439a0bf528SMauro Carvalho Chehab 43449a0bf528SMauro Carvalho Chehab // unforce divstr 43459a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, new_addr << 2); 43469a0bf528SMauro Carvalho Chehab 43479a0bf528SMauro Carvalho Chehab /* deactivate div - it was just for i2c-enumeration */ 43489a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, 0); 43499a0bf528SMauro Carvalho Chehab } 43509a0bf528SMauro Carvalho Chehab 43519a0bf528SMauro Carvalho Chehab error: 43529a0bf528SMauro Carvalho Chehab kfree(client.i2c_buffer_lock); 43539a0bf528SMauro Carvalho Chehab error_memory_lock: 43549a0bf528SMauro Carvalho Chehab kfree(client.i2c_read_buffer); 43559a0bf528SMauro Carvalho Chehab error_memory_read: 43569a0bf528SMauro Carvalho Chehab kfree(client.i2c_write_buffer); 43579a0bf528SMauro Carvalho Chehab 43589a0bf528SMauro Carvalho Chehab return ret; 43599a0bf528SMauro Carvalho Chehab } 43609a0bf528SMauro Carvalho Chehab 43619a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) 43629a0bf528SMauro Carvalho Chehab { 43639a0bf528SMauro Carvalho Chehab tune->min_delay_ms = 1000; 43649a0bf528SMauro Carvalho Chehab tune->step_size = 0; 43659a0bf528SMauro Carvalho Chehab tune->max_drift = 0; 43669a0bf528SMauro Carvalho Chehab return 0; 43679a0bf528SMauro Carvalho Chehab } 43689a0bf528SMauro Carvalho Chehab 43699a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe) 43709a0bf528SMauro Carvalho Chehab { 43719a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 43729a0bf528SMauro Carvalho Chehab u8 index_frontend; 43739a0bf528SMauro Carvalho Chehab 43749a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) 43759a0bf528SMauro Carvalho Chehab dvb_frontend_detach(st->fe[index_frontend]); 43769a0bf528SMauro Carvalho Chehab 43779a0bf528SMauro Carvalho Chehab dibx000_exit_i2c_master(&st->i2c_master); 43789a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->dib8096p_tuner_adap); 43799a0bf528SMauro Carvalho Chehab kfree(st->fe[0]); 43809a0bf528SMauro Carvalho Chehab kfree(st); 43819a0bf528SMauro Carvalho Chehab } 43829a0bf528SMauro Carvalho Chehab 4383d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) 43849a0bf528SMauro Carvalho Chehab { 43859a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 43869a0bf528SMauro Carvalho Chehab return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); 43879a0bf528SMauro Carvalho Chehab } 43889a0bf528SMauro Carvalho Chehab 4389d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) 43909a0bf528SMauro Carvalho Chehab { 43919a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 43929a0bf528SMauro Carvalho Chehab u16 val = dib8000_read_word(st, 299) & 0xffef; 43939a0bf528SMauro Carvalho Chehab val |= (onoff & 0x1) << 4; 43949a0bf528SMauro Carvalho Chehab 43958af16adfSMauro Carvalho Chehab dprintk("pid filter enabled %d\n", onoff); 43969a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 299, val); 43979a0bf528SMauro Carvalho Chehab } 43989a0bf528SMauro Carvalho Chehab 4399d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) 44009a0bf528SMauro Carvalho Chehab { 44019a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 44028af16adfSMauro Carvalho Chehab dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff); 44039a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); 44049a0bf528SMauro Carvalho Chehab } 44059a0bf528SMauro Carvalho Chehab 44069a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = { 44079a0bf528SMauro Carvalho Chehab .delsys = { SYS_ISDBT }, 44089a0bf528SMauro Carvalho Chehab .info = { 44099a0bf528SMauro Carvalho Chehab .name = "DiBcom 8000 ISDB-T", 44109a0bf528SMauro Carvalho Chehab .frequency_min = 44250000, 44119a0bf528SMauro Carvalho Chehab .frequency_max = 867250000, 44129a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 44139a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | 44149a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 44159a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 44169a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 44179a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, 44189a0bf528SMauro Carvalho Chehab }, 44199a0bf528SMauro Carvalho Chehab 44209a0bf528SMauro Carvalho Chehab .release = dib8000_release, 44219a0bf528SMauro Carvalho Chehab 44229a0bf528SMauro Carvalho Chehab .init = dib8000_wakeup, 44239a0bf528SMauro Carvalho Chehab .sleep = dib8000_sleep, 44249a0bf528SMauro Carvalho Chehab 44259a0bf528SMauro Carvalho Chehab .set_frontend = dib8000_set_frontend, 44269a0bf528SMauro Carvalho Chehab .get_tune_settings = dib8000_fe_get_tune_settings, 44279a0bf528SMauro Carvalho Chehab .get_frontend = dib8000_get_frontend, 44289a0bf528SMauro Carvalho Chehab 44299a0bf528SMauro Carvalho Chehab .read_status = dib8000_read_status, 44309a0bf528SMauro Carvalho Chehab .read_ber = dib8000_read_ber, 44319a0bf528SMauro Carvalho Chehab .read_signal_strength = dib8000_read_signal_strength, 44329a0bf528SMauro Carvalho Chehab .read_snr = dib8000_read_snr, 44339a0bf528SMauro Carvalho Chehab .read_ucblocks = dib8000_read_unc_blocks, 44349a0bf528SMauro Carvalho Chehab }; 44359a0bf528SMauro Carvalho Chehab 4436d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) 44379a0bf528SMauro Carvalho Chehab { 44389a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe; 44399a0bf528SMauro Carvalho Chehab struct dib8000_state *state; 44409a0bf528SMauro Carvalho Chehab 44418af16adfSMauro Carvalho Chehab dprintk("dib8000_init\n"); 44429a0bf528SMauro Carvalho Chehab 44439a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); 44449a0bf528SMauro Carvalho Chehab if (state == NULL) 44459a0bf528SMauro Carvalho Chehab return NULL; 44469a0bf528SMauro Carvalho Chehab fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); 44479a0bf528SMauro Carvalho Chehab if (fe == NULL) 44489a0bf528SMauro Carvalho Chehab goto error; 44499a0bf528SMauro Carvalho Chehab 44509a0bf528SMauro Carvalho Chehab memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); 44519a0bf528SMauro Carvalho Chehab state->i2c.adap = i2c_adap; 44529a0bf528SMauro Carvalho Chehab state->i2c.addr = i2c_addr; 44539a0bf528SMauro Carvalho Chehab state->i2c.i2c_write_buffer = state->i2c_write_buffer; 44549a0bf528SMauro Carvalho Chehab state->i2c.i2c_read_buffer = state->i2c_read_buffer; 44559a0bf528SMauro Carvalho Chehab mutex_init(&state->i2c_buffer_lock); 44569a0bf528SMauro Carvalho Chehab state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock; 44579a0bf528SMauro Carvalho Chehab state->gpio_val = cfg->gpio_val; 44589a0bf528SMauro Carvalho Chehab state->gpio_dir = cfg->gpio_dir; 44599a0bf528SMauro Carvalho Chehab 44609a0bf528SMauro Carvalho Chehab /* Ensure the output mode remains at the previous default if it's 44619a0bf528SMauro Carvalho Chehab * not specifically set by the caller. 44629a0bf528SMauro Carvalho Chehab */ 44639a0bf528SMauro Carvalho Chehab if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) 44649a0bf528SMauro Carvalho Chehab state->cfg.output_mode = OUTMODE_MPEG2_FIFO; 44659a0bf528SMauro Carvalho Chehab 44669a0bf528SMauro Carvalho Chehab state->fe[0] = fe; 44679a0bf528SMauro Carvalho Chehab fe->demodulator_priv = state; 44689a0bf528SMauro Carvalho Chehab memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); 44699a0bf528SMauro Carvalho Chehab 44709a0bf528SMauro Carvalho Chehab state->timf_default = cfg->pll->timf; 44719a0bf528SMauro Carvalho Chehab 44729a0bf528SMauro Carvalho Chehab if (dib8000_identify(&state->i2c) == 0) 44739a0bf528SMauro Carvalho Chehab goto error; 44749a0bf528SMauro Carvalho Chehab 44759a0bf528SMauro Carvalho Chehab dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); 44769a0bf528SMauro Carvalho Chehab 44779a0bf528SMauro Carvalho Chehab /* init 8096p tuner adapter */ 44789a0bf528SMauro Carvalho Chehab strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", 44799a0bf528SMauro Carvalho Chehab sizeof(state->dib8096p_tuner_adap.name)); 44809a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo; 44819a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo_data = NULL; 44829a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent; 44839a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&state->dib8096p_tuner_adap, state); 44849a0bf528SMauro Carvalho Chehab i2c_add_adapter(&state->dib8096p_tuner_adap); 44859a0bf528SMauro Carvalho Chehab 44869a0bf528SMauro Carvalho Chehab dib8000_reset(fe); 44879a0bf528SMauro Carvalho Chehab 44889a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ 4489173a64cbSPatrick Boettcher state->current_demod_bw = 6000; 44909a0bf528SMauro Carvalho Chehab 44919a0bf528SMauro Carvalho Chehab return fe; 44929a0bf528SMauro Carvalho Chehab 44939a0bf528SMauro Carvalho Chehab error: 44949a0bf528SMauro Carvalho Chehab kfree(state); 44959a0bf528SMauro Carvalho Chehab return NULL; 44969a0bf528SMauro Carvalho Chehab } 44979a0bf528SMauro Carvalho Chehab 4498d44913c1SMauro Carvalho Chehab void *dib8000_attach(struct dib8000_ops *ops) 4499d44913c1SMauro Carvalho Chehab { 4500d44913c1SMauro Carvalho Chehab if (!ops) 4501d44913c1SMauro Carvalho Chehab return NULL; 4502d44913c1SMauro Carvalho Chehab 4503d44913c1SMauro Carvalho Chehab ops->pwm_agc_reset = dib8000_pwm_agc_reset; 4504d44913c1SMauro Carvalho Chehab ops->get_dc_power = dib8090p_get_dc_power; 4505d44913c1SMauro Carvalho Chehab ops->set_gpio = dib8000_set_gpio; 4506d44913c1SMauro Carvalho Chehab ops->get_slave_frontend = dib8000_get_slave_frontend; 4507d44913c1SMauro Carvalho Chehab ops->set_tune_state = dib8000_set_tune_state; 4508d44913c1SMauro Carvalho Chehab ops->pid_filter_ctrl = dib8000_pid_filter_ctrl; 4509d44913c1SMauro Carvalho Chehab ops->remove_slave_frontend = dib8000_remove_slave_frontend; 4510d44913c1SMauro Carvalho Chehab ops->get_adc_power = dib8000_get_adc_power; 4511d44913c1SMauro Carvalho Chehab ops->update_pll = dib8000_update_pll; 4512d44913c1SMauro Carvalho Chehab ops->tuner_sleep = dib8096p_tuner_sleep; 4513d44913c1SMauro Carvalho Chehab ops->get_tune_state = dib8000_get_tune_state; 4514d44913c1SMauro Carvalho Chehab ops->get_i2c_tuner = dib8096p_get_i2c_tuner; 4515d44913c1SMauro Carvalho Chehab ops->set_slave_frontend = dib8000_set_slave_frontend; 4516d44913c1SMauro Carvalho Chehab ops->pid_filter = dib8000_pid_filter; 4517d44913c1SMauro Carvalho Chehab ops->ctrl_timf = dib8000_ctrl_timf; 4518d44913c1SMauro Carvalho Chehab ops->init = dib8000_init; 4519d44913c1SMauro Carvalho Chehab ops->get_i2c_master = dib8000_get_i2c_master; 4520d44913c1SMauro Carvalho Chehab ops->i2c_enumeration = dib8000_i2c_enumeration; 4521d44913c1SMauro Carvalho Chehab ops->set_wbd_ref = dib8000_set_wbd_ref; 4522d44913c1SMauro Carvalho Chehab 4523d44913c1SMauro Carvalho Chehab return ops; 4524d44913c1SMauro Carvalho Chehab } 4525d44913c1SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_attach); 45269a0bf528SMauro Carvalho Chehab 452799e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>"); 45289a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator"); 45299a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 4530