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 */ 109a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 119a0bf528SMauro Carvalho Chehab #include <linux/slab.h> 129a0bf528SMauro Carvalho Chehab #include <linux/i2c.h> 139a0bf528SMauro Carvalho Chehab #include <linux/mutex.h> 14b4600d70SMauro Carvalho Chehab #include <asm/div64.h> 159a0bf528SMauro Carvalho Chehab 169a0bf528SMauro Carvalho Chehab #include "dvb_math.h" 179a0bf528SMauro Carvalho Chehab 189a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 199a0bf528SMauro Carvalho Chehab 209a0bf528SMauro Carvalho Chehab #include "dib8000.h" 219a0bf528SMauro Carvalho Chehab 229a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1 239a0bf528SMauro Carvalho Chehab #define LAYER_A 1 249a0bf528SMauro Carvalho Chehab #define LAYER_B 2 259a0bf528SMauro Carvalho Chehab #define LAYER_C 3 269a0bf528SMauro Carvalho Chehab 279a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6 28173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */ 299a0bf528SMauro Carvalho Chehab 309a0bf528SMauro Carvalho Chehab static int debug; 319a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 329a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 339a0bf528SMauro Carvalho Chehab 349a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) 359a0bf528SMauro Carvalho Chehab 369a0bf528SMauro Carvalho Chehab struct i2c_device { 379a0bf528SMauro Carvalho Chehab struct i2c_adapter *adap; 389a0bf528SMauro Carvalho Chehab u8 addr; 399a0bf528SMauro Carvalho Chehab u8 *i2c_write_buffer; 409a0bf528SMauro Carvalho Chehab u8 *i2c_read_buffer; 419a0bf528SMauro Carvalho Chehab struct mutex *i2c_buffer_lock; 429a0bf528SMauro Carvalho Chehab }; 439a0bf528SMauro Carvalho Chehab 44173a64cbSPatrick Boettcher enum param_loop_step { 45173a64cbSPatrick Boettcher LOOP_TUNE_1, 46173a64cbSPatrick Boettcher LOOP_TUNE_2 47173a64cbSPatrick Boettcher }; 48173a64cbSPatrick Boettcher 49173a64cbSPatrick Boettcher enum dib8000_autosearch_step { 50173a64cbSPatrick Boettcher AS_START = 0, 51173a64cbSPatrick Boettcher AS_SEARCHING_FFT, 52173a64cbSPatrick Boettcher AS_SEARCHING_GUARD, 53173a64cbSPatrick Boettcher AS_DONE = 100, 54173a64cbSPatrick Boettcher }; 55173a64cbSPatrick Boettcher 56173a64cbSPatrick Boettcher enum timeout_mode { 57173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_OFF = 0, 58173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_ON, 59173a64cbSPatrick Boettcher }; 60173a64cbSPatrick Boettcher 619a0bf528SMauro Carvalho Chehab struct dib8000_state { 629a0bf528SMauro Carvalho Chehab struct dib8000_config cfg; 639a0bf528SMauro Carvalho Chehab 649a0bf528SMauro Carvalho Chehab struct i2c_device i2c; 659a0bf528SMauro Carvalho Chehab 669a0bf528SMauro Carvalho Chehab struct dibx000_i2c_master i2c_master; 679a0bf528SMauro Carvalho Chehab 689a0bf528SMauro Carvalho Chehab u16 wbd_ref; 699a0bf528SMauro Carvalho Chehab 709a0bf528SMauro Carvalho Chehab u8 current_band; 719a0bf528SMauro Carvalho Chehab u32 current_bandwidth; 729a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *current_agc; 739a0bf528SMauro Carvalho Chehab u32 timf; 749a0bf528SMauro Carvalho Chehab u32 timf_default; 759a0bf528SMauro Carvalho Chehab 769a0bf528SMauro Carvalho Chehab u8 div_force_off:1; 779a0bf528SMauro Carvalho Chehab u8 div_state:1; 789a0bf528SMauro Carvalho Chehab u16 div_sync_wait; 799a0bf528SMauro Carvalho Chehab 809a0bf528SMauro Carvalho Chehab u8 agc_state; 819a0bf528SMauro Carvalho Chehab u8 differential_constellation; 829a0bf528SMauro Carvalho Chehab u8 diversity_onoff; 839a0bf528SMauro Carvalho Chehab 849a0bf528SMauro Carvalho Chehab s16 ber_monitored_layer; 859a0bf528SMauro Carvalho Chehab u16 gpio_dir; 869a0bf528SMauro Carvalho Chehab u16 gpio_val; 879a0bf528SMauro Carvalho Chehab 889a0bf528SMauro Carvalho Chehab u16 revision; 899a0bf528SMauro Carvalho Chehab u8 isdbt_cfg_loaded; 909a0bf528SMauro Carvalho Chehab enum frontend_tune_state tune_state; 91173a64cbSPatrick Boettcher s32 status; 929a0bf528SMauro Carvalho Chehab 939a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; 949a0bf528SMauro Carvalho Chehab 959a0bf528SMauro Carvalho Chehab /* for the I2C transfer */ 969a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2]; 979a0bf528SMauro Carvalho Chehab u8 i2c_write_buffer[4]; 989a0bf528SMauro Carvalho Chehab u8 i2c_read_buffer[2]; 999a0bf528SMauro Carvalho Chehab struct mutex i2c_buffer_lock; 1009a0bf528SMauro Carvalho Chehab u8 input_mode_mpeg; 1019a0bf528SMauro Carvalho Chehab 1029a0bf528SMauro Carvalho Chehab u16 tuner_enable; 1039a0bf528SMauro Carvalho Chehab struct i2c_adapter dib8096p_tuner_adap; 104173a64cbSPatrick Boettcher u16 current_demod_bw; 105173a64cbSPatrick Boettcher 106173a64cbSPatrick Boettcher u16 seg_mask; 107173a64cbSPatrick Boettcher u16 seg_diff_mask; 108173a64cbSPatrick Boettcher u16 mode; 109173a64cbSPatrick Boettcher u8 layer_b_nb_seg; 110173a64cbSPatrick Boettcher u8 layer_c_nb_seg; 111173a64cbSPatrick Boettcher 112173a64cbSPatrick Boettcher u8 channel_parameters_set; 113173a64cbSPatrick Boettcher u16 autosearch_state; 114173a64cbSPatrick Boettcher u16 found_nfft; 115173a64cbSPatrick Boettcher u16 found_guard; 116173a64cbSPatrick Boettcher u8 subchannel; 117173a64cbSPatrick Boettcher u8 symbol_duration; 118173a64cbSPatrick Boettcher u32 timeout; 119173a64cbSPatrick Boettcher u8 longest_intlv_layer; 120173a64cbSPatrick Boettcher u16 output_mode; 121173a64cbSPatrick Boettcher 122704f01bbSMauro Carvalho Chehab /* for DVBv5 stats */ 1237a9d85d5SMauro Carvalho Chehab s64 init_ucb; 1240400c535SMauro Carvalho Chehab unsigned long per_jiffies_stats; 1250400c535SMauro Carvalho Chehab unsigned long ber_jiffies_stats; 1260400c535SMauro Carvalho Chehab unsigned long ber_jiffies_stats_layer[3]; 127704f01bbSMauro Carvalho Chehab 128173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 129173a64cbSPatrick Boettcher u16 agc1_max; 130173a64cbSPatrick Boettcher u16 agc1_min; 131173a64cbSPatrick Boettcher u16 agc2_max; 132173a64cbSPatrick Boettcher u16 agc2_min; 133173a64cbSPatrick Boettcher #endif 1349a0bf528SMauro Carvalho Chehab }; 1359a0bf528SMauro Carvalho Chehab 1369a0bf528SMauro Carvalho Chehab enum dib8000_power_mode { 1379a0bf528SMauro Carvalho Chehab DIB8000_POWER_ALL = 0, 1389a0bf528SMauro Carvalho Chehab DIB8000_POWER_INTERFACE_ONLY, 1399a0bf528SMauro Carvalho Chehab }; 1409a0bf528SMauro Carvalho Chehab 1419a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) 1429a0bf528SMauro Carvalho Chehab { 1439a0bf528SMauro Carvalho Chehab u16 ret; 1449a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2] = { 1459a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = 0, .len = 2}, 1469a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2}, 1479a0bf528SMauro Carvalho Chehab }; 1489a0bf528SMauro Carvalho Chehab 1499a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { 1509a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 1519a0bf528SMauro Carvalho Chehab return 0; 1529a0bf528SMauro Carvalho Chehab } 1539a0bf528SMauro Carvalho Chehab 1549a0bf528SMauro Carvalho Chehab msg[0].buf = i2c->i2c_write_buffer; 1559a0bf528SMauro Carvalho Chehab msg[0].buf[0] = reg >> 8; 1569a0bf528SMauro Carvalho Chehab msg[0].buf[1] = reg & 0xff; 1579a0bf528SMauro Carvalho Chehab msg[1].buf = i2c->i2c_read_buffer; 1589a0bf528SMauro Carvalho Chehab 1599a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c->adap, msg, 2) != 2) 1609a0bf528SMauro Carvalho Chehab dprintk("i2c read error on %d", reg); 1619a0bf528SMauro Carvalho Chehab 1629a0bf528SMauro Carvalho Chehab ret = (msg[1].buf[0] << 8) | msg[1].buf[1]; 1639a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock); 1649a0bf528SMauro Carvalho Chehab return ret; 1659a0bf528SMauro Carvalho Chehab } 1669a0bf528SMauro Carvalho Chehab 1675ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg) 1689a0bf528SMauro Carvalho Chehab { 1699a0bf528SMauro Carvalho Chehab u16 ret; 1709a0bf528SMauro Carvalho Chehab 1719a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = reg >> 8; 1729a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 1739a0bf528SMauro Carvalho Chehab 1749a0bf528SMauro Carvalho Chehab memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 1759a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1; 1769a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 1779a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 1789a0bf528SMauro Carvalho Chehab state->msg[0].len = 2; 1799a0bf528SMauro Carvalho Chehab state->msg[1].addr = state->i2c.addr >> 1; 1809a0bf528SMauro Carvalho Chehab state->msg[1].flags = I2C_M_RD; 1819a0bf528SMauro Carvalho Chehab state->msg[1].buf = state->i2c_read_buffer; 1829a0bf528SMauro Carvalho Chehab state->msg[1].len = 2; 1839a0bf528SMauro Carvalho Chehab 1849a0bf528SMauro Carvalho Chehab if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) 1859a0bf528SMauro Carvalho Chehab dprintk("i2c read error on %d", reg); 1869a0bf528SMauro Carvalho Chehab 1879a0bf528SMauro Carvalho Chehab ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 1885ac64ba1SMauro Carvalho Chehab 1895ac64ba1SMauro Carvalho Chehab return ret; 1905ac64ba1SMauro Carvalho Chehab } 1915ac64ba1SMauro Carvalho Chehab 1925ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) 1935ac64ba1SMauro Carvalho Chehab { 1945ac64ba1SMauro Carvalho Chehab u16 ret; 1955ac64ba1SMauro Carvalho Chehab 1965ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 1975ac64ba1SMauro Carvalho Chehab dprintk("could not acquire lock"); 1985ac64ba1SMauro Carvalho Chehab return 0; 1995ac64ba1SMauro Carvalho Chehab } 2005ac64ba1SMauro Carvalho Chehab 2015ac64ba1SMauro Carvalho Chehab ret = __dib8000_read_word(state, reg); 2025ac64ba1SMauro Carvalho Chehab 2039a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2049a0bf528SMauro Carvalho Chehab 2059a0bf528SMauro Carvalho Chehab return ret; 2069a0bf528SMauro Carvalho Chehab } 2079a0bf528SMauro Carvalho Chehab 2089a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg) 2099a0bf528SMauro Carvalho Chehab { 2109a0bf528SMauro Carvalho Chehab u16 rw[2]; 2119a0bf528SMauro Carvalho Chehab 2125ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 2135ac64ba1SMauro Carvalho Chehab dprintk("could not acquire lock"); 2145ac64ba1SMauro Carvalho Chehab return 0; 2155ac64ba1SMauro Carvalho Chehab } 2165ac64ba1SMauro Carvalho Chehab 2175ac64ba1SMauro Carvalho Chehab rw[0] = __dib8000_read_word(state, reg + 0); 2185ac64ba1SMauro Carvalho Chehab rw[1] = __dib8000_read_word(state, reg + 1); 2195ac64ba1SMauro Carvalho Chehab 2205ac64ba1SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2219a0bf528SMauro Carvalho Chehab 2229a0bf528SMauro Carvalho Chehab return ((rw[0] << 16) | (rw[1])); 2239a0bf528SMauro Carvalho Chehab } 2249a0bf528SMauro Carvalho Chehab 2259a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) 2269a0bf528SMauro Carvalho Chehab { 2279a0bf528SMauro Carvalho Chehab struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4}; 2289a0bf528SMauro Carvalho Chehab int ret = 0; 2299a0bf528SMauro Carvalho Chehab 2309a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { 2319a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 2329a0bf528SMauro Carvalho Chehab return -EINVAL; 2339a0bf528SMauro Carvalho Chehab } 2349a0bf528SMauro Carvalho Chehab 2359a0bf528SMauro Carvalho Chehab msg.buf = i2c->i2c_write_buffer; 2369a0bf528SMauro Carvalho Chehab msg.buf[0] = (reg >> 8) & 0xff; 2379a0bf528SMauro Carvalho Chehab msg.buf[1] = reg & 0xff; 2389a0bf528SMauro Carvalho Chehab msg.buf[2] = (val >> 8) & 0xff; 2399a0bf528SMauro Carvalho Chehab msg.buf[3] = val & 0xff; 2409a0bf528SMauro Carvalho Chehab 2419a0bf528SMauro Carvalho Chehab ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; 2429a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock); 2439a0bf528SMauro Carvalho Chehab 2449a0bf528SMauro Carvalho Chehab return ret; 2459a0bf528SMauro Carvalho Chehab } 2469a0bf528SMauro Carvalho Chehab 2479a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) 2489a0bf528SMauro Carvalho Chehab { 2499a0bf528SMauro Carvalho Chehab int ret; 2509a0bf528SMauro Carvalho Chehab 2519a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 2529a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 2539a0bf528SMauro Carvalho Chehab return -EINVAL; 2549a0bf528SMauro Carvalho Chehab } 2559a0bf528SMauro Carvalho Chehab 2569a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = (reg >> 8) & 0xff; 2579a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 2589a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[2] = (val >> 8) & 0xff; 2599a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[3] = val & 0xff; 2609a0bf528SMauro Carvalho Chehab 2619a0bf528SMauro Carvalho Chehab memset(&state->msg[0], 0, sizeof(struct i2c_msg)); 2629a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1; 2639a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 2649a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 2659a0bf528SMauro Carvalho Chehab state->msg[0].len = 4; 2669a0bf528SMauro Carvalho Chehab 2679a0bf528SMauro Carvalho Chehab ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? 2689a0bf528SMauro Carvalho Chehab -EREMOTEIO : 0); 2699a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2709a0bf528SMauro Carvalho Chehab 2719a0bf528SMauro Carvalho Chehab return ret; 2729a0bf528SMauro Carvalho Chehab } 2739a0bf528SMauro Carvalho Chehab 2749a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = { 2759a0bf528SMauro Carvalho Chehab (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, 2769a0bf528SMauro Carvalho Chehab (920 << 5) | 0x09 2779a0bf528SMauro Carvalho Chehab }; 2789a0bf528SMauro Carvalho Chehab 2799a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = { 2809a0bf528SMauro Carvalho Chehab (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f 2819a0bf528SMauro Carvalho Chehab }; 2829a0bf528SMauro Carvalho Chehab 2839a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { 2849a0bf528SMauro Carvalho Chehab (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, 2859a0bf528SMauro Carvalho Chehab (-931 << 5) | 0x0f 2869a0bf528SMauro Carvalho Chehab }; 2879a0bf528SMauro Carvalho Chehab 2889a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = { 2899a0bf528SMauro Carvalho Chehab (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, 2909a0bf528SMauro Carvalho Chehab (982 << 5) | 0x0c 2919a0bf528SMauro Carvalho Chehab }; 2929a0bf528SMauro Carvalho Chehab 2939a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = { 2949a0bf528SMauro Carvalho Chehab (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, 2959a0bf528SMauro Carvalho Chehab (-720 << 5) | 0x0d 2969a0bf528SMauro Carvalho Chehab }; 2979a0bf528SMauro Carvalho Chehab 2989a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = { 2999a0bf528SMauro Carvalho Chehab (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, 3009a0bf528SMauro Carvalho Chehab (-610 << 5) | 0x0a 3019a0bf528SMauro Carvalho Chehab }; 3029a0bf528SMauro Carvalho Chehab 3039a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = { 3049a0bf528SMauro Carvalho Chehab (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, 3059a0bf528SMauro Carvalho Chehab (-922 << 5) | 0x0d 3069a0bf528SMauro Carvalho Chehab }; 3079a0bf528SMauro Carvalho Chehab 3089a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = { 3099a0bf528SMauro Carvalho Chehab (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, 3109a0bf528SMauro Carvalho Chehab (-655 << 5) | 0x0a 3119a0bf528SMauro Carvalho Chehab }; 3129a0bf528SMauro Carvalho Chehab 3139a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { 3149a0bf528SMauro Carvalho Chehab (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, 3159a0bf528SMauro Carvalho Chehab (-958 << 5) | 0x13 3169a0bf528SMauro Carvalho Chehab }; 3179a0bf528SMauro Carvalho Chehab 3189a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = { 3199a0bf528SMauro Carvalho Chehab (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, 3209a0bf528SMauro Carvalho Chehab (-568 << 5) | 0x0f 3219a0bf528SMauro Carvalho Chehab }; 3229a0bf528SMauro Carvalho Chehab 3239a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = { 3249a0bf528SMauro Carvalho Chehab (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, 3259a0bf528SMauro Carvalho Chehab (-848 << 5) | 0x13 3269a0bf528SMauro Carvalho Chehab }; 3279a0bf528SMauro Carvalho Chehab 3289a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = { 3299a0bf528SMauro Carvalho Chehab (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, 3309a0bf528SMauro Carvalho Chehab (-869 << 5) | 0x13 3319a0bf528SMauro Carvalho Chehab }; 3329a0bf528SMauro Carvalho Chehab 3339a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = { 3349a0bf528SMauro Carvalho Chehab (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, 3359a0bf528SMauro Carvalho Chehab (-598 << 5) | 0x10 3369a0bf528SMauro Carvalho Chehab }; 3379a0bf528SMauro Carvalho Chehab 3389a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = { 3399a0bf528SMauro Carvalho Chehab (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, 3409a0bf528SMauro Carvalho Chehab (585 << 5) | 0x0f 3419a0bf528SMauro Carvalho Chehab }; 3429a0bf528SMauro Carvalho Chehab 3439a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { 3449a0bf528SMauro Carvalho Chehab (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, 3459a0bf528SMauro Carvalho Chehab (0 << 5) | 0x14 3469a0bf528SMauro Carvalho Chehab }; 3479a0bf528SMauro Carvalho Chehab 3489a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = { 3499a0bf528SMauro Carvalho Chehab (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, 3509a0bf528SMauro Carvalho Chehab (-877 << 5) | 0x15 3519a0bf528SMauro Carvalho Chehab }; 3529a0bf528SMauro Carvalho Chehab 3539a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = { 3549a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, 3559a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x14 3569a0bf528SMauro Carvalho Chehab }; 3579a0bf528SMauro Carvalho Chehab 3589a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = { 3599a0bf528SMauro Carvalho Chehab (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, 3609a0bf528SMauro Carvalho Chehab (690 << 5) | 0x14 3619a0bf528SMauro Carvalho Chehab }; 3629a0bf528SMauro Carvalho Chehab 3639a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = { 3649a0bf528SMauro 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 3659a0bf528SMauro Carvalho Chehab }; 3669a0bf528SMauro Carvalho Chehab 3679a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = { 3689a0bf528SMauro 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 3699a0bf528SMauro Carvalho Chehab }; 3709a0bf528SMauro Carvalho Chehab 3719a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = { 3729a0bf528SMauro 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 3739a0bf528SMauro Carvalho Chehab }; 3749a0bf528SMauro Carvalho Chehab 3759a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state) 3769a0bf528SMauro Carvalho Chehab { 3779a0bf528SMauro Carvalho Chehab u16 mode; 3789a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) { 3799a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 3809a0bf528SMauro Carvalho Chehab mode = 1; 3819a0bf528SMauro Carvalho Chehab break; 3829a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 3839a0bf528SMauro Carvalho Chehab mode = 2; 3849a0bf528SMauro Carvalho Chehab break; 3859a0bf528SMauro Carvalho Chehab default: 3869a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_AUTO: 3879a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 3889a0bf528SMauro Carvalho Chehab mode = 3; 3899a0bf528SMauro Carvalho Chehab break; 3909a0bf528SMauro Carvalho Chehab } 3919a0bf528SMauro Carvalho Chehab return mode; 3929a0bf528SMauro Carvalho Chehab } 3939a0bf528SMauro Carvalho Chehab 3949a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state) 3959a0bf528SMauro Carvalho Chehab { 3969a0bf528SMauro Carvalho Chehab u16 nud = dib8000_read_word(state, 298); 3979a0bf528SMauro Carvalho Chehab nud |= (1 << 3) | (1 << 0); 3989a0bf528SMauro Carvalho Chehab dprintk("acquisition mode activated"); 3999a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 298, nud); 4009a0bf528SMauro Carvalho Chehab } 4019a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) 4029a0bf528SMauro Carvalho Chehab { 4039a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 4049a0bf528SMauro Carvalho Chehab u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ 4059a0bf528SMauro Carvalho Chehab 406173a64cbSPatrick Boettcher state->output_mode = mode; 4079a0bf528SMauro Carvalho Chehab outreg = 0; 4089a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 4099a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); 4109a0bf528SMauro Carvalho Chehab 4119a0bf528SMauro Carvalho Chehab dprintk("-I- Setting output mode for demod %p to %d", 4129a0bf528SMauro Carvalho Chehab &state->fe[0], mode); 4139a0bf528SMauro Carvalho Chehab 4149a0bf528SMauro Carvalho Chehab switch (mode) { 4159a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock 4169a0bf528SMauro Carvalho Chehab outreg = (1 << 10); /* 0x0400 */ 4179a0bf528SMauro Carvalho Chehab break; 4189a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock 4199a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (1 << 6); /* 0x0440 */ 4209a0bf528SMauro Carvalho Chehab break; 4219a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: // STBs with serial input 4229a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ 4239a0bf528SMauro Carvalho Chehab break; 4249a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 4259a0bf528SMauro Carvalho Chehab if (state->cfg.hostbus_diversity) { 4269a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (4 << 6); /* 0x0500 */ 4279a0bf528SMauro Carvalho Chehab sram &= 0xfdff; 4289a0bf528SMauro Carvalho Chehab } else 4299a0bf528SMauro Carvalho Chehab sram |= 0x0c00; 4309a0bf528SMauro Carvalho Chehab break; 4319a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: // e.g. USB feeding 4329a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 4339a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 4349a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (5 << 6); 4359a0bf528SMauro Carvalho Chehab break; 4369a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: // disable 4379a0bf528SMauro Carvalho Chehab outreg = 0; 4389a0bf528SMauro Carvalho Chehab break; 4399a0bf528SMauro Carvalho Chehab 4409a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 4419a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (3 << 6); 4429a0bf528SMauro Carvalho Chehab dib8000_set_acquisition_mode(state); 4439a0bf528SMauro Carvalho Chehab break; 4449a0bf528SMauro Carvalho Chehab 4459a0bf528SMauro Carvalho Chehab default: 4469a0bf528SMauro Carvalho Chehab dprintk("Unhandled output_mode passed to be set for demod %p", 4479a0bf528SMauro Carvalho Chehab &state->fe[0]); 4489a0bf528SMauro Carvalho Chehab return -EINVAL; 4499a0bf528SMauro Carvalho Chehab } 4509a0bf528SMauro Carvalho Chehab 4519a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 4529a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 4539a0bf528SMauro Carvalho Chehab 4549a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 299, smo_mode); 4559a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */ 4569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1286, outreg); 4579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1291, sram); 4589a0bf528SMauro Carvalho Chehab 4599a0bf528SMauro Carvalho Chehab return 0; 4609a0bf528SMauro Carvalho Chehab } 4619a0bf528SMauro Carvalho Chehab 4629a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) 4639a0bf528SMauro Carvalho Chehab { 4649a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 465173a64cbSPatrick Boettcher u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0; 4669a0bf528SMauro Carvalho Chehab 467173a64cbSPatrick Boettcher dprintk("set diversity input to %i", onoff); 4689a0bf528SMauro Carvalho Chehab if (!state->differential_constellation) { 4699a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 4709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 4719a0bf528SMauro Carvalho Chehab } else { 4729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0 4739a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0 4749a0bf528SMauro Carvalho Chehab } 4759a0bf528SMauro Carvalho Chehab state->diversity_onoff = onoff; 4769a0bf528SMauro Carvalho Chehab 4779a0bf528SMauro Carvalho Chehab switch (onoff) { 4789a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */ 4799a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 1); 4809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 0); 4819a0bf528SMauro Carvalho Chehab break; 4829a0bf528SMauro Carvalho Chehab case 1: /* both ways */ 4839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 6); 4849a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 6); 4859a0bf528SMauro Carvalho Chehab break; 4869a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */ 4879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 0); 4889a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 1); 4899a0bf528SMauro Carvalho Chehab break; 4909a0bf528SMauro Carvalho Chehab } 491173a64cbSPatrick Boettcher 492173a64cbSPatrick Boettcher if (state->revision == 0x8002) { 493173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 903); 494173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp & ~(1 << 3)); 495173a64cbSPatrick Boettcher msleep(30); 496173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp | (1 << 3)); 497173a64cbSPatrick Boettcher } 4989a0bf528SMauro Carvalho Chehab return 0; 4999a0bf528SMauro Carvalho Chehab } 5009a0bf528SMauro Carvalho Chehab 5019a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode) 5029a0bf528SMauro Carvalho Chehab { 5039a0bf528SMauro Carvalho Chehab /* by default everything is going to be powered off */ 5049a0bf528SMauro Carvalho Chehab u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, 5059a0bf528SMauro Carvalho Chehab reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, 5069a0bf528SMauro Carvalho Chehab reg_1280; 5079a0bf528SMauro Carvalho Chehab 5089a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5099a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; 5109a0bf528SMauro Carvalho Chehab else 5119a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80; 5129a0bf528SMauro Carvalho Chehab 5139a0bf528SMauro Carvalho Chehab /* now, depending on the requested mode, we power on */ 5149a0bf528SMauro Carvalho Chehab switch (mode) { 5159a0bf528SMauro Carvalho Chehab /* power up everything in the demod */ 5169a0bf528SMauro Carvalho Chehab case DIB8000_POWER_ALL: 5179a0bf528SMauro Carvalho Chehab reg_774 = 0x0000; 5189a0bf528SMauro Carvalho Chehab reg_775 = 0x0000; 5199a0bf528SMauro Carvalho Chehab reg_776 = 0x0000; 5209a0bf528SMauro Carvalho Chehab reg_900 &= 0xfffc; 5219a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5229a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff; 5239a0bf528SMauro Carvalho Chehab else 5249a0bf528SMauro Carvalho Chehab reg_1280 &= 0x707f; 5259a0bf528SMauro Carvalho Chehab break; 5269a0bf528SMauro Carvalho Chehab case DIB8000_POWER_INTERFACE_ONLY: 5279a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5289a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff; 5299a0bf528SMauro Carvalho Chehab else 5309a0bf528SMauro Carvalho Chehab reg_1280 &= 0xfa7b; 5319a0bf528SMauro Carvalho Chehab break; 5329a0bf528SMauro Carvalho Chehab } 5339a0bf528SMauro Carvalho Chehab 5349a0bf528SMauro Carvalho Chehab dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280); 5359a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 774, reg_774); 5369a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 775, reg_775); 5379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 776, reg_776); 5389a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 900, reg_900); 5399a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, reg_1280); 5409a0bf528SMauro Carvalho Chehab } 5419a0bf528SMauro Carvalho Chehab 5429a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) 5439a0bf528SMauro Carvalho Chehab { 5449a0bf528SMauro Carvalho Chehab int ret = 0; 5459a0bf528SMauro Carvalho Chehab u16 reg, reg_907 = dib8000_read_word(state, 907); 5469a0bf528SMauro Carvalho Chehab u16 reg_908 = dib8000_read_word(state, 908); 5479a0bf528SMauro Carvalho Chehab 5489a0bf528SMauro Carvalho Chehab switch (no) { 5499a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_ON: 5509a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 5519a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0); 5529a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908); 5539a0bf528SMauro Carvalho Chehab reg_908 &= ~(1 << 1); 5549a0bf528SMauro Carvalho Chehab } else { 5559a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5569a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 1 */ 5579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg | 5589a0bf528SMauro Carvalho Chehab (1<<4) | (1<<2)); 5599a0bf528SMauro Carvalho Chehab 5609a0bf528SMauro Carvalho Chehab /* read acces to make it works... strange ... */ 5619a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5629a0bf528SMauro Carvalho Chehab msleep(20); 5639a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 0 */ 5649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg & ~(1<<4)); 5659a0bf528SMauro Carvalho Chehab 5669a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 921) & ~((0x3 << 14) 5679a0bf528SMauro Carvalho Chehab | (0x3 << 12)); 5689a0bf528SMauro Carvalho Chehab /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; 5699a0bf528SMauro Carvalho Chehab (Vin2 = Vcm) */ 5709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, reg | (1 << 14) 5719a0bf528SMauro Carvalho Chehab | (3 << 12)); 5729a0bf528SMauro Carvalho Chehab } 5739a0bf528SMauro Carvalho Chehab break; 5749a0bf528SMauro Carvalho Chehab 5759a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_OFF: 5769a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 5779a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5789a0bf528SMauro Carvalho Chehab /* reset_sladc = 1 en_slowAdc = 0 */ 5799a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, 5809a0bf528SMauro Carvalho Chehab (reg & ~(1<<2)) | (1<<4)); 5819a0bf528SMauro Carvalho Chehab } 5829a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0); 5839a0bf528SMauro Carvalho Chehab break; 5849a0bf528SMauro Carvalho Chehab 5859a0bf528SMauro Carvalho Chehab case DIBX000_ADC_ON: 5869a0bf528SMauro Carvalho Chehab reg_907 &= 0x0fff; 5879a0bf528SMauro Carvalho Chehab reg_908 &= 0x0003; 5889a0bf528SMauro Carvalho Chehab break; 5899a0bf528SMauro Carvalho Chehab 5909a0bf528SMauro Carvalho Chehab case DIBX000_ADC_OFF: // leave the VBG voltage on 5919a0bf528SMauro Carvalho Chehab reg_907 |= (1 << 14) | (1 << 13) | (1 << 12); 5929a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); 5939a0bf528SMauro Carvalho Chehab break; 5949a0bf528SMauro Carvalho Chehab 5959a0bf528SMauro Carvalho Chehab case DIBX000_VBG_ENABLE: 5969a0bf528SMauro Carvalho Chehab reg_907 &= ~(1 << 15); 5979a0bf528SMauro Carvalho Chehab break; 5989a0bf528SMauro Carvalho Chehab 5999a0bf528SMauro Carvalho Chehab case DIBX000_VBG_DISABLE: 6009a0bf528SMauro Carvalho Chehab reg_907 |= (1 << 15); 6019a0bf528SMauro Carvalho Chehab break; 6029a0bf528SMauro Carvalho Chehab 6039a0bf528SMauro Carvalho Chehab default: 6049a0bf528SMauro Carvalho Chehab break; 6059a0bf528SMauro Carvalho Chehab } 6069a0bf528SMauro Carvalho Chehab 6079a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 907, reg_907); 6089a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908); 6099a0bf528SMauro Carvalho Chehab 6109a0bf528SMauro Carvalho Chehab return ret; 6119a0bf528SMauro Carvalho Chehab } 6129a0bf528SMauro Carvalho Chehab 6139a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) 6149a0bf528SMauro Carvalho Chehab { 6159a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 6169a0bf528SMauro Carvalho Chehab u32 timf; 6179a0bf528SMauro Carvalho Chehab 6189a0bf528SMauro Carvalho Chehab if (bw == 0) 6199a0bf528SMauro Carvalho Chehab bw = 6000; 6209a0bf528SMauro Carvalho Chehab 6219a0bf528SMauro Carvalho Chehab if (state->timf == 0) { 6229a0bf528SMauro Carvalho Chehab dprintk("using default timf"); 6239a0bf528SMauro Carvalho Chehab timf = state->timf_default; 6249a0bf528SMauro Carvalho Chehab } else { 6259a0bf528SMauro Carvalho Chehab dprintk("using updated timf"); 6269a0bf528SMauro Carvalho Chehab timf = state->timf; 6279a0bf528SMauro Carvalho Chehab } 6289a0bf528SMauro Carvalho Chehab 6299a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff)); 6309a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) ((timf) & 0xffff)); 6319a0bf528SMauro Carvalho Chehab 6329a0bf528SMauro Carvalho Chehab return 0; 6339a0bf528SMauro Carvalho Chehab } 6349a0bf528SMauro Carvalho Chehab 6359a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state) 6369a0bf528SMauro Carvalho Chehab { 637173a64cbSPatrick Boettcher u8 sad_sel = 3; 638173a64cbSPatrick Boettcher 6399a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 640173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2)); 641173a64cbSPatrick Boettcher dib8000_write_word(state, 923, 2048); 642173a64cbSPatrick Boettcher 643173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2) | 0x1); 644173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2)); 645173a64cbSPatrick Boettcher } else { 6469a0bf528SMauro Carvalho Chehab /* internal */ 6479a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); 648173a64cbSPatrick Boettcher dib8000_write_word(state, 924, 776); 6499a0bf528SMauro Carvalho Chehab 6509a0bf528SMauro Carvalho Chehab /* do the calibration */ 6519a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (1 << 0)); 6529a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 0)); 653173a64cbSPatrick Boettcher } 6549a0bf528SMauro Carvalho Chehab 6559a0bf528SMauro Carvalho Chehab msleep(1); 6569a0bf528SMauro Carvalho Chehab return 0; 6579a0bf528SMauro Carvalho Chehab } 6589a0bf528SMauro Carvalho Chehab 659d44913c1SMauro Carvalho Chehab static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) 6609a0bf528SMauro Carvalho Chehab { 6619a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 6629a0bf528SMauro Carvalho Chehab if (value > 4095) 6639a0bf528SMauro Carvalho Chehab value = 4095; 6649a0bf528SMauro Carvalho Chehab state->wbd_ref = value; 6659a0bf528SMauro Carvalho Chehab return dib8000_write_word(state, 106, value); 6669a0bf528SMauro Carvalho Chehab } 667173a64cbSPatrick Boettcher 6689a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) 6699a0bf528SMauro Carvalho Chehab { 6709a0bf528SMauro Carvalho Chehab dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); 6719a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 6729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, 6739a0bf528SMauro Carvalho Chehab (u16) (((bw->internal * 1000) >> 16) & 0xffff)); 6749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, 6759a0bf528SMauro Carvalho Chehab (u16) ((bw->internal * 1000) & 0xffff)); 6769a0bf528SMauro Carvalho Chehab } else { 6779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff)); 6789a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, 6799a0bf528SMauro Carvalho Chehab (u16) ((bw->internal / 2 * 1000) & 0xffff)); 6809a0bf528SMauro Carvalho Chehab } 6819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); 6829a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); 6839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); 6849a0bf528SMauro Carvalho Chehab 6859a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 6869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, bw->sad_cfg); 6879a0bf528SMauro Carvalho Chehab } 6889a0bf528SMauro Carvalho Chehab 6899a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state) 6909a0bf528SMauro Carvalho Chehab { 6919a0bf528SMauro Carvalho Chehab const struct dibx000_bandwidth_config *pll = state->cfg.pll; 6929a0bf528SMauro Carvalho Chehab u16 clk_cfg1, reg; 6939a0bf528SMauro Carvalho Chehab 6949a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 6959a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 901, 6969a0bf528SMauro Carvalho Chehab (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); 6979a0bf528SMauro Carvalho Chehab 6989a0bf528SMauro Carvalho Chehab clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | 6999a0bf528SMauro Carvalho Chehab (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | 7009a0bf528SMauro Carvalho Chehab (1 << 3) | (pll->pll_range << 1) | 7019a0bf528SMauro Carvalho Chehab (pll->pll_reset << 0); 7029a0bf528SMauro Carvalho Chehab 7039a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1); 7049a0bf528SMauro Carvalho Chehab clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); 7059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1); 7069a0bf528SMauro Carvalho Chehab 7079a0bf528SMauro Carvalho Chehab dprintk("clk_cfg1: 0x%04x", clk_cfg1); 7089a0bf528SMauro Carvalho Chehab 7099a0bf528SMauro Carvalho Chehab /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ 7109a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ADClkSrc == 0) 7119a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, 7129a0bf528SMauro Carvalho Chehab (0 << 15) | (0 << 12) | (0 << 10) | 7139a0bf528SMauro Carvalho Chehab (pll->modulo << 8) | 7149a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7159a0bf528SMauro Carvalho Chehab else if (state->cfg.refclksel != 0) 7169a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | 7179a0bf528SMauro Carvalho Chehab ((state->cfg.refclksel & 0x3) << 10) | 7189a0bf528SMauro Carvalho Chehab (pll->modulo << 8) | 7199a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7209a0bf528SMauro Carvalho Chehab else 7219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | 7229a0bf528SMauro Carvalho Chehab (3 << 10) | (pll->modulo << 8) | 7239a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7249a0bf528SMauro Carvalho Chehab } else { 7259a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, (!pll->pll_reset<<13) | 7269a0bf528SMauro Carvalho Chehab (pll->pll_range<<12) | (pll->pll_ratio<<6) | 7279a0bf528SMauro Carvalho Chehab (pll->pll_prediv)); 7289a0bf528SMauro Carvalho Chehab 7299a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1857); 7309a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15)); 7319a0bf528SMauro Carvalho Chehab 7329a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */ 7339a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1858, reg | 1); 7349a0bf528SMauro Carvalho Chehab 7359a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (pll->modulo << 8)); 7369a0bf528SMauro Carvalho Chehab } 7379a0bf528SMauro Carvalho Chehab 7389a0bf528SMauro Carvalho Chehab dib8000_reset_pll_common(state, pll); 7399a0bf528SMauro Carvalho Chehab } 7409a0bf528SMauro Carvalho Chehab 741d44913c1SMauro Carvalho Chehab static int dib8000_update_pll(struct dvb_frontend *fe, 742173a64cbSPatrick Boettcher struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio) 7439a0bf528SMauro Carvalho Chehab { 7449a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 7459a0bf528SMauro Carvalho Chehab u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856); 746173a64cbSPatrick Boettcher u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ; 7479a0bf528SMauro Carvalho Chehab u32 internal, xtal; 7489a0bf528SMauro Carvalho Chehab 7499a0bf528SMauro Carvalho Chehab /* get back old values */ 7509a0bf528SMauro Carvalho Chehab prediv = reg_1856 & 0x3f; 7519a0bf528SMauro Carvalho Chehab loopdiv = (reg_1856 >> 6) & 0x3f; 7529a0bf528SMauro Carvalho Chehab 753173a64cbSPatrick Boettcher if ((pll == NULL) || (pll->pll_prediv == prediv && 754173a64cbSPatrick Boettcher pll->pll_ratio == loopdiv)) 755173a64cbSPatrick Boettcher return -EINVAL; 756173a64cbSPatrick Boettcher 7579a0bf528SMauro Carvalho Chehab dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); 758173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 7599a0bf528SMauro Carvalho Chehab reg_1856 &= 0xf000; 7609a0bf528SMauro Carvalho Chehab reg_1857 = dib8000_read_word(state, 1857); 7619a0bf528SMauro Carvalho Chehab /* disable PLL */ 7629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15)); 7639a0bf528SMauro Carvalho Chehab 7649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, reg_1856 | 7659a0bf528SMauro Carvalho Chehab ((pll->pll_ratio & 0x3f) << 6) | 7669a0bf528SMauro Carvalho Chehab (pll->pll_prediv & 0x3f)); 7679a0bf528SMauro Carvalho Chehab 7689a0bf528SMauro Carvalho Chehab /* write new system clk into P_sec_len */ 7699a0bf528SMauro Carvalho Chehab internal = dib8000_read32(state, 23) / 1000; 7709a0bf528SMauro Carvalho Chehab dprintk("Old Internal = %d", internal); 7719a0bf528SMauro Carvalho Chehab xtal = 2 * (internal / loopdiv) * prediv; 7729a0bf528SMauro Carvalho Chehab internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio; 7739a0bf528SMauro Carvalho Chehab dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000); 7749a0bf528SMauro Carvalho Chehab dprintk("New Internal = %d", internal); 7759a0bf528SMauro Carvalho Chehab 7769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, 7779a0bf528SMauro Carvalho Chehab (u16) (((internal / 2) >> 16) & 0xffff)); 7789a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff)); 7799a0bf528SMauro Carvalho Chehab /* enable PLL */ 7809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 | (1 << 15)); 7819a0bf528SMauro Carvalho Chehab 7829a0bf528SMauro Carvalho Chehab while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1) 7839a0bf528SMauro Carvalho Chehab dprintk("Waiting for PLL to lock"); 7849a0bf528SMauro Carvalho Chehab 7859a0bf528SMauro Carvalho Chehab /* verify */ 7869a0bf528SMauro Carvalho Chehab reg_1856 = dib8000_read_word(state, 1856); 7879a0bf528SMauro Carvalho Chehab dprintk("PLL Updated with prediv = %d and loopdiv = %d", 7889a0bf528SMauro Carvalho Chehab reg_1856&0x3f, (reg_1856>>6)&0x3f); 789173a64cbSPatrick Boettcher } else { 790173a64cbSPatrick Boettcher if (bw != state->current_demod_bw) { 791173a64cbSPatrick Boettcher /** Bandwidth change => force PLL update **/ 792173a64cbSPatrick Boettcher dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv); 793173a64cbSPatrick Boettcher 794173a64cbSPatrick Boettcher if (state->cfg.pll->pll_prediv != oldprediv) { 795173a64cbSPatrick Boettcher /** Full PLL change only if prediv is changed **/ 796173a64cbSPatrick Boettcher 797173a64cbSPatrick Boettcher /** full update => bypass and reconfigure **/ 798173a64cbSPatrick Boettcher dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio); 799173a64cbSPatrick Boettcher dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */ 800173a64cbSPatrick Boettcher dib8000_reset_pll(state); 801173a64cbSPatrick Boettcher dib8000_write_word(state, 898, 0x0004); /* sad */ 802173a64cbSPatrick Boettcher } else 803173a64cbSPatrick Boettcher ratio = state->cfg.pll->pll_ratio; 804173a64cbSPatrick Boettcher 805173a64cbSPatrick Boettcher state->current_demod_bw = bw; 806173a64cbSPatrick Boettcher } 807173a64cbSPatrick Boettcher 808173a64cbSPatrick Boettcher if (ratio != 0) { 809173a64cbSPatrick Boettcher /** ratio update => only change ratio **/ 810173a64cbSPatrick Boettcher dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio); 811173a64cbSPatrick Boettcher dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ 812173a64cbSPatrick Boettcher } 813173a64cbSPatrick Boettcher } 8149a0bf528SMauro Carvalho Chehab 8159a0bf528SMauro Carvalho Chehab return 0; 8169a0bf528SMauro Carvalho Chehab } 8179a0bf528SMauro Carvalho Chehab 8189a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st) 8199a0bf528SMauro Carvalho Chehab { 8209a0bf528SMauro Carvalho Chehab /* reset the GPIOs */ 8219a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir); 8229a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val); 8239a0bf528SMauro Carvalho Chehab 8249a0bf528SMauro Carvalho Chehab /* TODO 782 is P_gpio_od */ 8259a0bf528SMauro Carvalho Chehab 8269a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos); 8279a0bf528SMauro Carvalho Chehab 8289a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1037, st->cfg.pwm_freq_div); 8299a0bf528SMauro Carvalho Chehab return 0; 8309a0bf528SMauro Carvalho Chehab } 8319a0bf528SMauro Carvalho Chehab 8329a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val) 8339a0bf528SMauro Carvalho Chehab { 8349a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir = dib8000_read_word(st, 1029); 8359a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */ 8369a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */ 8379a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir); 8389a0bf528SMauro Carvalho Chehab 8399a0bf528SMauro Carvalho Chehab st->cfg.gpio_val = dib8000_read_word(st, 1030); 8409a0bf528SMauro Carvalho Chehab st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */ 8419a0bf528SMauro Carvalho Chehab st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */ 8429a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val); 8439a0bf528SMauro Carvalho Chehab 8449a0bf528SMauro Carvalho Chehab dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val); 8459a0bf528SMauro Carvalho Chehab 8469a0bf528SMauro Carvalho Chehab return 0; 8479a0bf528SMauro Carvalho Chehab } 8489a0bf528SMauro Carvalho Chehab 849d44913c1SMauro Carvalho Chehab static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) 8509a0bf528SMauro Carvalho Chehab { 8519a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 8529a0bf528SMauro Carvalho Chehab return dib8000_cfg_gpio(state, num, dir, val); 8539a0bf528SMauro Carvalho Chehab } 8549a0bf528SMauro Carvalho Chehab 8559a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = { 8569a0bf528SMauro Carvalho Chehab /* auto search configuration - lock0 by default waiting 8579a0bf528SMauro Carvalho Chehab * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */ 8589a0bf528SMauro Carvalho Chehab 3, 7, 8599a0bf528SMauro Carvalho Chehab 0x0004, 8609a0bf528SMauro Carvalho Chehab 0x0400, 8619a0bf528SMauro Carvalho Chehab 0x0814, 8629a0bf528SMauro Carvalho Chehab 8639a0bf528SMauro Carvalho Chehab 12, 11, 8649a0bf528SMauro Carvalho Chehab 0x001b, 8659a0bf528SMauro Carvalho Chehab 0x7740, 8669a0bf528SMauro Carvalho Chehab 0x005b, 8679a0bf528SMauro Carvalho Chehab 0x8d80, 8689a0bf528SMauro Carvalho Chehab 0x01c9, 8699a0bf528SMauro Carvalho Chehab 0xc380, 8709a0bf528SMauro Carvalho Chehab 0x0000, 8719a0bf528SMauro Carvalho Chehab 0x0080, 8729a0bf528SMauro Carvalho Chehab 0x0000, 8739a0bf528SMauro Carvalho Chehab 0x0090, 8749a0bf528SMauro Carvalho Chehab 0x0001, 8759a0bf528SMauro Carvalho Chehab 0xd4c0, 8769a0bf528SMauro Carvalho Chehab 8779a0bf528SMauro Carvalho Chehab /*1, 32, 8789a0bf528SMauro Carvalho Chehab 0x6680 // P_corm_thres Lock algorithms configuration */ 8799a0bf528SMauro Carvalho Chehab 8809a0bf528SMauro Carvalho Chehab 11, 80, /* set ADC level to -16 */ 8819a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117, 8829a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117, 8839a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117, 8849a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117, 8859a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117, 8869a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117, 8879a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117, 8889a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117, 8899a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117, 8909a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117, 8919a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117, 8929a0bf528SMauro Carvalho Chehab 8939a0bf528SMauro Carvalho Chehab 4, 108, 8949a0bf528SMauro Carvalho Chehab 0, 8959a0bf528SMauro Carvalho Chehab 0, 8969a0bf528SMauro Carvalho Chehab 0, 8979a0bf528SMauro Carvalho Chehab 0, 8989a0bf528SMauro Carvalho Chehab 8999a0bf528SMauro Carvalho Chehab 1, 175, 9009a0bf528SMauro Carvalho Chehab 0x0410, 9019a0bf528SMauro Carvalho Chehab 1, 179, 9029a0bf528SMauro Carvalho Chehab 8192, // P_fft_nb_to_cut 9039a0bf528SMauro Carvalho Chehab 9049a0bf528SMauro Carvalho Chehab 6, 181, 9059a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800 9069a0bf528SMauro Carvalho Chehab 0x2800, 9079a0bf528SMauro Carvalho Chehab 0x2800, 9089a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800 9099a0bf528SMauro Carvalho Chehab 0x2800, 9109a0bf528SMauro Carvalho Chehab 0x2800, 9119a0bf528SMauro Carvalho Chehab 9129a0bf528SMauro Carvalho Chehab 2, 193, 9139a0bf528SMauro Carvalho Chehab 0x0666, // P_pha3_thres 9149a0bf528SMauro Carvalho Chehab 0x0000, // P_cti_use_cpe, P_cti_use_prog 9159a0bf528SMauro Carvalho Chehab 9169a0bf528SMauro Carvalho Chehab 2, 205, 9179a0bf528SMauro Carvalho Chehab 0x200f, // P_cspu_regul, P_cspu_win_cut 9189a0bf528SMauro Carvalho Chehab 0x000f, // P_des_shift_work 9199a0bf528SMauro Carvalho Chehab 9209a0bf528SMauro Carvalho Chehab 5, 215, 9219a0bf528SMauro Carvalho Chehab 0x023d, // P_adp_regul_cnt 9229a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_noise_cnt 9239a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_regul_ext 9249a0bf528SMauro Carvalho Chehab 0x7ff0, // P_adp_noise_ext 9259a0bf528SMauro Carvalho Chehab 0x3ccc, // P_adp_fil 9269a0bf528SMauro Carvalho Chehab 9279a0bf528SMauro Carvalho Chehab 1, 230, 9289a0bf528SMauro Carvalho Chehab 0x0000, // P_2d_byp_ti_num 9299a0bf528SMauro Carvalho Chehab 9309a0bf528SMauro Carvalho Chehab 1, 263, 9319a0bf528SMauro Carvalho Chehab 0x800, //P_equal_thres_wgn 9329a0bf528SMauro Carvalho Chehab 9339a0bf528SMauro Carvalho Chehab 1, 268, 9349a0bf528SMauro Carvalho Chehab (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode 9359a0bf528SMauro Carvalho Chehab 9369a0bf528SMauro Carvalho Chehab 1, 270, 9379a0bf528SMauro Carvalho Chehab 0x0001, // P_div_lock0_wait 9389a0bf528SMauro Carvalho Chehab 1, 285, 9399a0bf528SMauro Carvalho Chehab 0x0020, //p_fec_ 9409a0bf528SMauro Carvalho Chehab 1, 299, 9419a0bf528SMauro Carvalho Chehab 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */ 9429a0bf528SMauro Carvalho Chehab 9439a0bf528SMauro Carvalho Chehab 1, 338, 9449a0bf528SMauro Carvalho Chehab (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 9459a0bf528SMauro Carvalho Chehab (1 << 10) | 9469a0bf528SMauro Carvalho Chehab (0 << 9) | /* P_ctrl_pre_freq_inh=0 */ 9479a0bf528SMauro Carvalho Chehab (3 << 5) | /* P_ctrl_pre_freq_step=3 */ 9489a0bf528SMauro Carvalho Chehab (1 << 0), /* P_pre_freq_win_len=1 */ 9499a0bf528SMauro Carvalho Chehab 9509a0bf528SMauro Carvalho Chehab 0, 9519a0bf528SMauro Carvalho Chehab }; 9529a0bf528SMauro Carvalho Chehab 9539a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client) 9549a0bf528SMauro Carvalho Chehab { 9559a0bf528SMauro Carvalho Chehab u16 value; 9569a0bf528SMauro Carvalho Chehab 9579a0bf528SMauro Carvalho Chehab //because of glitches sometimes 9589a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 896); 9599a0bf528SMauro Carvalho Chehab 9609a0bf528SMauro Carvalho Chehab if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) { 9619a0bf528SMauro Carvalho Chehab dprintk("wrong Vendor ID (read=0x%x)", value); 9629a0bf528SMauro Carvalho Chehab return 0; 9639a0bf528SMauro Carvalho Chehab } 9649a0bf528SMauro Carvalho Chehab 9659a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 897); 9669a0bf528SMauro Carvalho Chehab if (value != 0x8000 && value != 0x8001 && 9679a0bf528SMauro Carvalho Chehab value != 0x8002 && value != 0x8090) { 9689a0bf528SMauro Carvalho Chehab dprintk("wrong Device ID (%x)", value); 9699a0bf528SMauro Carvalho Chehab return 0; 9709a0bf528SMauro Carvalho Chehab } 9719a0bf528SMauro Carvalho Chehab 9729a0bf528SMauro Carvalho Chehab switch (value) { 9739a0bf528SMauro Carvalho Chehab case 0x8000: 9749a0bf528SMauro Carvalho Chehab dprintk("found DiB8000A"); 9759a0bf528SMauro Carvalho Chehab break; 9769a0bf528SMauro Carvalho Chehab case 0x8001: 9779a0bf528SMauro Carvalho Chehab dprintk("found DiB8000B"); 9789a0bf528SMauro Carvalho Chehab break; 9799a0bf528SMauro Carvalho Chehab case 0x8002: 9809a0bf528SMauro Carvalho Chehab dprintk("found DiB8000C"); 9819a0bf528SMauro Carvalho Chehab break; 9829a0bf528SMauro Carvalho Chehab case 0x8090: 9839a0bf528SMauro Carvalho Chehab dprintk("found DiB8096P"); 9849a0bf528SMauro Carvalho Chehab break; 9859a0bf528SMauro Carvalho Chehab } 9869a0bf528SMauro Carvalho Chehab return value; 9879a0bf528SMauro Carvalho Chehab } 9889a0bf528SMauro Carvalho Chehab 9897a9d85d5SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc); 9907a9d85d5SMauro Carvalho Chehab 9916ef06e78SMauro Carvalho Chehab static void dib8000_reset_stats(struct dvb_frontend *fe) 9926ef06e78SMauro Carvalho Chehab { 9936ef06e78SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 9946ef06e78SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 9957a9d85d5SMauro Carvalho Chehab u32 ucb; 9966ef06e78SMauro Carvalho Chehab 9976ef06e78SMauro Carvalho Chehab memset(&c->strength, 0, sizeof(c->strength)); 9986ef06e78SMauro Carvalho Chehab memset(&c->cnr, 0, sizeof(c->cnr)); 9996ef06e78SMauro Carvalho Chehab memset(&c->post_bit_error, 0, sizeof(c->post_bit_error)); 10006ef06e78SMauro Carvalho Chehab memset(&c->post_bit_count, 0, sizeof(c->post_bit_count)); 10016ef06e78SMauro Carvalho Chehab memset(&c->block_error, 0, sizeof(c->block_error)); 10026ef06e78SMauro Carvalho Chehab 10036ef06e78SMauro Carvalho Chehab c->strength.len = 1; 10046ef06e78SMauro Carvalho Chehab c->cnr.len = 1; 10056ef06e78SMauro Carvalho Chehab c->block_error.len = 1; 10060400c535SMauro Carvalho Chehab c->block_count.len = 1; 10076ef06e78SMauro Carvalho Chehab c->post_bit_error.len = 1; 10086ef06e78SMauro Carvalho Chehab c->post_bit_count.len = 1; 10096ef06e78SMauro Carvalho Chehab 1010b4600d70SMauro Carvalho Chehab c->strength.stat[0].scale = FE_SCALE_DECIBEL; 10116ef06e78SMauro Carvalho Chehab c->strength.stat[0].uvalue = 0; 10126ef06e78SMauro Carvalho Chehab 10136ef06e78SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10146ef06e78SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10150400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10166ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10176ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 10187a9d85d5SMauro Carvalho Chehab 10197a9d85d5SMauro Carvalho Chehab dib8000_read_unc_blocks(fe, &ucb); 1020704f01bbSMauro Carvalho Chehab 10217a9d85d5SMauro Carvalho Chehab state->init_ucb = -ucb; 10220400c535SMauro Carvalho Chehab state->ber_jiffies_stats = 0; 10230400c535SMauro Carvalho Chehab state->per_jiffies_stats = 0; 10240400c535SMauro Carvalho Chehab memset(&state->ber_jiffies_stats_layer, 0, 10250400c535SMauro Carvalho Chehab sizeof(state->ber_jiffies_stats_layer)); 10266ef06e78SMauro Carvalho Chehab } 10276ef06e78SMauro Carvalho Chehab 10289a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe) 10299a0bf528SMauro Carvalho Chehab { 10309a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 10319a0bf528SMauro Carvalho Chehab 10329a0bf528SMauro Carvalho Chehab if ((state->revision = dib8000_identify(&state->i2c)) == 0) 10339a0bf528SMauro Carvalho Chehab return -EINVAL; 10349a0bf528SMauro Carvalho Chehab 10359a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */ 10369a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 10379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, 0x0003); 10389a0bf528SMauro Carvalho Chehab 10399a0bf528SMauro Carvalho Chehab if (state->revision == 0x8000) 10409a0bf528SMauro Carvalho Chehab dprintk("error : dib8000 MA not supported"); 10419a0bf528SMauro Carvalho Chehab 10429a0bf528SMauro Carvalho Chehab dibx000_reset_i2c_master(&state->i2c_master); 10439a0bf528SMauro Carvalho Chehab 10449a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 10459a0bf528SMauro Carvalho Chehab 10469a0bf528SMauro Carvalho Chehab /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ 1047173a64cbSPatrick Boettcher dib8000_set_adc_state(state, DIBX000_ADC_OFF); 10489a0bf528SMauro Carvalho Chehab 10499a0bf528SMauro Carvalho Chehab /* restart all parts */ 10509a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0xffff); 10519a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0xffff); 10529a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0xfffc); 10539a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 10549a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0045); 10559a0bf528SMauro Carvalho Chehab else 10569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x004d); 10579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x000c); 10589a0bf528SMauro Carvalho Chehab 10599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000); 10609a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0x0000); 10619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0x0000); 10629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004); // sad 10639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0000); 10649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x0000); 10659a0bf528SMauro Carvalho Chehab 10669a0bf528SMauro Carvalho Chehab /* drives */ 10679a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 10689a0bf528SMauro Carvalho Chehab if (state->cfg.drives) 10699a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, state->cfg.drives); 10709a0bf528SMauro Carvalho Chehab else { 10719a0bf528SMauro Carvalho Chehab dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); 10729a0bf528SMauro Carvalho Chehab /* min drive SDRAM - not optimal - adjust */ 10739a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, 0x2d98); 10749a0bf528SMauro Carvalho Chehab } 10759a0bf528SMauro Carvalho Chehab } 10769a0bf528SMauro Carvalho Chehab 10779a0bf528SMauro Carvalho Chehab dib8000_reset_pll(state); 10789a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 10799a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004); 10809a0bf528SMauro Carvalho Chehab 10819a0bf528SMauro Carvalho Chehab if (dib8000_reset_gpio(state) != 0) 10829a0bf528SMauro Carvalho Chehab dprintk("GPIO reset was not successful."); 10839a0bf528SMauro Carvalho Chehab 10849a0bf528SMauro Carvalho Chehab if ((state->revision != 0x8090) && 10859a0bf528SMauro Carvalho Chehab (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)) 10869a0bf528SMauro Carvalho Chehab dprintk("OUTPUT_MODE could not be resetted."); 10879a0bf528SMauro Carvalho Chehab 10889a0bf528SMauro Carvalho Chehab state->current_agc = NULL; 10899a0bf528SMauro Carvalho Chehab 10909a0bf528SMauro Carvalho Chehab // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... 10919a0bf528SMauro Carvalho Chehab /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */ 10929a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ifreq == 0) 10939a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */ 10949a0bf528SMauro Carvalho Chehab else 10959a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */ 10969a0bf528SMauro Carvalho Chehab 10979a0bf528SMauro Carvalho Chehab { 10989a0bf528SMauro Carvalho Chehab u16 l = 0, r; 10999a0bf528SMauro Carvalho Chehab const u16 *n; 11009a0bf528SMauro Carvalho Chehab n = dib8000_defaults; 11019a0bf528SMauro Carvalho Chehab l = *n++; 11029a0bf528SMauro Carvalho Chehab while (l) { 11039a0bf528SMauro Carvalho Chehab r = *n++; 11049a0bf528SMauro Carvalho Chehab do { 11059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, r, *n++); 11069a0bf528SMauro Carvalho Chehab r++; 11079a0bf528SMauro Carvalho Chehab } while (--l); 11089a0bf528SMauro Carvalho Chehab l = *n++; 11099a0bf528SMauro Carvalho Chehab } 11109a0bf528SMauro Carvalho Chehab } 1111173a64cbSPatrick Boettcher 11129a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0; 11139a0bf528SMauro Carvalho Chehab 11149a0bf528SMauro Carvalho Chehab //div_cfg override for special configs 1115173a64cbSPatrick Boettcher if ((state->revision != 8090) && (state->cfg.div_cfg != 0)) 11169a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 903, state->cfg.div_cfg); 11179a0bf528SMauro Carvalho Chehab 11189a0bf528SMauro Carvalho Chehab /* unforce divstr regardless whether i2c enumeration was done or not */ 11199a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1)); 11209a0bf528SMauro Carvalho Chehab 11219a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(fe, 6000); 11229a0bf528SMauro Carvalho Chehab 11239a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); 11249a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state); 1125173a64cbSPatrick Boettcher if (state->revision != 0x8090) 11269a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); 1127173a64cbSPatrick Boettcher 1128173a64cbSPatrick Boettcher /* ber_rs_len = 3 */ 1129173a64cbSPatrick Boettcher dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); 11309a0bf528SMauro Carvalho Chehab 11319a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); 11329a0bf528SMauro Carvalho Chehab 11336ef06e78SMauro Carvalho Chehab dib8000_reset_stats(fe); 11346ef06e78SMauro Carvalho Chehab 11359a0bf528SMauro Carvalho Chehab return 0; 11369a0bf528SMauro Carvalho Chehab } 11379a0bf528SMauro Carvalho Chehab 11389a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state) 11399a0bf528SMauro Carvalho Chehab { 11409a0bf528SMauro Carvalho Chehab // P_restart_iqc & P_restart_agc 11419a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0a00); 11429a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000); 11439a0bf528SMauro Carvalho Chehab } 11449a0bf528SMauro Carvalho Chehab 11459a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state) 11469a0bf528SMauro Carvalho Chehab { 11479a0bf528SMauro Carvalho Chehab u16 dyn_gain; 11489a0bf528SMauro Carvalho Chehab 11499a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna) { 11509a0bf528SMauro Carvalho Chehab // read dyn_gain here (because it is demod-dependent and not tuner) 11519a0bf528SMauro Carvalho Chehab dyn_gain = dib8000_read_word(state, 390); 11529a0bf528SMauro Carvalho Chehab 11539a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna(state->fe[0], dyn_gain)) { 11549a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state); 11559a0bf528SMauro Carvalho Chehab return 1; 11569a0bf528SMauro Carvalho Chehab } 11579a0bf528SMauro Carvalho Chehab } 11589a0bf528SMauro Carvalho Chehab return 0; 11599a0bf528SMauro Carvalho Chehab } 11609a0bf528SMauro Carvalho Chehab 11619a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) 11629a0bf528SMauro Carvalho Chehab { 11639a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *agc = NULL; 11649a0bf528SMauro Carvalho Chehab int i; 11659a0bf528SMauro Carvalho Chehab u16 reg; 11669a0bf528SMauro Carvalho Chehab 11679a0bf528SMauro Carvalho Chehab if (state->current_band == band && state->current_agc != NULL) 11689a0bf528SMauro Carvalho Chehab return 0; 11699a0bf528SMauro Carvalho Chehab state->current_band = band; 11709a0bf528SMauro Carvalho Chehab 11719a0bf528SMauro Carvalho Chehab for (i = 0; i < state->cfg.agc_config_count; i++) 11729a0bf528SMauro Carvalho Chehab if (state->cfg.agc[i].band_caps & band) { 11739a0bf528SMauro Carvalho Chehab agc = &state->cfg.agc[i]; 11749a0bf528SMauro Carvalho Chehab break; 11759a0bf528SMauro Carvalho Chehab } 11769a0bf528SMauro Carvalho Chehab 11779a0bf528SMauro Carvalho Chehab if (agc == NULL) { 11789a0bf528SMauro Carvalho Chehab dprintk("no valid AGC configuration found for band 0x%02x", band); 11799a0bf528SMauro Carvalho Chehab return -EINVAL; 11809a0bf528SMauro Carvalho Chehab } 11819a0bf528SMauro Carvalho Chehab 11829a0bf528SMauro Carvalho Chehab state->current_agc = agc; 11839a0bf528SMauro Carvalho Chehab 11849a0bf528SMauro Carvalho Chehab /* AGC */ 11859a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 76, agc->setup); 11869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 77, agc->inv_gain); 11879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 78, agc->time_stabiliz); 11889a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock); 11899a0bf528SMauro Carvalho Chehab 11909a0bf528SMauro Carvalho Chehab // Demod AGC loop configuration 11919a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp); 11929a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp); 11939a0bf528SMauro Carvalho Chehab 11949a0bf528SMauro Carvalho Chehab dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", 11959a0bf528SMauro Carvalho Chehab state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); 11969a0bf528SMauro Carvalho Chehab 11979a0bf528SMauro Carvalho Chehab /* AGC continued */ 11989a0bf528SMauro Carvalho Chehab if (state->wbd_ref != 0) 11999a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, state->wbd_ref); 12009a0bf528SMauro Carvalho Chehab else // use default 12019a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, agc->wbd_ref); 12029a0bf528SMauro Carvalho Chehab 12039a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 12049a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 922) & (0x3 << 2); 12059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2)); 12069a0bf528SMauro Carvalho Chehab } 12079a0bf528SMauro Carvalho Chehab 12089a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); 12099a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 108, agc->agc1_max); 12109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 109, agc->agc1_min); 12119a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 110, agc->agc2_max); 12129a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 111, agc->agc2_min); 12139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2); 12149a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); 12159a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); 12169a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); 12179a0bf528SMauro Carvalho Chehab 12189a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 75, agc->agc1_pt3); 12199a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 12209a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, 12219a0bf528SMauro Carvalho Chehab (dib8000_read_word(state, 923) & 0xffe3) | 12229a0bf528SMauro Carvalho Chehab (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); 12239a0bf528SMauro Carvalho Chehab 12249a0bf528SMauro Carvalho Chehab return 0; 12259a0bf528SMauro Carvalho Chehab } 12269a0bf528SMauro Carvalho Chehab 1227d44913c1SMauro Carvalho Chehab static void dib8000_pwm_agc_reset(struct dvb_frontend *fe) 12289a0bf528SMauro Carvalho Chehab { 12299a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 12309a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 12319a0bf528SMauro Carvalho Chehab dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); 12329a0bf528SMauro Carvalho Chehab } 12339a0bf528SMauro Carvalho Chehab 12349a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state) 12359a0bf528SMauro Carvalho Chehab { 12369a0bf528SMauro Carvalho Chehab u16 agc, split_offset; 12379a0bf528SMauro Carvalho Chehab 12389a0bf528SMauro Carvalho Chehab if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) 12399a0bf528SMauro Carvalho Chehab return FE_CALLBACK_TIME_NEVER; 12409a0bf528SMauro Carvalho Chehab 12419a0bf528SMauro Carvalho Chehab // n_agc_global 12429a0bf528SMauro Carvalho Chehab agc = dib8000_read_word(state, 390); 12439a0bf528SMauro Carvalho Chehab 12449a0bf528SMauro Carvalho Chehab if (agc > state->current_agc->split.min_thres) 12459a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.min; 12469a0bf528SMauro Carvalho Chehab else if (agc < state->current_agc->split.max_thres) 12479a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max; 12489a0bf528SMauro Carvalho Chehab else 12499a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max * 12509a0bf528SMauro Carvalho Chehab (agc - state->current_agc->split.min_thres) / 12519a0bf528SMauro Carvalho Chehab (state->current_agc->split.max_thres - state->current_agc->split.min_thres); 12529a0bf528SMauro Carvalho Chehab 12539a0bf528SMauro Carvalho Chehab dprintk("AGC split_offset: %d", split_offset); 12549a0bf528SMauro Carvalho Chehab 12559a0bf528SMauro Carvalho Chehab // P_agc_force_split and P_agc_split_offset 12569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset); 12579a0bf528SMauro Carvalho Chehab return 5000; 12589a0bf528SMauro Carvalho Chehab } 12599a0bf528SMauro Carvalho Chehab 12609a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe) 12619a0bf528SMauro Carvalho Chehab { 12629a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 12639a0bf528SMauro Carvalho Chehab enum frontend_tune_state *tune_state = &state->tune_state; 12649a0bf528SMauro Carvalho Chehab int ret = 0; 12659a0bf528SMauro Carvalho Chehab u16 reg, upd_demod_gain_period = 0x8000; 12669a0bf528SMauro Carvalho Chehab 12679a0bf528SMauro Carvalho Chehab switch (*tune_state) { 12689a0bf528SMauro Carvalho Chehab case CT_AGC_START: 12699a0bf528SMauro Carvalho Chehab // set power-up level: interf+analog+AGC 12709a0bf528SMauro Carvalho Chehab 12719a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 12729a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 12739a0bf528SMauro Carvalho Chehab else { 12749a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 12759a0bf528SMauro Carvalho Chehab 12769a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1947)&0xff00; 12779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1946, 12789a0bf528SMauro Carvalho Chehab upd_demod_gain_period & 0xFFFF); 12799a0bf528SMauro Carvalho Chehab /* bit 14 = enDemodGain */ 12809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1947, reg | (1<<14) | 12819a0bf528SMauro Carvalho Chehab ((upd_demod_gain_period >> 16) & 0xFF)); 12829a0bf528SMauro Carvalho Chehab 12839a0bf528SMauro Carvalho Chehab /* enable adc i & q */ 12849a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1920); 12859a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1920, (reg | 0x3) & 12869a0bf528SMauro Carvalho Chehab (~(1 << 7))); 12879a0bf528SMauro Carvalho Chehab } 12889a0bf528SMauro Carvalho Chehab 12899a0bf528SMauro Carvalho Chehab if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { 12909a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP; 12919a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_TUNE_FAILED; 12929a0bf528SMauro Carvalho Chehab break; 12939a0bf528SMauro Carvalho Chehab } 12949a0bf528SMauro Carvalho Chehab 12959a0bf528SMauro Carvalho Chehab ret = 70; 12969a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_0; 12979a0bf528SMauro Carvalho Chehab break; 12989a0bf528SMauro Carvalho Chehab 12999a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_0: 13009a0bf528SMauro Carvalho Chehab //AGC initialization 13019a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 13029a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 1); 13039a0bf528SMauro Carvalho Chehab 13049a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state); 13059a0bf528SMauro Carvalho Chehab 13069a0bf528SMauro Carvalho Chehab // wait AGC rough lock time 13079a0bf528SMauro Carvalho Chehab ret = 50; 13089a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_1; 13099a0bf528SMauro Carvalho Chehab break; 13109a0bf528SMauro Carvalho Chehab 13119a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_1: 13129a0bf528SMauro Carvalho Chehab // wait AGC accurate lock time 13139a0bf528SMauro Carvalho Chehab ret = 70; 13149a0bf528SMauro Carvalho Chehab 13159a0bf528SMauro Carvalho Chehab if (dib8000_update_lna(state)) 13169a0bf528SMauro Carvalho Chehab // wait only AGC rough lock time 13179a0bf528SMauro Carvalho Chehab ret = 50; 13189a0bf528SMauro Carvalho Chehab else 13199a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_2; 13209a0bf528SMauro Carvalho Chehab break; 13219a0bf528SMauro Carvalho Chehab 13229a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_2: 13239a0bf528SMauro Carvalho Chehab dib8000_agc_soft_split(state); 13249a0bf528SMauro Carvalho Chehab 13259a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 13269a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 0); 13279a0bf528SMauro Carvalho Chehab 13289a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP; 13299a0bf528SMauro Carvalho Chehab break; 13309a0bf528SMauro Carvalho Chehab default: 13319a0bf528SMauro Carvalho Chehab ret = dib8000_agc_soft_split(state); 13329a0bf528SMauro Carvalho Chehab break; 13339a0bf528SMauro Carvalho Chehab } 13349a0bf528SMauro Carvalho Chehab return ret; 13359a0bf528SMauro Carvalho Chehab 13369a0bf528SMauro Carvalho Chehab } 13379a0bf528SMauro Carvalho Chehab 13389a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive) 13399a0bf528SMauro Carvalho Chehab { 13409a0bf528SMauro Carvalho Chehab u16 reg; 13419a0bf528SMauro Carvalho Chehab 13429a0bf528SMauro Carvalho Chehab drive &= 0x7; 13439a0bf528SMauro Carvalho Chehab 13449a0bf528SMauro Carvalho Chehab /* drive host bus 2, 3, 4 */ 13459a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1798) & 13469a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13479a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13489a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1798, reg); 13499a0bf528SMauro Carvalho Chehab 13509a0bf528SMauro Carvalho Chehab /* drive host bus 5,6 */ 13519a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); 13529a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2); 13539a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1799, reg); 13549a0bf528SMauro Carvalho Chehab 13559a0bf528SMauro Carvalho Chehab /* drive host bus 7, 8, 9 */ 13569a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1800) & 13579a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13589a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1800, reg); 13609a0bf528SMauro Carvalho Chehab 13619a0bf528SMauro Carvalho Chehab /* drive host bus 10, 11 */ 13629a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); 13639a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2); 13649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1801, reg); 13659a0bf528SMauro Carvalho Chehab 13669a0bf528SMauro Carvalho Chehab /* drive host bus 12, 13, 14 */ 13679a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1802) & 13689a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13699a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1802, reg); 13719a0bf528SMauro Carvalho Chehab } 13729a0bf528SMauro Carvalho Chehab 13739a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout, 13749a0bf528SMauro Carvalho Chehab u32 insertExtSynchro, u32 syncSize) 13759a0bf528SMauro Carvalho Chehab { 13769a0bf528SMauro Carvalho Chehab u32 quantif = 3; 13779a0bf528SMauro Carvalho Chehab u32 nom = (insertExtSynchro * P_Kin+syncSize); 13789a0bf528SMauro Carvalho Chehab u32 denom = P_Kout; 13799a0bf528SMauro Carvalho Chehab u32 syncFreq = ((nom << quantif) / denom); 13809a0bf528SMauro Carvalho Chehab 13819a0bf528SMauro Carvalho Chehab if ((syncFreq & ((1 << quantif) - 1)) != 0) 13829a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif) + 1; 13839a0bf528SMauro Carvalho Chehab else 13849a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif); 13859a0bf528SMauro Carvalho Chehab 13869a0bf528SMauro Carvalho Chehab if (syncFreq != 0) 13879a0bf528SMauro Carvalho Chehab syncFreq = syncFreq - 1; 13889a0bf528SMauro Carvalho Chehab 13899a0bf528SMauro Carvalho Chehab return syncFreq; 13909a0bf528SMauro Carvalho Chehab } 13919a0bf528SMauro Carvalho Chehab 13929a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin, 13939a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, 13949a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize) 13959a0bf528SMauro Carvalho Chehab { 13969a0bf528SMauro Carvalho Chehab dprintk("Configure DibStream Tx"); 13979a0bf528SMauro Carvalho Chehab 13989a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 1); 13999a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1603, P_Kin); 14009a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1605, P_Kout); 14019a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1606, insertExtSynchro); 14029a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1608, synchroMode); 14039a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff); 14049a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1610, syncWord & 0xffff); 14059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1612, syncSize); 14069a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 0); 14079a0bf528SMauro Carvalho Chehab } 14089a0bf528SMauro Carvalho Chehab 14099a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin, 14109a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, 14119a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize, u32 dataOutRate) 14129a0bf528SMauro Carvalho Chehab { 14139a0bf528SMauro Carvalho Chehab u32 syncFreq; 14149a0bf528SMauro Carvalho Chehab 14159a0bf528SMauro Carvalho Chehab dprintk("Configure DibStream Rx synchroMode = %d", synchroMode); 14169a0bf528SMauro Carvalho Chehab 14179a0bf528SMauro Carvalho Chehab if ((P_Kin != 0) && (P_Kout != 0)) { 14189a0bf528SMauro Carvalho Chehab syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout, 14199a0bf528SMauro Carvalho Chehab insertExtSynchro, syncSize); 14209a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1542, syncFreq); 14219a0bf528SMauro Carvalho Chehab } 14229a0bf528SMauro Carvalho Chehab 14239a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 1); 14249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1536, P_Kin); 14259a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1537, P_Kout); 14269a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1539, synchroMode); 14279a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff); 14289a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1541, syncWord & 0xffff); 14299a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1543, syncSize); 14309a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1544, dataOutRate); 14319a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 0); 14329a0bf528SMauro Carvalho Chehab } 14339a0bf528SMauro Carvalho Chehab 14349a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff) 14359a0bf528SMauro Carvalho Chehab { 14369a0bf528SMauro Carvalho Chehab u16 reg_1287; 14379a0bf528SMauro Carvalho Chehab 14389a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287); 14399a0bf528SMauro Carvalho Chehab 14409a0bf528SMauro Carvalho Chehab switch (onoff) { 14419a0bf528SMauro Carvalho Chehab case 1: 14429a0bf528SMauro Carvalho Chehab reg_1287 &= ~(1 << 8); 14439a0bf528SMauro Carvalho Chehab break; 14449a0bf528SMauro Carvalho Chehab case 0: 14459a0bf528SMauro Carvalho Chehab reg_1287 |= (1 << 8); 14469a0bf528SMauro Carvalho Chehab break; 14479a0bf528SMauro Carvalho Chehab } 14489a0bf528SMauro Carvalho Chehab 14499a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 14509a0bf528SMauro Carvalho Chehab } 14519a0bf528SMauro Carvalho Chehab 14529a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state, 14539a0bf528SMauro Carvalho Chehab u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) 14549a0bf528SMauro Carvalho Chehab { 14559a0bf528SMauro Carvalho Chehab u16 reg_1287; 14569a0bf528SMauro Carvalho Chehab 14579a0bf528SMauro Carvalho Chehab dprintk("Enable Mpeg mux"); 14589a0bf528SMauro Carvalho Chehab 14599a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 14609a0bf528SMauro Carvalho Chehab 14619a0bf528SMauro Carvalho Chehab /* If the input mode is MPEG do not divide the serial clock */ 14629a0bf528SMauro Carvalho Chehab if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) 14639a0bf528SMauro Carvalho Chehab enSerialClkDiv2 = 0; 14649a0bf528SMauro Carvalho Chehab 14659a0bf528SMauro Carvalho Chehab reg_1287 = ((pulseWidth & 0x1f) << 3) | 14669a0bf528SMauro Carvalho Chehab ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1); 14679a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 14689a0bf528SMauro Carvalho Chehab 14699a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 1); 14709a0bf528SMauro Carvalho Chehab } 14719a0bf528SMauro Carvalho Chehab 14729a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode) 14739a0bf528SMauro Carvalho Chehab { 14749a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7); 14759a0bf528SMauro Carvalho Chehab 14769a0bf528SMauro Carvalho Chehab switch (mode) { 14779a0bf528SMauro Carvalho Chehab case MPEG_ON_DIBTX: 14789a0bf528SMauro Carvalho Chehab dprintk("SET MPEG ON DIBSTREAM TX"); 14799a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); 14809a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 9); break; 14819a0bf528SMauro Carvalho Chehab case DIV_ON_DIBTX: 14829a0bf528SMauro Carvalho Chehab dprintk("SET DIV_OUT ON DIBSTREAM TX"); 14839a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); 14849a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 8); break; 14859a0bf528SMauro Carvalho Chehab case ADC_ON_DIBTX: 14869a0bf528SMauro Carvalho Chehab dprintk("SET ADC_OUT ON DIBSTREAM TX"); 14879a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); 14889a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 7); break; 14899a0bf528SMauro Carvalho Chehab default: 14909a0bf528SMauro Carvalho Chehab break; 14919a0bf528SMauro Carvalho Chehab } 14929a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288); 14939a0bf528SMauro Carvalho Chehab } 14949a0bf528SMauro Carvalho Chehab 14959a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode) 14969a0bf528SMauro Carvalho Chehab { 14979a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4); 14989a0bf528SMauro Carvalho Chehab 14999a0bf528SMauro Carvalho Chehab switch (mode) { 15009a0bf528SMauro Carvalho Chehab case DEMOUT_ON_HOSTBUS: 15019a0bf528SMauro Carvalho Chehab dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); 15029a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 15039a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 6); 15049a0bf528SMauro Carvalho Chehab break; 15059a0bf528SMauro Carvalho Chehab case DIBTX_ON_HOSTBUS: 15069a0bf528SMauro Carvalho Chehab dprintk("SET DIBSTREAM TX ON HOST BUS"); 15079a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 15089a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 5); 15099a0bf528SMauro Carvalho Chehab break; 15109a0bf528SMauro Carvalho Chehab case MPEG_ON_HOSTBUS: 15119a0bf528SMauro Carvalho Chehab dprintk("SET MPEG MUX ON HOST BUS"); 15129a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 4); 15139a0bf528SMauro Carvalho Chehab break; 15149a0bf528SMauro Carvalho Chehab default: 15159a0bf528SMauro Carvalho Chehab break; 15169a0bf528SMauro Carvalho Chehab } 15179a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288); 15189a0bf528SMauro Carvalho Chehab } 15199a0bf528SMauro Carvalho Chehab 15209a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff) 15219a0bf528SMauro Carvalho Chehab { 15229a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 15239a0bf528SMauro Carvalho Chehab u16 reg_1287; 15249a0bf528SMauro Carvalho Chehab 15259a0bf528SMauro Carvalho Chehab switch (onoff) { 15269a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */ 15279a0bf528SMauro Carvalho Chehab dprintk("%s mode OFF : by default Enable Mpeg INPUT", 15289a0bf528SMauro Carvalho Chehab __func__); 15299a0bf528SMauro Carvalho Chehab /* outputRate = 8 */ 15309a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); 15319a0bf528SMauro Carvalho Chehab 15329a0bf528SMauro Carvalho Chehab /* Do not divide the serial clock of MPEG MUX in 15339a0bf528SMauro Carvalho Chehab SERIAL MODE in case input mode MPEG is used */ 15349a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287); 15359a0bf528SMauro Carvalho Chehab /* enSerialClkDiv2 == 1 ? */ 15369a0bf528SMauro Carvalho Chehab if ((reg_1287 & 0x1) == 1) { 15379a0bf528SMauro Carvalho Chehab /* force enSerialClkDiv2 = 0 */ 15389a0bf528SMauro Carvalho Chehab reg_1287 &= ~0x1; 15399a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 15409a0bf528SMauro Carvalho Chehab } 15419a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 1; 15429a0bf528SMauro Carvalho Chehab break; 15439a0bf528SMauro Carvalho Chehab case 1: /* both ways */ 15449a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */ 15459a0bf528SMauro Carvalho Chehab dprintk("%s ON : Enable diversity INPUT", __func__); 15469a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); 15479a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 0; 15489a0bf528SMauro Carvalho Chehab break; 15499a0bf528SMauro Carvalho Chehab } 15509a0bf528SMauro Carvalho Chehab 15519a0bf528SMauro Carvalho Chehab dib8000_set_diversity_in(state->fe[0], onoff); 15529a0bf528SMauro Carvalho Chehab return 0; 15539a0bf528SMauro Carvalho Chehab } 15549a0bf528SMauro Carvalho Chehab 15559a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) 15569a0bf528SMauro Carvalho Chehab { 15579a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 15589a0bf528SMauro Carvalho Chehab u16 outreg, smo_mode, fifo_threshold; 15599a0bf528SMauro Carvalho Chehab u8 prefer_mpeg_mux_use = 1; 15609a0bf528SMauro Carvalho Chehab int ret = 0; 15619a0bf528SMauro Carvalho Chehab 1562173a64cbSPatrick Boettcher state->output_mode = mode; 15639a0bf528SMauro Carvalho Chehab dib8096p_host_bus_drive(state, 1); 15649a0bf528SMauro Carvalho Chehab 15659a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 15669a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); 15679a0bf528SMauro Carvalho Chehab outreg = dib8000_read_word(state, 1286) & 15689a0bf528SMauro Carvalho Chehab ~((1 << 10) | (0x7 << 6) | (1 << 1)); 15699a0bf528SMauro Carvalho Chehab 15709a0bf528SMauro Carvalho Chehab switch (mode) { 15719a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: 15729a0bf528SMauro Carvalho Chehab outreg = 0; 15739a0bf528SMauro Carvalho Chehab break; 15749a0bf528SMauro Carvalho Chehab 15759a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 15769a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 15779a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux"); 15789a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 3, 1, 1); 15799a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); 15809a0bf528SMauro Carvalho Chehab } else {/* Use Smooth block */ 15819a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc"); 15829a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, 15839a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS); 15849a0bf528SMauro Carvalho Chehab outreg |= (2 << 6) | (0 << 1); 15859a0bf528SMauro Carvalho Chehab } 15869a0bf528SMauro Carvalho Chehab break; 15879a0bf528SMauro Carvalho Chehab 15889a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 15899a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 15909a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); 15919a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 2, 0, 0); 15929a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); 15939a0bf528SMauro Carvalho Chehab } else { /* Use Smooth block */ 15949a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block"); 15959a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, 15969a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS); 15979a0bf528SMauro Carvalho Chehab outreg |= (0 << 6); 15989a0bf528SMauro Carvalho Chehab } 15999a0bf528SMauro Carvalho Chehab break; 16009a0bf528SMauro Carvalho Chehab 16019a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ 16029a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block"); 16039a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 16049a0bf528SMauro Carvalho Chehab outreg |= (1 << 6); 16059a0bf528SMauro Carvalho Chehab break; 16069a0bf528SMauro Carvalho Chehab 16079a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: 16089a0bf528SMauro Carvalho Chehab /* Using Smooth block because not supported 16099a0bf528SMauro Carvalho Chehab by new Mpeg Mux bloc */ 16109a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_FIFO using Smooth block"); 16119a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 16129a0bf528SMauro Carvalho Chehab outreg |= (5 << 6); 16139a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 16149a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 16159a0bf528SMauro Carvalho Chehab break; 16169a0bf528SMauro Carvalho Chehab 16179a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 16189a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_DIVERSITY"); 16199a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, DIV_ON_DIBTX); 16209a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 16219a0bf528SMauro Carvalho Chehab break; 16229a0bf528SMauro Carvalho Chehab 16239a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 16249a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_ANALOG_ADC"); 16259a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, ADC_ON_DIBTX); 16269a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 16279a0bf528SMauro Carvalho Chehab break; 16289a0bf528SMauro Carvalho Chehab } 16299a0bf528SMauro Carvalho Chehab 16309a0bf528SMauro Carvalho Chehab if (mode != OUTMODE_HIGH_Z) 16319a0bf528SMauro Carvalho Chehab outreg |= (1<<10); 16329a0bf528SMauro Carvalho Chehab 16339a0bf528SMauro Carvalho Chehab dprintk("output_mpeg2_in_188_bytes = %d", 16349a0bf528SMauro Carvalho Chehab state->cfg.output_mpeg2_in_188_bytes); 16359a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 16369a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 16379a0bf528SMauro Carvalho Chehab 16389a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299, smo_mode); 16399a0bf528SMauro Carvalho Chehab /* synchronous fread */ 16409a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299 + 1, fifo_threshold); 16419a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 1286, outreg); 16429a0bf528SMauro Carvalho Chehab 16439a0bf528SMauro Carvalho Chehab return ret; 16449a0bf528SMauro Carvalho Chehab } 16459a0bf528SMauro Carvalho Chehab 16469a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg) 16479a0bf528SMauro Carvalho Chehab { 16489a0bf528SMauro Carvalho Chehab if (msg->buf[0] <= 15) 16499a0bf528SMauro Carvalho Chehab msg->buf[0] -= 1; 16509a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 17) 16519a0bf528SMauro Carvalho Chehab msg->buf[0] = 15; 16529a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 16) 16539a0bf528SMauro Carvalho Chehab msg->buf[0] = 17; 16549a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 19) 16559a0bf528SMauro Carvalho Chehab msg->buf[0] = 16; 16569a0bf528SMauro Carvalho Chehab else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) 16579a0bf528SMauro Carvalho Chehab msg->buf[0] -= 3; 16589a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 28) 16599a0bf528SMauro Carvalho Chehab msg->buf[0] = 23; 16609a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 99) 16619a0bf528SMauro Carvalho Chehab msg->buf[0] = 99; 16629a0bf528SMauro Carvalho Chehab else 16639a0bf528SMauro Carvalho Chehab return -EINVAL; 16649a0bf528SMauro Carvalho Chehab return 0; 16659a0bf528SMauro Carvalho Chehab } 16669a0bf528SMauro Carvalho Chehab 16679a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap, 16689a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 16699a0bf528SMauro Carvalho Chehab { 16709a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 16719a0bf528SMauro Carvalho Chehab u8 n_overflow = 1; 16729a0bf528SMauro Carvalho Chehab u16 i = 1000; 16739a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 16749a0bf528SMauro Carvalho Chehab 16759a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 16769a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; 16779a0bf528SMauro Carvalho Chehab i--; 16789a0bf528SMauro Carvalho Chehab if (i == 0) 16799a0bf528SMauro Carvalho Chehab dprintk("Tuner ITF: write busy (overflow)"); 16809a0bf528SMauro Carvalho Chehab } 16819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); 16829a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); 16839a0bf528SMauro Carvalho Chehab 16849a0bf528SMauro Carvalho Chehab return num; 16859a0bf528SMauro Carvalho Chehab } 16869a0bf528SMauro Carvalho Chehab 16879a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap, 16889a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 16899a0bf528SMauro Carvalho Chehab { 16909a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 16919a0bf528SMauro Carvalho Chehab u8 n_overflow = 1, n_empty = 1; 16929a0bf528SMauro Carvalho Chehab u16 i = 1000; 16939a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 16949a0bf528SMauro Carvalho Chehab u16 read_word; 16959a0bf528SMauro Carvalho Chehab 16969a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 16979a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; 16989a0bf528SMauro Carvalho Chehab i--; 16999a0bf528SMauro Carvalho Chehab if (i == 0) 17009a0bf528SMauro Carvalho Chehab dprintk("TunerITF: read busy (overflow)"); 17019a0bf528SMauro Carvalho Chehab } 17029a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f)); 17039a0bf528SMauro Carvalho Chehab 17049a0bf528SMauro Carvalho Chehab i = 1000; 17059a0bf528SMauro Carvalho Chehab while (n_empty == 1 && i) { 17069a0bf528SMauro Carvalho Chehab n_empty = dib8000_read_word(state, 1984)&0x1; 17079a0bf528SMauro Carvalho Chehab i--; 17089a0bf528SMauro Carvalho Chehab if (i == 0) 17099a0bf528SMauro Carvalho Chehab dprintk("TunerITF: read busy (empty)"); 17109a0bf528SMauro Carvalho Chehab } 17119a0bf528SMauro Carvalho Chehab 17129a0bf528SMauro Carvalho Chehab read_word = dib8000_read_word(state, 1987); 17139a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (read_word >> 8) & 0xff; 17149a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (read_word) & 0xff; 17159a0bf528SMauro Carvalho Chehab 17169a0bf528SMauro Carvalho Chehab return num; 17179a0bf528SMauro Carvalho Chehab } 17189a0bf528SMauro Carvalho Chehab 17199a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, 17209a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 17219a0bf528SMauro Carvalho Chehab { 17229a0bf528SMauro Carvalho Chehab if (map_addr_to_serpar_number(&msg[0]) == 0) { 17239a0bf528SMauro Carvalho Chehab if (num == 1) /* write */ 17249a0bf528SMauro Carvalho Chehab return dib8096p_tuner_write_serpar(i2c_adap, msg, 1); 17259a0bf528SMauro Carvalho Chehab else /* read */ 17269a0bf528SMauro Carvalho Chehab return dib8096p_tuner_read_serpar(i2c_adap, msg, 2); 17279a0bf528SMauro Carvalho Chehab } 17289a0bf528SMauro Carvalho Chehab return num; 17299a0bf528SMauro Carvalho Chehab } 17309a0bf528SMauro Carvalho Chehab 17319a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap, 17329a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num, u16 apb_address) 17339a0bf528SMauro Carvalho Chehab { 17349a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 17359a0bf528SMauro Carvalho Chehab u16 word; 17369a0bf528SMauro Carvalho Chehab 17379a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 17389a0bf528SMauro Carvalho Chehab dib8000_write_word(state, apb_address, 17399a0bf528SMauro Carvalho Chehab ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); 17409a0bf528SMauro Carvalho Chehab } else { 17419a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, apb_address); 17429a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 17439a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 17449a0bf528SMauro Carvalho Chehab } 17459a0bf528SMauro Carvalho Chehab return num; 17469a0bf528SMauro Carvalho Chehab } 17479a0bf528SMauro Carvalho Chehab 17489a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap, 17499a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 17509a0bf528SMauro Carvalho Chehab { 17519a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 17529a0bf528SMauro Carvalho Chehab u16 apb_address = 0, word; 17539a0bf528SMauro Carvalho Chehab int i = 0; 17549a0bf528SMauro Carvalho Chehab 17559a0bf528SMauro Carvalho Chehab switch (msg[0].buf[0]) { 17569a0bf528SMauro Carvalho Chehab case 0x12: 17579a0bf528SMauro Carvalho Chehab apb_address = 1920; 17589a0bf528SMauro Carvalho Chehab break; 17599a0bf528SMauro Carvalho Chehab case 0x14: 17609a0bf528SMauro Carvalho Chehab apb_address = 1921; 17619a0bf528SMauro Carvalho Chehab break; 17629a0bf528SMauro Carvalho Chehab case 0x24: 17639a0bf528SMauro Carvalho Chehab apb_address = 1922; 17649a0bf528SMauro Carvalho Chehab break; 17659a0bf528SMauro Carvalho Chehab case 0x1a: 17669a0bf528SMauro Carvalho Chehab apb_address = 1923; 17679a0bf528SMauro Carvalho Chehab break; 17689a0bf528SMauro Carvalho Chehab case 0x22: 17699a0bf528SMauro Carvalho Chehab apb_address = 1924; 17709a0bf528SMauro Carvalho Chehab break; 17719a0bf528SMauro Carvalho Chehab case 0x33: 17729a0bf528SMauro Carvalho Chehab apb_address = 1926; 17739a0bf528SMauro Carvalho Chehab break; 17749a0bf528SMauro Carvalho Chehab case 0x34: 17759a0bf528SMauro Carvalho Chehab apb_address = 1927; 17769a0bf528SMauro Carvalho Chehab break; 17779a0bf528SMauro Carvalho Chehab case 0x35: 17789a0bf528SMauro Carvalho Chehab apb_address = 1928; 17799a0bf528SMauro Carvalho Chehab break; 17809a0bf528SMauro Carvalho Chehab case 0x36: 17819a0bf528SMauro Carvalho Chehab apb_address = 1929; 17829a0bf528SMauro Carvalho Chehab break; 17839a0bf528SMauro Carvalho Chehab case 0x37: 17849a0bf528SMauro Carvalho Chehab apb_address = 1930; 17859a0bf528SMauro Carvalho Chehab break; 17869a0bf528SMauro Carvalho Chehab case 0x38: 17879a0bf528SMauro Carvalho Chehab apb_address = 1931; 17889a0bf528SMauro Carvalho Chehab break; 17899a0bf528SMauro Carvalho Chehab case 0x39: 17909a0bf528SMauro Carvalho Chehab apb_address = 1932; 17919a0bf528SMauro Carvalho Chehab break; 17929a0bf528SMauro Carvalho Chehab case 0x2a: 17939a0bf528SMauro Carvalho Chehab apb_address = 1935; 17949a0bf528SMauro Carvalho Chehab break; 17959a0bf528SMauro Carvalho Chehab case 0x2b: 17969a0bf528SMauro Carvalho Chehab apb_address = 1936; 17979a0bf528SMauro Carvalho Chehab break; 17989a0bf528SMauro Carvalho Chehab case 0x2c: 17999a0bf528SMauro Carvalho Chehab apb_address = 1937; 18009a0bf528SMauro Carvalho Chehab break; 18019a0bf528SMauro Carvalho Chehab case 0x2d: 18029a0bf528SMauro Carvalho Chehab apb_address = 1938; 18039a0bf528SMauro Carvalho Chehab break; 18049a0bf528SMauro Carvalho Chehab case 0x2e: 18059a0bf528SMauro Carvalho Chehab apb_address = 1939; 18069a0bf528SMauro Carvalho Chehab break; 18079a0bf528SMauro Carvalho Chehab case 0x2f: 18089a0bf528SMauro Carvalho Chehab apb_address = 1940; 18099a0bf528SMauro Carvalho Chehab break; 18109a0bf528SMauro Carvalho Chehab case 0x30: 18119a0bf528SMauro Carvalho Chehab apb_address = 1941; 18129a0bf528SMauro Carvalho Chehab break; 18139a0bf528SMauro Carvalho Chehab case 0x31: 18149a0bf528SMauro Carvalho Chehab apb_address = 1942; 18159a0bf528SMauro Carvalho Chehab break; 18169a0bf528SMauro Carvalho Chehab case 0x32: 18179a0bf528SMauro Carvalho Chehab apb_address = 1943; 18189a0bf528SMauro Carvalho Chehab break; 18199a0bf528SMauro Carvalho Chehab case 0x3e: 18209a0bf528SMauro Carvalho Chehab apb_address = 1944; 18219a0bf528SMauro Carvalho Chehab break; 18229a0bf528SMauro Carvalho Chehab case 0x3f: 18239a0bf528SMauro Carvalho Chehab apb_address = 1945; 18249a0bf528SMauro Carvalho Chehab break; 18259a0bf528SMauro Carvalho Chehab case 0x40: 18269a0bf528SMauro Carvalho Chehab apb_address = 1948; 18279a0bf528SMauro Carvalho Chehab break; 18289a0bf528SMauro Carvalho Chehab case 0x25: 18299a0bf528SMauro Carvalho Chehab apb_address = 936; 18309a0bf528SMauro Carvalho Chehab break; 18319a0bf528SMauro Carvalho Chehab case 0x26: 18329a0bf528SMauro Carvalho Chehab apb_address = 937; 18339a0bf528SMauro Carvalho Chehab break; 18349a0bf528SMauro Carvalho Chehab case 0x27: 18359a0bf528SMauro Carvalho Chehab apb_address = 938; 18369a0bf528SMauro Carvalho Chehab break; 18379a0bf528SMauro Carvalho Chehab case 0x28: 18389a0bf528SMauro Carvalho Chehab apb_address = 939; 18399a0bf528SMauro Carvalho Chehab break; 18409a0bf528SMauro Carvalho Chehab case 0x1d: 18419a0bf528SMauro Carvalho Chehab /* get sad sel request */ 18429a0bf528SMauro Carvalho Chehab i = ((dib8000_read_word(state, 921) >> 12)&0x3); 18439a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, 924+i); 18449a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 18459a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 18469a0bf528SMauro Carvalho Chehab return num; 18479a0bf528SMauro Carvalho Chehab case 0x1f: 18489a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 18499a0bf528SMauro Carvalho Chehab word = (u16) ((msg[0].buf[1] << 8) | 18509a0bf528SMauro Carvalho Chehab msg[0].buf[2]); 18519a0bf528SMauro Carvalho Chehab /* in the VGAMODE Sel are located on bit 0/1 */ 18529a0bf528SMauro Carvalho Chehab word &= 0x3; 18539a0bf528SMauro Carvalho Chehab word = (dib8000_read_word(state, 921) & 18549a0bf528SMauro Carvalho Chehab ~(3<<12)) | (word<<12); 18559a0bf528SMauro Carvalho Chehab /* Set the proper input */ 18569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, word); 18579a0bf528SMauro Carvalho Chehab return num; 18589a0bf528SMauro Carvalho Chehab } 18599a0bf528SMauro Carvalho Chehab } 18609a0bf528SMauro Carvalho Chehab 18619a0bf528SMauro Carvalho Chehab if (apb_address != 0) /* R/W acces via APB */ 18629a0bf528SMauro Carvalho Chehab return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address); 18639a0bf528SMauro Carvalho Chehab else /* R/W access via SERPAR */ 18649a0bf528SMauro Carvalho Chehab return dib8096p_tuner_rw_serpar(i2c_adap, msg, num); 18659a0bf528SMauro Carvalho Chehab 18669a0bf528SMauro Carvalho Chehab return 0; 18679a0bf528SMauro Carvalho Chehab } 18689a0bf528SMauro Carvalho Chehab 18699a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter) 18709a0bf528SMauro Carvalho Chehab { 18719a0bf528SMauro Carvalho Chehab return I2C_FUNC_I2C; 18729a0bf528SMauro Carvalho Chehab } 18739a0bf528SMauro Carvalho Chehab 18749a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = { 18759a0bf528SMauro Carvalho Chehab .master_xfer = dib8096p_tuner_xfer, 18769a0bf528SMauro Carvalho Chehab .functionality = dib8096p_i2c_func, 18779a0bf528SMauro Carvalho Chehab }; 18789a0bf528SMauro Carvalho Chehab 1879d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) 18809a0bf528SMauro Carvalho Chehab { 18819a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 18829a0bf528SMauro Carvalho Chehab return &st->dib8096p_tuner_adap; 18839a0bf528SMauro Carvalho Chehab } 18849a0bf528SMauro Carvalho Chehab 1885d44913c1SMauro Carvalho Chehab static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) 18869a0bf528SMauro Carvalho Chehab { 18879a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 18889a0bf528SMauro Carvalho Chehab u16 en_cur_state; 18899a0bf528SMauro Carvalho Chehab 18909a0bf528SMauro Carvalho Chehab dprintk("sleep dib8096p: %d", onoff); 18919a0bf528SMauro Carvalho Chehab 18929a0bf528SMauro Carvalho Chehab en_cur_state = dib8000_read_word(state, 1922); 18939a0bf528SMauro Carvalho Chehab 18949a0bf528SMauro Carvalho Chehab /* LNAs and MIX are ON and therefore it is a valid configuration */ 18959a0bf528SMauro Carvalho Chehab if (en_cur_state > 0xff) 18969a0bf528SMauro Carvalho Chehab state->tuner_enable = en_cur_state ; 18979a0bf528SMauro Carvalho Chehab 18989a0bf528SMauro Carvalho Chehab if (onoff) 18999a0bf528SMauro Carvalho Chehab en_cur_state &= 0x00ff; 19009a0bf528SMauro Carvalho Chehab else { 19019a0bf528SMauro Carvalho Chehab if (state->tuner_enable != 0) 19029a0bf528SMauro Carvalho Chehab en_cur_state = state->tuner_enable; 19039a0bf528SMauro Carvalho Chehab } 19049a0bf528SMauro Carvalho Chehab 19059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1922, en_cur_state); 19069a0bf528SMauro Carvalho Chehab 19079a0bf528SMauro Carvalho Chehab return 0; 19089a0bf528SMauro Carvalho Chehab } 19099a0bf528SMauro Carvalho Chehab 19109a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = 19119a0bf528SMauro Carvalho Chehab { 19129a0bf528SMauro Carvalho Chehab 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 19139a0bf528SMauro Carvalho Chehab }; 19149a0bf528SMauro Carvalho Chehab 1915d44913c1SMauro Carvalho Chehab static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) 19169a0bf528SMauro Carvalho Chehab { 19179a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 19189a0bf528SMauro Carvalho Chehab u32 ix = 0, tmp_val = 0, exp = 0, mant = 0; 19199a0bf528SMauro Carvalho Chehab s32 val; 19209a0bf528SMauro Carvalho Chehab 19219a0bf528SMauro Carvalho Chehab val = dib8000_read32(state, 384); 19229a0bf528SMauro Carvalho Chehab if (mode) { 19239a0bf528SMauro Carvalho Chehab tmp_val = val; 19249a0bf528SMauro Carvalho Chehab while (tmp_val >>= 1) 19259a0bf528SMauro Carvalho Chehab exp++; 19269a0bf528SMauro Carvalho Chehab mant = (val * 1000 / (1<<exp)); 19279a0bf528SMauro Carvalho Chehab ix = (u8)((mant-1000)/100); /* index of the LUT */ 19289a0bf528SMauro Carvalho Chehab val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); 19299a0bf528SMauro Carvalho Chehab val = (val*256)/1000; 19309a0bf528SMauro Carvalho Chehab } 19319a0bf528SMauro Carvalho Chehab return val; 19329a0bf528SMauro Carvalho Chehab } 19339a0bf528SMauro Carvalho Chehab 1934d44913c1SMauro Carvalho Chehab static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) 19359a0bf528SMauro Carvalho Chehab { 19369a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 19379a0bf528SMauro Carvalho Chehab int val = 0; 19389a0bf528SMauro Carvalho Chehab 19399a0bf528SMauro Carvalho Chehab switch (IQ) { 19409a0bf528SMauro Carvalho Chehab case 1: 19419a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 403); 19429a0bf528SMauro Carvalho Chehab break; 19439a0bf528SMauro Carvalho Chehab case 0: 19449a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 404); 19459a0bf528SMauro Carvalho Chehab break; 19469a0bf528SMauro Carvalho Chehab } 19479a0bf528SMauro Carvalho Chehab if (val & 0x200) 19489a0bf528SMauro Carvalho Chehab val -= 1024; 19499a0bf528SMauro Carvalho Chehab 19509a0bf528SMauro Carvalho Chehab return val; 19519a0bf528SMauro Carvalho Chehab } 19529a0bf528SMauro Carvalho Chehab 19539a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state) 19549a0bf528SMauro Carvalho Chehab { 19559a0bf528SMauro Carvalho Chehab u32 timf = state->timf = dib8000_read32(state, 435); 19569a0bf528SMauro Carvalho Chehab 19579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) (timf >> 16)); 19589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) (timf & 0xffff)); 19599a0bf528SMauro Carvalho Chehab dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); 19609a0bf528SMauro Carvalho Chehab } 19619a0bf528SMauro Carvalho Chehab 1962d44913c1SMauro Carvalho Chehab static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) 19639a0bf528SMauro Carvalho Chehab { 19649a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 19659a0bf528SMauro Carvalho Chehab 19669a0bf528SMauro Carvalho Chehab switch (op) { 19679a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_SET: 19689a0bf528SMauro Carvalho Chehab state->timf = timf; 19699a0bf528SMauro Carvalho Chehab break; 19709a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_UPDATE: 19719a0bf528SMauro Carvalho Chehab dib8000_update_timf(state); 19729a0bf528SMauro Carvalho Chehab break; 19739a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_GET: 19749a0bf528SMauro Carvalho Chehab break; 19759a0bf528SMauro Carvalho Chehab } 19769a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(state->fe[0], 6000); 19779a0bf528SMauro Carvalho Chehab 19789a0bf528SMauro Carvalho Chehab return state->timf; 19799a0bf528SMauro Carvalho Chehab } 19809a0bf528SMauro Carvalho Chehab 19819a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = { 19829a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117, 19839a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117, 19849a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117, 19859a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117, 19869a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117, 19879a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117, 19889a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117, 19899a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117, 19909a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117, 19919a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117, 19929a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117 19939a0bf528SMauro 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; 2128173a64cbSPatrick Boettcher dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", 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 2354173a64cbSPatrick Boettcher /* P_mode */ 2355173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (seq << 4)); 2356173a64cbSPatrick Boettcher 2357173a64cbSPatrick Boettcher /* init mode */ 2358173a64cbSPatrick Boettcher state->mode = fft_to_mode(state); 2359173a64cbSPatrick Boettcher 2360173a64cbSPatrick Boettcher /* set guard */ 2361173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 1); 2362c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3)); 2363173a64cbSPatrick Boettcher 2364c82056d0SMauro 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)); 2365173a64cbSPatrick Boettcher 2366173a64cbSPatrick Boettcher /* signal optimization parameter */ 2367c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) { 2368c82056d0SMauro Carvalho Chehab state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0]; 2369173a64cbSPatrick Boettcher for (i = 1; i < 3; i++) 2370c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; 2371173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++) 2372173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i+1]; 2373173a64cbSPatrick Boettcher } else { 2374173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) 2375c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; 2376173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++) 2377173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i]; 2378173a64cbSPatrick Boettcher } 2379173a64cbSPatrick Boettcher 2380173a64cbSPatrick Boettcher if (state->seg_diff_mask) 2381173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); 2382173a64cbSPatrick Boettcher else 2383173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */ 2384173a64cbSPatrick Boettcher 2385173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) 2386173a64cbSPatrick Boettcher max_constellation = dib8000_set_layer(state, i, max_constellation); 2387173a64cbSPatrick Boettcher if (autosearching == 0) { 2388c82056d0SMauro Carvalho Chehab state->layer_b_nb_seg = c->layer[1].segment_count; 2389c82056d0SMauro Carvalho Chehab state->layer_c_nb_seg = c->layer[2].segment_count; 2390173a64cbSPatrick Boettcher } 2391173a64cbSPatrick Boettcher 2392173a64cbSPatrick Boettcher /* WRITE: Mode & Diff mask */ 2393173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask); 2394173a64cbSPatrick Boettcher 2395173a64cbSPatrick Boettcher state->differential_constellation = (state->seg_diff_mask != 0); 23969a0bf528SMauro Carvalho Chehab 23979a0bf528SMauro Carvalho Chehab /* channel estimation fine configuration */ 2398173a64cbSPatrick Boettcher ana_gain = dib8000_adp_fine_tune(state, max_constellation); 23999a0bf528SMauro Carvalho Chehab 2400173a64cbSPatrick Boettcher /* update ana_gain depending on max constellation */ 2401173a64cbSPatrick Boettcher dib8000_update_ana_gain(state, ana_gain); 24029a0bf528SMauro Carvalho Chehab 2403173a64cbSPatrick Boettcher /* ---- ANA_FE ---- */ 2404c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) /* 3-segments */ 2405173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg); 2406173a64cbSPatrick Boettcher else 2407173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */ 2408173a64cbSPatrick Boettcher 2409173a64cbSPatrick Boettcher /* TSB or ISDBT ? apply it now */ 2410c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2411173a64cbSPatrick Boettcher dib8000_set_sb_channel(state); 2412746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_subchannel < 14) 2413c82056d0SMauro Carvalho Chehab init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel); 2414173a64cbSPatrick Boettcher else 2415173a64cbSPatrick Boettcher init_prbs = 0; 2416173a64cbSPatrick Boettcher } else { 2417173a64cbSPatrick Boettcher dib8000_set_13seg_channel(state); 2418173a64cbSPatrick Boettcher init_prbs = 0xfff; 2419173a64cbSPatrick Boettcher } 24209a0bf528SMauro Carvalho Chehab 2421173a64cbSPatrick Boettcher /* SMALL */ 2422173a64cbSPatrick Boettcher dib8000_small_fine_tune(state); 24239a0bf528SMauro Carvalho Chehab 2424173a64cbSPatrick Boettcher dib8000_set_subchannel_prbs(state, init_prbs); 2425173a64cbSPatrick Boettcher 2426173a64cbSPatrick Boettcher /* ---- CHAN_BLK ---- */ 24279a0bf528SMauro Carvalho Chehab for (i = 0; i < 13; i++) { 2428173a64cbSPatrick Boettcher if ((((~state->seg_diff_mask) >> i) & 1) == 1) { 2429173a64cbSPatrick Boettcher p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0)); 2430173a64cbSPatrick Boettcher p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0)); 24319a0bf528SMauro Carvalho Chehab } 24329a0bf528SMauro Carvalho Chehab } 2433173a64cbSPatrick Boettcher dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */ 2434173a64cbSPatrick Boettcher dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */ 2435173a64cbSPatrick Boettcher /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */ 24369a0bf528SMauro Carvalho Chehab 2437173a64cbSPatrick Boettcher dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */ 2438173a64cbSPatrick Boettcher dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */ 2439173a64cbSPatrick Boettcher dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */ 2440173a64cbSPatrick Boettcher 2441173a64cbSPatrick Boettcher if (!autosearching) 2442173a64cbSPatrick Boettcher dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ 2443173a64cbSPatrick Boettcher else 2444173a64cbSPatrick Boettcher dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */ 2445173a64cbSPatrick Boettcher 2446173a64cbSPatrick Boettcher dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */ 2447173a64cbSPatrick Boettcher dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */ 2448173a64cbSPatrick Boettcher 2449173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ 2450173a64cbSPatrick Boettcher 2451173a64cbSPatrick Boettcher /* ---- TMCC ---- */ 24529a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) 2453c82056d0SMauro Carvalho Chehab tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ; 2454173a64cbSPatrick Boettcher 2455173a64cbSPatrick Boettcher /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */ 2456173a64cbSPatrick Boettcher /* Threshold is set at 1/4 of max power. */ 24579a0bf528SMauro Carvalho Chehab tmcc_pow *= (1 << (9-2)); 2458173a64cbSPatrick Boettcher dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */ 2459173a64cbSPatrick Boettcher dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */ 2460173a64cbSPatrick Boettcher dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */ 2461173a64cbSPatrick Boettcher /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */ 24629a0bf528SMauro Carvalho Chehab 2463173a64cbSPatrick Boettcher /* ---- PHA3 ---- */ 24649a0bf528SMauro Carvalho Chehab if (state->isdbt_cfg_loaded == 0) 24659a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */ 24669a0bf528SMauro Carvalho Chehab 24679a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0; 2468173a64cbSPatrick Boettcher } 24699a0bf528SMauro Carvalho Chehab 24706f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, 24716f7ee06fSMauro Carvalho Chehab u32 wait0_ms, u32 wait1_ms, u32 wait2_ms) 2472173a64cbSPatrick Boettcher { 247313122f98SMauro Carvalho Chehab u32 value = 0; /* P_search_end0 wait time */ 2474173a64cbSPatrick Boettcher u16 reg = 11; /* P_search_end0 start addr */ 2475173a64cbSPatrick Boettcher 2476173a64cbSPatrick Boettcher for (reg = 11; reg < 16; reg += 2) { 2477173a64cbSPatrick Boettcher if (reg == 11) { 2478173a64cbSPatrick Boettcher if (state->revision == 0x8090) 247913122f98SMauro Carvalho Chehab value = internal * wait1_ms; 2480173a64cbSPatrick Boettcher else 248113122f98SMauro Carvalho Chehab value = internal * wait0_ms; 2482173a64cbSPatrick Boettcher } else if (reg == 13) 248313122f98SMauro Carvalho Chehab value = internal * wait1_ms; 2484173a64cbSPatrick Boettcher else if (reg == 15) 248513122f98SMauro Carvalho Chehab value = internal * wait2_ms; 2486173a64cbSPatrick Boettcher dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff)); 2487173a64cbSPatrick Boettcher dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff)); 2488173a64cbSPatrick Boettcher } 2489173a64cbSPatrick Boettcher return value; 24909a0bf528SMauro Carvalho Chehab } 24919a0bf528SMauro Carvalho Chehab 24929a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe) 24939a0bf528SMauro Carvalho Chehab { 24949a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 2495c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2496173a64cbSPatrick Boettcher u8 slist = 0; 2497173a64cbSPatrick Boettcher u32 value, internal = state->cfg.pll->internal; 24989a0bf528SMauro Carvalho Chehab 2499173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2500173a64cbSPatrick Boettcher internal = dib8000_read32(state, 23) / 1000; 25019a0bf528SMauro Carvalho Chehab 2502d67350f8SOlivier Grenie if ((state->revision >= 0x8002) && 2503d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) { 2504173a64cbSPatrick Boettcher dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ 2505173a64cbSPatrick Boettcher dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ 2506173a64cbSPatrick Boettcher 2507173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */ 2508173a64cbSPatrick Boettcher dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */ 2509173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */ 2510173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */ 2511173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */ 2512173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */ 2513173a64cbSPatrick Boettcher 2514173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2515173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2516173a64cbSPatrick Boettcher else 2517173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2518173a64cbSPatrick Boettcher 2519173a64cbSPatrick Boettcher dib8000_write_word(state, 17, 0); 2520173a64cbSPatrick Boettcher dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */ 2521173a64cbSPatrick Boettcher dib8000_write_word(state, 19, 0); 2522173a64cbSPatrick Boettcher dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */ 2523173a64cbSPatrick Boettcher dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */ 2524173a64cbSPatrick Boettcher dib8000_write_word(state, 22, value & 0xffff); 2525173a64cbSPatrick Boettcher 2526173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2527173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */ 2528173a64cbSPatrick Boettcher else 2529173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */ 2530173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */ 2531173a64cbSPatrick Boettcher 2532173a64cbSPatrick Boettcher /* P_search_param_select = (1 | 1<<4 | 1 << 8) */ 2533173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0); 2534173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0x111); 2535173a64cbSPatrick Boettcher 2536173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ 2537173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ 2538173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ 2539d67350f8SOlivier Grenie } else if ((state->revision >= 0x8002) && 2540d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_GUARD)) { 2541c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 2542c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 2543c82056d0SMauro Carvalho Chehab c->inversion = 0; 2544c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64; 2545c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3; 2546c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0; 2547c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 25489a0bf528SMauro Carvalho Chehab 2549173a64cbSPatrick Boettcher slist = 16; 2550c82056d0SMauro Carvalho Chehab c->transmission_mode = state->found_nfft; 2551173a64cbSPatrick Boettcher 2552173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1); 2553173a64cbSPatrick Boettcher 2554173a64cbSPatrick Boettcher /* set lock_mask values */ 2555173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0x4); 2556173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2557173a64cbSPatrick Boettcher dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */ 2558173a64cbSPatrick Boettcher else 2559173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0x8); 2560173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0x1000); 2561173a64cbSPatrick Boettcher 2562173a64cbSPatrick Boettcher /* set lock_mask wait time values */ 2563173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2564173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2565173a64cbSPatrick Boettcher else 2566173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2567173a64cbSPatrick Boettcher 2568173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */ 2569173a64cbSPatrick Boettcher 2570173a64cbSPatrick Boettcher /* P_search_param_select = 0xf; look for the 4 different guard intervals */ 2571173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0); 2572173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0xf); 2573173a64cbSPatrick Boettcher 2574173a64cbSPatrick Boettcher value = dib8000_read_word(state, 0); 2575173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)((1 << 15) | value)); 2576173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ 2577173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)value); 2578173a64cbSPatrick Boettcher } else { 2579c82056d0SMauro Carvalho Chehab c->inversion = 0; 2580c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64; 2581c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3; 2582c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0; 2583c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 2584c82056d0SMauro Carvalho Chehab if (!c->isdbt_sb_mode) 2585c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 2586173a64cbSPatrick Boettcher 2587173a64cbSPatrick Boettcher /* choose the right list, in sb, always do everything */ 2588c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 25899a0bf528SMauro Carvalho Chehab slist = 7; 25909a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); 25919a0bf528SMauro Carvalho Chehab } else { 2592c82056d0SMauro Carvalho Chehab if (c->guard_interval == GUARD_INTERVAL_AUTO) { 2593c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 2594c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 2595c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 25969a0bf528SMauro Carvalho Chehab slist = 7; 2597173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */ 2598173a64cbSPatrick Boettcher } else { 2599c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 26009a0bf528SMauro Carvalho Chehab slist = 3; 2601173a64cbSPatrick Boettcher } 26029a0bf528SMauro Carvalho Chehab } else { 2603c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 2604c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 26059a0bf528SMauro Carvalho Chehab slist = 2; 2606173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */ 26079a0bf528SMauro Carvalho Chehab } else 26089a0bf528SMauro Carvalho Chehab slist = 0; 26099a0bf528SMauro Carvalho Chehab } 2610173a64cbSPatrick Boettcher } 2611173a64cbSPatrick Boettcher dprintk("Using list for autosearch : %d", slist); 26129a0bf528SMauro Carvalho Chehab 2613173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1); 26149a0bf528SMauro Carvalho Chehab 2615173a64cbSPatrick Boettcher /* set lock_mask values */ 26169a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 6, 0x4); 2617173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2618173a64cbSPatrick Boettcher dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10)); 2619173a64cbSPatrick Boettcher else 26209a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 7, 0x8); 26219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 8, 0x1000); 26229a0bf528SMauro Carvalho Chehab 2623173a64cbSPatrick Boettcher /* set lock_mask wait time values */ 2624173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2625173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2626173a64cbSPatrick Boettcher else 2627173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 26289a0bf528SMauro Carvalho Chehab 26299a0bf528SMauro Carvalho Chehab value = dib8000_read_word(state, 0); 26309a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)((1 << 15) | value)); 2631173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ 26329a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)value); 26339a0bf528SMauro Carvalho Chehab } 26349a0bf528SMauro Carvalho Chehab return 0; 26359a0bf528SMauro Carvalho Chehab } 26369a0bf528SMauro Carvalho Chehab 26379a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe) 26389a0bf528SMauro Carvalho Chehab { 26399a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 26409a0bf528SMauro Carvalho Chehab u16 irq_pending = dib8000_read_word(state, 1284); 26419a0bf528SMauro Carvalho Chehab 2642d67350f8SOlivier Grenie if ((state->revision >= 0x8002) && 2643d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) { 2644173a64cbSPatrick Boettcher if (irq_pending & 0x1) { 2645173a64cbSPatrick Boettcher dprintk("dib8000_autosearch_irq: max correlation result available"); 2646173a64cbSPatrick Boettcher return 3; 2647173a64cbSPatrick Boettcher } 2648173a64cbSPatrick Boettcher } else { 2649173a64cbSPatrick Boettcher if (irq_pending & 0x1) { /* failed */ 26509a0bf528SMauro Carvalho Chehab dprintk("dib8000_autosearch_irq failed"); 26519a0bf528SMauro Carvalho Chehab return 1; 26529a0bf528SMauro Carvalho Chehab } 26539a0bf528SMauro Carvalho Chehab 2654173a64cbSPatrick Boettcher if (irq_pending & 0x2) { /* succeeded */ 26559a0bf528SMauro Carvalho Chehab dprintk("dib8000_autosearch_irq succeeded"); 26569a0bf528SMauro Carvalho Chehab return 2; 26579a0bf528SMauro Carvalho Chehab } 2658173a64cbSPatrick Boettcher } 26599a0bf528SMauro Carvalho Chehab 26609a0bf528SMauro Carvalho Chehab return 0; // still pending 26619a0bf528SMauro Carvalho Chehab } 26629a0bf528SMauro Carvalho Chehab 2663173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff) 2664173a64cbSPatrick Boettcher { 2665173a64cbSPatrick Boettcher u16 tmp; 2666173a64cbSPatrick Boettcher 2667173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 771); 2668173a64cbSPatrick Boettcher if (onoff) /* start P_restart_chd : channel_decoder */ 2669173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp & 0xfffd); 2670173a64cbSPatrick Boettcher else /* stop P_restart_chd : channel_decoder */ 2671173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp | (1<<1)); 2672173a64cbSPatrick Boettcher } 2673173a64cbSPatrick Boettcher 2674173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) 2675173a64cbSPatrick Boettcher { 2676173a64cbSPatrick Boettcher s16 unit_khz_dds_val; 2677173a64cbSPatrick Boettcher u32 abs_offset_khz = ABS(offset_khz); 2678173a64cbSPatrick Boettcher u32 dds = state->cfg.pll->ifreq & 0x1ffffff; 2679173a64cbSPatrick Boettcher u8 invert = !!(state->cfg.pll->ifreq & (1 << 25)); 2680173a64cbSPatrick Boettcher u8 ratio; 2681173a64cbSPatrick Boettcher 2682173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 2683173a64cbSPatrick Boettcher ratio = 4; 2684173a64cbSPatrick Boettcher unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000); 2685173a64cbSPatrick Boettcher if (offset_khz < 0) 2686173a64cbSPatrick Boettcher dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val); 2687173a64cbSPatrick Boettcher else 2688173a64cbSPatrick Boettcher dds = (abs_offset_khz * unit_khz_dds_val); 2689173a64cbSPatrick Boettcher 2690173a64cbSPatrick Boettcher if (invert) 2691173a64cbSPatrick Boettcher dds = (1<<26) - dds; 2692173a64cbSPatrick Boettcher } else { 2693173a64cbSPatrick Boettcher ratio = 2; 2694173a64cbSPatrick Boettcher unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal); 2695173a64cbSPatrick Boettcher 2696173a64cbSPatrick Boettcher if (offset_khz < 0) 2697173a64cbSPatrick Boettcher unit_khz_dds_val *= -1; 2698173a64cbSPatrick Boettcher 2699173a64cbSPatrick Boettcher /* IF tuner */ 2700173a64cbSPatrick Boettcher if (invert) 2701173a64cbSPatrick Boettcher dds -= abs_offset_khz * unit_khz_dds_val; 2702173a64cbSPatrick Boettcher else 2703173a64cbSPatrick Boettcher dds += abs_offset_khz * unit_khz_dds_val; 2704173a64cbSPatrick Boettcher } 2705173a64cbSPatrick Boettcher 2706173a64cbSPatrick Boettcher dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val); 2707173a64cbSPatrick Boettcher 2708173a64cbSPatrick Boettcher if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) { 2709173a64cbSPatrick Boettcher /* Max dds offset is the half of the demod freq */ 2710173a64cbSPatrick Boettcher dib8000_write_word(state, 26, invert); 2711173a64cbSPatrick Boettcher dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff); 2712173a64cbSPatrick Boettcher dib8000_write_word(state, 28, (u16)(dds & 0xffff)); 2713173a64cbSPatrick Boettcher } 2714173a64cbSPatrick Boettcher } 2715173a64cbSPatrick Boettcher 2716173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state) 2717173a64cbSPatrick Boettcher { 2718c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2719173a64cbSPatrick Boettcher int i; 2720173a64cbSPatrick Boettcher u32 current_rf; 2721173a64cbSPatrick Boettcher int total_dds_offset_khz; 2722173a64cbSPatrick Boettcher 2723173a64cbSPatrick Boettcher if (state->fe[0]->ops.tuner_ops.get_frequency) 2724173a64cbSPatrick Boettcher state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], ¤t_rf); 2725173a64cbSPatrick Boettcher else 2726c82056d0SMauro Carvalho Chehab current_rf = c->frequency; 2727173a64cbSPatrick Boettcher current_rf /= 1000; 2728c82056d0SMauro Carvalho Chehab total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000; 2729173a64cbSPatrick Boettcher 2730c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2731c82056d0SMauro Carvalho Chehab state->subchannel = c->isdbt_sb_subchannel; 2732173a64cbSPatrick Boettcher 2733173a64cbSPatrick Boettcher i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */ 2734c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 26, c->inversion ^ i); 2735173a64cbSPatrick Boettcher 2736173a64cbSPatrick Boettcher if (state->cfg.pll->ifreq == 0) { /* low if tuner */ 2737c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0) 2738173a64cbSPatrick Boettcher dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); 2739173a64cbSPatrick Boettcher } else { 2740c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0) 2741173a64cbSPatrick Boettcher total_dds_offset_khz *= -1; 2742173a64cbSPatrick Boettcher } 2743173a64cbSPatrick Boettcher } 2744173a64cbSPatrick Boettcher 2745c82056d0SMauro Carvalho Chehab dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz); 2746173a64cbSPatrick Boettcher 2747173a64cbSPatrick Boettcher /* apply dds offset now */ 2748173a64cbSPatrick Boettcher dib8000_set_dds(state, total_dds_offset_khz); 2749173a64cbSPatrick Boettcher } 2750173a64cbSPatrick Boettcher 2751173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 }; 27526f7ee06fSMauro Carvalho Chehab 27536f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state) 2754173a64cbSPatrick Boettcher { 2755c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2756173a64cbSPatrick Boettcher u16 i; 2757173a64cbSPatrick Boettcher 2758c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2759173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2760173a64cbSPatrick Boettcher i = 0; 2761173a64cbSPatrick Boettcher break; 2762173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K: 2763173a64cbSPatrick Boettcher i = 2; 2764173a64cbSPatrick Boettcher break; 2765173a64cbSPatrick Boettcher default: 2766173a64cbSPatrick Boettcher case TRANSMISSION_MODE_AUTO: 2767173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2768173a64cbSPatrick Boettcher i = 1; 2769173a64cbSPatrick Boettcher break; 2770173a64cbSPatrick Boettcher } 2771173a64cbSPatrick Boettcher 2772c82056d0SMauro Carvalho Chehab return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1; 2773173a64cbSPatrick Boettcher } 2774173a64cbSPatrick Boettcher 2775173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step) 2776173a64cbSPatrick Boettcher { 2777c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2778173a64cbSPatrick Boettcher u16 reg_32 = 0, reg_37 = 0; 2779173a64cbSPatrick Boettcher 2780173a64cbSPatrick Boettcher switch (loop_step) { 2781173a64cbSPatrick Boettcher case LOOP_TUNE_1: 2782c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2783c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { 2784173a64cbSPatrick Boettcher reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */ 2785173a64cbSPatrick 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) */ 2786173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2787173a64cbSPatrick Boettcher reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */ 2788173a64cbSPatrick 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) */ 2789173a64cbSPatrick Boettcher } 2790173a64cbSPatrick Boettcher } else { /* 13-seg start conf offset loop parameters */ 2791173a64cbSPatrick Boettcher reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ 2792173a64cbSPatrick 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 */ 2793173a64cbSPatrick Boettcher } 2794173a64cbSPatrick Boettcher break; 2795173a64cbSPatrick Boettcher case LOOP_TUNE_2: 2796c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2797c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */ 2798173a64cbSPatrick Boettcher reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/ 2799173a64cbSPatrick Boettcher reg_37 = (12-state->mode) | ((5 + state->mode) << 5); 2800173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2801173a64cbSPatrick Boettcher reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */ 2802173a64cbSPatrick Boettcher reg_37 = (11-state->mode) | ((5 + state->mode) << 5); 2803173a64cbSPatrick Boettcher } 2804173a64cbSPatrick Boettcher } else { /* 13 seg */ 2805173a64cbSPatrick Boettcher reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */ 2806173a64cbSPatrick Boettcher reg_37 = ((5+state->mode) << 5) | (10 - state->mode); 2807173a64cbSPatrick Boettcher } 2808173a64cbSPatrick Boettcher break; 2809173a64cbSPatrick Boettcher } 2810173a64cbSPatrick Boettcher dib8000_write_word(state, 32, reg_32); 2811173a64cbSPatrick Boettcher dib8000_write_word(state, 37, reg_37); 2812173a64cbSPatrick Boettcher } 2813173a64cbSPatrick Boettcher 2814173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state) 2815173a64cbSPatrick Boettcher { 2816173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x4000); 2817173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x0000); 2818173a64cbSPatrick Boettcher return; 2819173a64cbSPatrick Boettcher } 2820173a64cbSPatrick Boettcher 2821173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state) 2822173a64cbSPatrick Boettcher { 2823c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2824173a64cbSPatrick Boettcher u16 sync_wait = 64; 2825173a64cbSPatrick Boettcher 2826173a64cbSPatrick Boettcher /* P_dvsy_sync_wait - reuse mode */ 2827c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2828173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2829173a64cbSPatrick Boettcher sync_wait = 256; 2830173a64cbSPatrick Boettcher break; 2831173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K: 2832173a64cbSPatrick Boettcher sync_wait = 128; 2833173a64cbSPatrick Boettcher break; 2834173a64cbSPatrick Boettcher default: 2835173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2836173a64cbSPatrick Boettcher sync_wait = 64; 2837173a64cbSPatrick Boettcher break; 2838173a64cbSPatrick Boettcher } 2839173a64cbSPatrick Boettcher 2840173a64cbSPatrick Boettcher if (state->cfg.diversity_delay == 0) 2841c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */ 2842173a64cbSPatrick Boettcher else 2843c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */ 2844173a64cbSPatrick Boettcher 2845173a64cbSPatrick Boettcher dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4)); 2846173a64cbSPatrick Boettcher } 2847173a64cbSPatrick Boettcher 2848173a64cbSPatrick Boettcher static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode) 2849173a64cbSPatrick Boettcher { 2850173a64cbSPatrick Boettcher if (mode == SYMBOL_DEPENDENT_ON) 2851173a64cbSPatrick Boettcher return systime() + (delay * state->symbol_duration); 2852173a64cbSPatrick Boettcher else 2853173a64cbSPatrick Boettcher return systime() + delay; 2854173a64cbSPatrick Boettcher } 2855173a64cbSPatrick Boettcher 2856173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe) 2857173a64cbSPatrick Boettcher { 2858173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2859173a64cbSPatrick Boettcher return state->status; 2860173a64cbSPatrick Boettcher } 2861173a64cbSPatrick Boettcher 2862d44913c1SMauro Carvalho Chehab static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) 2863173a64cbSPatrick Boettcher { 2864173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2865173a64cbSPatrick Boettcher return state->tune_state; 2866173a64cbSPatrick Boettcher } 2867173a64cbSPatrick Boettcher 2868d44913c1SMauro Carvalho Chehab static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) 2869173a64cbSPatrick Boettcher { 2870173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2871173a64cbSPatrick Boettcher 2872173a64cbSPatrick Boettcher state->tune_state = tune_state; 2873173a64cbSPatrick Boettcher return 0; 2874173a64cbSPatrick Boettcher } 2875173a64cbSPatrick Boettcher 2876173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe) 2877173a64cbSPatrick Boettcher { 2878173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2879173a64cbSPatrick Boettcher 2880173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING; 2881173a64cbSPatrick Boettcher state->tune_state = CT_DEMOD_START; 2882173a64cbSPatrick Boettcher return 0; 2883173a64cbSPatrick Boettcher } 2884173a64cbSPatrick Boettcher 2885173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe) 2886173a64cbSPatrick Boettcher { 2887173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2888173a64cbSPatrick Boettcher 2889173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2890173a64cbSPatrick Boettcher return dib8000_read_word(state, 570); 2891173a64cbSPatrick Boettcher return dib8000_read_word(state, 568); 2892173a64cbSPatrick Boettcher } 2893173a64cbSPatrick Boettcher 2894173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state) 2895173a64cbSPatrick Boettcher { 2896173a64cbSPatrick Boettcher u16 reg = 0; 2897173a64cbSPatrick Boettcher dprintk("init sdram"); 2898173a64cbSPatrick Boettcher 2899173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 274) & 0xfff0; 2900173a64cbSPatrick Boettcher dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */ 2901173a64cbSPatrick Boettcher 2902173a64cbSPatrick Boettcher dib8000_write_word(state, 1803, (7 << 2)); 2903173a64cbSPatrick Boettcher 2904173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 1280); 2905173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */ 2906173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */ 2907173a64cbSPatrick Boettcher 2908173a64cbSPatrick Boettcher return 0; 2909173a64cbSPatrick Boettcher } 2910173a64cbSPatrick Boettcher 2911ad976187SMauro Carvalho Chehab /** 2912ad976187SMauro Carvalho Chehab * is_manual_mode - Check if TMCC should be used for parameters settings 2913ad976187SMauro Carvalho Chehab * @c: struct dvb_frontend_properties 2914ad976187SMauro Carvalho Chehab * 2915ad976187SMauro Carvalho Chehab * By default, TMCC table should be used for parameter settings on most 2916ad976187SMauro Carvalho Chehab * usercases. However, sometimes it is desirable to lock the demod to 2917ad976187SMauro Carvalho Chehab * use the manual parameters. 2918ad976187SMauro Carvalho Chehab * 2919ad976187SMauro Carvalho Chehab * On manual mode, the current dib8000_tune state machine is very restrict: 2920ad976187SMauro Carvalho Chehab * It requires that both per-layer and per-transponder parameters to be 2921ad976187SMauro Carvalho Chehab * properly specified, otherwise the device won't lock. 2922ad976187SMauro Carvalho Chehab * 2923ad976187SMauro Carvalho Chehab * Check if all those conditions are properly satisfied before allowing 2924ad976187SMauro Carvalho Chehab * the device to use the manual frequency lock mode. 2925ad976187SMauro Carvalho Chehab */ 2926ad976187SMauro Carvalho Chehab static int is_manual_mode(struct dtv_frontend_properties *c) 2927ad976187SMauro Carvalho Chehab { 2928ad976187SMauro Carvalho Chehab int i, n_segs = 0; 2929ad976187SMauro Carvalho Chehab 2930ad976187SMauro Carvalho Chehab /* Use auto mode on DVB-T compat mode */ 2931ad976187SMauro Carvalho Chehab if (c->delivery_system != SYS_ISDBT) 2932ad976187SMauro Carvalho Chehab return 0; 2933ad976187SMauro Carvalho Chehab 2934ad976187SMauro Carvalho Chehab /* 2935ad976187SMauro Carvalho Chehab * Transmission mode is only detected on auto mode, currently 2936ad976187SMauro Carvalho Chehab */ 2937ad976187SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 2938ad976187SMauro Carvalho Chehab dprintk("transmission mode auto"); 2939ad976187SMauro Carvalho Chehab return 0; 2940ad976187SMauro Carvalho Chehab } 2941ad976187SMauro Carvalho Chehab 2942ad976187SMauro Carvalho Chehab /* 2943ad976187SMauro Carvalho Chehab * Guard interval is only detected on auto mode, currently 2944ad976187SMauro Carvalho Chehab */ 2945ad976187SMauro Carvalho Chehab if (c->guard_interval == GUARD_INTERVAL_AUTO) { 2946ad976187SMauro Carvalho Chehab dprintk("guard interval auto"); 2947ad976187SMauro Carvalho Chehab return 0; 2948ad976187SMauro Carvalho Chehab } 2949ad976187SMauro Carvalho Chehab 2950ad976187SMauro Carvalho Chehab /* 2951ad976187SMauro Carvalho Chehab * If no layer is enabled, assume auto mode, as at least one 2952ad976187SMauro Carvalho Chehab * layer should be enabled 2953ad976187SMauro Carvalho Chehab */ 2954ad976187SMauro Carvalho Chehab if (!c->isdbt_layer_enabled) { 2955ad976187SMauro Carvalho Chehab dprintk("no layer modulation specified"); 2956ad976187SMauro Carvalho Chehab return 0; 2957ad976187SMauro Carvalho Chehab } 2958ad976187SMauro Carvalho Chehab 2959ad976187SMauro Carvalho Chehab /* 2960ad976187SMauro Carvalho Chehab * Check if the per-layer parameters aren't auto and 2961ad976187SMauro Carvalho Chehab * disable a layer if segment count is 0 or invalid. 2962ad976187SMauro Carvalho Chehab */ 2963ad976187SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 2964ad976187SMauro Carvalho Chehab if (!(c->isdbt_layer_enabled & 1 << i)) 2965ad976187SMauro Carvalho Chehab continue; 2966ad976187SMauro Carvalho Chehab 2967ad976187SMauro Carvalho Chehab if ((c->layer[i].segment_count > 13) || 2968ad976187SMauro Carvalho Chehab (c->layer[i].segment_count == 0)) { 2969ad976187SMauro Carvalho Chehab c->isdbt_layer_enabled &= ~(1 << i); 2970ad976187SMauro Carvalho Chehab continue; 2971ad976187SMauro Carvalho Chehab } 2972ad976187SMauro Carvalho Chehab 2973ad976187SMauro Carvalho Chehab n_segs += c->layer[i].segment_count; 2974ad976187SMauro Carvalho Chehab 2975ad976187SMauro Carvalho Chehab if ((c->layer[i].modulation == QAM_AUTO) || 2976ad976187SMauro Carvalho Chehab (c->layer[i].fec == FEC_AUTO)) { 2977ad976187SMauro Carvalho Chehab dprintk("layer %c has either modulation or FEC auto", 2978ad976187SMauro Carvalho Chehab 'A' + i); 2979ad976187SMauro Carvalho Chehab return 0; 2980ad976187SMauro Carvalho Chehab } 2981ad976187SMauro Carvalho Chehab } 2982ad976187SMauro Carvalho Chehab 2983ad976187SMauro Carvalho Chehab /* 2984ad976187SMauro Carvalho Chehab * Userspace specified a wrong number of segments. 2985ad976187SMauro Carvalho Chehab * fallback to auto mode. 2986ad976187SMauro Carvalho Chehab */ 2987ad976187SMauro Carvalho Chehab if (n_segs == 0 || n_segs > 13) { 2988ad976187SMauro Carvalho Chehab dprintk("number of segments is invalid"); 2989ad976187SMauro Carvalho Chehab return 0; 2990ad976187SMauro Carvalho Chehab } 2991ad976187SMauro Carvalho Chehab 2992ad976187SMauro Carvalho Chehab /* Everything looks ok for manual mode */ 2993ad976187SMauro Carvalho Chehab return 1; 2994ad976187SMauro Carvalho Chehab } 2995ad976187SMauro Carvalho Chehab 29969a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe) 29979a0bf528SMauro Carvalho Chehab { 29989a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 2999c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 3000173a64cbSPatrick Boettcher enum frontend_tune_state *tune_state = &state->tune_state; 30019a0bf528SMauro Carvalho Chehab 3002173a64cbSPatrick Boettcher u16 locks, deeper_interleaver = 0, i; 3003173a64cbSPatrick Boettcher int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */ 30049a0bf528SMauro Carvalho Chehab 3005173a64cbSPatrick Boettcher u32 *timeout = &state->timeout; 3006173a64cbSPatrick Boettcher u32 now = systime(); 3007173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 3008173a64cbSPatrick Boettcher u16 agc1, agc2; 3009173a64cbSPatrick Boettcher #endif 30109a0bf528SMauro Carvalho Chehab 3011173a64cbSPatrick Boettcher u32 corm[4] = {0, 0, 0, 0}; 3012173a64cbSPatrick Boettcher u8 find_index, max_value; 30139a0bf528SMauro Carvalho Chehab 3014173a64cbSPatrick Boettcher #if 0 3015173a64cbSPatrick Boettcher if (*tune_state < CT_DEMOD_STOP) 3016173a64cbSPatrick Boettcher dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now); 3017173a64cbSPatrick Boettcher #endif 30189a0bf528SMauro Carvalho Chehab 3019173a64cbSPatrick Boettcher switch (*tune_state) { 3020173a64cbSPatrick Boettcher case CT_DEMOD_START: /* 30 */ 30216ef06e78SMauro Carvalho Chehab dib8000_reset_stats(fe); 30226ef06e78SMauro Carvalho Chehab 3023173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3024173a64cbSPatrick Boettcher dib8090p_init_sdram(state); 3025173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING; 3026ad976187SMauro Carvalho Chehab state->channel_parameters_set = is_manual_mode(c); 3027ad976187SMauro Carvalho Chehab 3028ad976187SMauro Carvalho Chehab dprintk("Tuning channel on %s search mode", 3029ad976187SMauro Carvalho Chehab state->channel_parameters_set ? "manual" : "auto"); 30309a0bf528SMauro Carvalho Chehab 3031173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 0); /* force chan dec in restart */ 30329a0bf528SMauro Carvalho Chehab 3033ad976187SMauro Carvalho Chehab /* Layer monitor */ 3034173a64cbSPatrick Boettcher dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); 3035173a64cbSPatrick Boettcher 3036173a64cbSPatrick Boettcher dib8000_set_frequency_offset(state); 3037c82056d0SMauro Carvalho Chehab dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000); 3038173a64cbSPatrick Boettcher 3039173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */ 3040173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 3041173a64cbSPatrick Boettcher if (state->revision != 0x8090) { 3042173a64cbSPatrick Boettcher state->agc1_max = dib8000_read_word(state, 108); 3043173a64cbSPatrick Boettcher state->agc1_min = dib8000_read_word(state, 109); 3044173a64cbSPatrick Boettcher state->agc2_max = dib8000_read_word(state, 110); 3045173a64cbSPatrick Boettcher state->agc2_min = dib8000_read_word(state, 111); 3046173a64cbSPatrick Boettcher agc1 = dib8000_read_word(state, 388); 3047173a64cbSPatrick Boettcher agc2 = dib8000_read_word(state, 389); 3048173a64cbSPatrick Boettcher dib8000_write_word(state, 108, agc1); 3049173a64cbSPatrick Boettcher dib8000_write_word(state, 109, agc1); 3050173a64cbSPatrick Boettcher dib8000_write_word(state, 110, agc2); 3051173a64cbSPatrick Boettcher dib8000_write_word(state, 111, agc2); 3052173a64cbSPatrick Boettcher } 3053173a64cbSPatrick Boettcher #endif 3054173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_FFT; 3055173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_AUTO; 3056173a64cbSPatrick Boettcher state->found_guard = GUARD_INTERVAL_AUTO; 3057173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT; 3058173a64cbSPatrick Boettcher } else { /* we already know the channel struct so TUNE only ! */ 3059173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3060173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 3061173a64cbSPatrick Boettcher } 3062173a64cbSPatrick Boettcher state->symbol_duration = dib8000_get_symbol_duration(state); 3063173a64cbSPatrick Boettcher break; 3064173a64cbSPatrick Boettcher 3065173a64cbSPatrick Boettcher case CT_DEMOD_SEARCH_NEXT: /* 51 */ 3066173a64cbSPatrick Boettcher dib8000_autosearch_start(fe); 3067173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3068173a64cbSPatrick Boettcher ret = 50; 3069173a64cbSPatrick Boettcher else 3070173a64cbSPatrick Boettcher ret = 15; 3071173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_1; 3072173a64cbSPatrick Boettcher break; 3073173a64cbSPatrick Boettcher 3074173a64cbSPatrick Boettcher case CT_DEMOD_STEP_1: /* 31 */ 3075173a64cbSPatrick Boettcher switch (dib8000_autosearch_irq(fe)) { 3076173a64cbSPatrick Boettcher case 1: /* fail */ 3077173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3078173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3079173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */ 3080173a64cbSPatrick Boettcher break; 3081173a64cbSPatrick Boettcher case 2: /* Succes */ 3082173a64cbSPatrick Boettcher state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */ 3083173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 3084173a64cbSPatrick Boettcher if (state->autosearch_state == AS_SEARCHING_GUARD) 3085173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2; 3086173a64cbSPatrick Boettcher else 3087173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3088173a64cbSPatrick Boettcher break; 3089173a64cbSPatrick Boettcher case 3: /* Autosearch FFT max correlation endded */ 3090173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2; 3091173a64cbSPatrick Boettcher break; 3092173a64cbSPatrick Boettcher } 3093173a64cbSPatrick Boettcher break; 3094173a64cbSPatrick Boettcher 3095173a64cbSPatrick Boettcher case CT_DEMOD_STEP_2: 3096173a64cbSPatrick Boettcher switch (state->autosearch_state) { 3097173a64cbSPatrick Boettcher case AS_SEARCHING_FFT: 3098173a64cbSPatrick Boettcher /* searching for the correct FFT */ 3099173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 3100173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); 3101173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); 3102173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601)); 3103173a64cbSPatrick Boettcher } else { 3104173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595)); 3105173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); 3106173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); 3107173a64cbSPatrick Boettcher } 3108173a64cbSPatrick Boettcher /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */ 3109173a64cbSPatrick Boettcher 3110173a64cbSPatrick Boettcher max_value = 0; 3111173a64cbSPatrick Boettcher for (find_index = 1 ; find_index < 3 ; find_index++) { 3112173a64cbSPatrick Boettcher if (corm[max_value] < corm[find_index]) 3113173a64cbSPatrick Boettcher max_value = find_index ; 31149a0bf528SMauro Carvalho Chehab } 31159a0bf528SMauro Carvalho Chehab 3116173a64cbSPatrick Boettcher switch (max_value) { 3117173a64cbSPatrick Boettcher case 0: 3118173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_2K; 3119173a64cbSPatrick Boettcher break; 3120173a64cbSPatrick Boettcher case 1: 3121173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_4K; 3122173a64cbSPatrick Boettcher break; 3123173a64cbSPatrick Boettcher case 2: 3124173a64cbSPatrick Boettcher default: 3125173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_8K; 3126173a64cbSPatrick Boettcher break; 3127173a64cbSPatrick Boettcher } 3128173a64cbSPatrick Boettcher /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */ 3129173a64cbSPatrick Boettcher 3130173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT; 3131173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_GUARD; 3132173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3133173a64cbSPatrick Boettcher ret = 50; 3134173a64cbSPatrick Boettcher else 3135173a64cbSPatrick Boettcher ret = 10; 3136173a64cbSPatrick Boettcher break; 3137173a64cbSPatrick Boettcher case AS_SEARCHING_GUARD: 3138173a64cbSPatrick Boettcher /* searching for the correct guard interval */ 3139173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3140173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 572) & 0x3; 3141173a64cbSPatrick Boettcher else 3142173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 570) & 0x3; 3143173a64cbSPatrick Boettcher /* dprintk("guard interval found=%i", state->found_guard); */ 3144173a64cbSPatrick Boettcher 3145173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 3146173a64cbSPatrick Boettcher break; 3147173a64cbSPatrick Boettcher default: 3148173a64cbSPatrick Boettcher /* the demod should never be in this state */ 3149173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3150173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3151173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */ 3152173a64cbSPatrick Boettcher break; 3153173a64cbSPatrick Boettcher } 3154173a64cbSPatrick Boettcher break; 3155173a64cbSPatrick Boettcher 3156173a64cbSPatrick Boettcher case CT_DEMOD_STEP_3: /* 33 */ 3157173a64cbSPatrick Boettcher state->symbol_duration = dib8000_get_symbol_duration(state); 3158173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1); 3159173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */ 3160173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_4; 3161173a64cbSPatrick Boettcher break; 3162173a64cbSPatrick Boettcher 3163173a64cbSPatrick Boettcher case CT_DEMOD_STEP_4: /* (34) */ 3164173a64cbSPatrick Boettcher dib8000_demod_restart(state); 3165173a64cbSPatrick Boettcher 3166173a64cbSPatrick Boettcher dib8000_set_sync_wait(state); 3167173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); 3168173a64cbSPatrick Boettcher 3169173a64cbSPatrick Boettcher locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */ 317039c1cb2bSJonathan McCrohan /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */ 3171173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON); 3172173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_5; 3173173a64cbSPatrick Boettcher break; 3174173a64cbSPatrick Boettcher 3175173a64cbSPatrick Boettcher case CT_DEMOD_STEP_5: /* (35) */ 3176173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3177173a64cbSPatrick Boettcher if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */ 3178173a64cbSPatrick Boettcher dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */ 3179173a64cbSPatrick Boettcher if (!state->differential_constellation) { 3180173a64cbSPatrick Boettcher /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */ 3181173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON); 3182173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_7; 3183173a64cbSPatrick Boettcher } else { 3184173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; 3185173a64cbSPatrick Boettcher } 3186173a64cbSPatrick Boettcher } else if (now > *timeout) { 3187173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ 3188173a64cbSPatrick Boettcher } 3189173a64cbSPatrick Boettcher break; 3190173a64cbSPatrick Boettcher 3191173a64cbSPatrick Boettcher case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */ 3192173a64cbSPatrick Boettcher if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { 3193173a64cbSPatrick 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 */ 3194173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ 3195173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ 3196173a64cbSPatrick Boettcher else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */ 3197173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ 3198173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3199173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3200173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3201173a64cbSPatrick Boettcher } 3202173a64cbSPatrick Boettcher } else { 3203173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3204173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3205173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ 3206173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3207173a64cbSPatrick Boettcher } 3208173a64cbSPatrick Boettcher break; 3209173a64cbSPatrick Boettcher 3210173a64cbSPatrick Boettcher case CT_DEMOD_STEP_7: /* 37 */ 3211173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3212173a64cbSPatrick Boettcher if (locks & (1<<10)) { /* lmod4_lock */ 3213173a64cbSPatrick Boettcher ret = 14; /* wait for 14 symbols */ 3214173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; 3215173a64cbSPatrick Boettcher } else if (now > *timeout) 3216173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ 3217173a64cbSPatrick Boettcher break; 3218173a64cbSPatrick Boettcher 3219173a64cbSPatrick Boettcher case CT_DEMOD_STEP_8: /* 38 */ 3220173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3221173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3222173a64cbSPatrick Boettcher 3223173a64cbSPatrick Boettcher /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ 3224746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3225746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3226746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) { 3227173a64cbSPatrick Boettcher state->subchannel = 0; 3228173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11; 3229173a64cbSPatrick Boettcher } else { 3230173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9; 3231173a64cbSPatrick Boettcher state->status = FE_STATUS_LOCKED; 3232173a64cbSPatrick Boettcher } 3233173a64cbSPatrick Boettcher break; 3234173a64cbSPatrick Boettcher 3235173a64cbSPatrick Boettcher case CT_DEMOD_STEP_9: /* 39 */ 3236173a64cbSPatrick Boettcher if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */ 323739c1cb2bSJonathan McCrohan /* defines timeout for mpeg lock depending on interleaver length of longest layer */ 3238173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) { 3239c82056d0SMauro Carvalho Chehab if (c->layer[i].interleaving >= deeper_interleaver) { 3240c82056d0SMauro Carvalho Chehab dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving); 3241c82056d0SMauro Carvalho Chehab if (c->layer[i].segment_count > 0) { /* valid layer */ 3242c82056d0SMauro Carvalho Chehab deeper_interleaver = c->layer[0].interleaving; 3243173a64cbSPatrick Boettcher state->longest_intlv_layer = i; 3244173a64cbSPatrick Boettcher } 3245173a64cbSPatrick Boettcher } 3246173a64cbSPatrick Boettcher } 3247173a64cbSPatrick Boettcher 3248173a64cbSPatrick Boettcher if (deeper_interleaver == 0) 3249173a64cbSPatrick Boettcher locks = 2; /* locks is the tmp local variable name */ 3250173a64cbSPatrick Boettcher else if (deeper_interleaver == 3) 3251173a64cbSPatrick Boettcher locks = 8; 3252173a64cbSPatrick Boettcher else 3253173a64cbSPatrick Boettcher locks = 2 * deeper_interleaver; 3254173a64cbSPatrick Boettcher 3255173a64cbSPatrick Boettcher if (state->diversity_onoff != 0) /* because of diversity sync */ 3256173a64cbSPatrick Boettcher locks *= 2; 3257173a64cbSPatrick Boettcher 3258173a64cbSPatrick Boettcher *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */ 3259173a64cbSPatrick Boettcher dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout); 3260173a64cbSPatrick Boettcher 3261173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_10; 3262173a64cbSPatrick Boettcher } else 3263173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3264173a64cbSPatrick Boettcher break; 3265173a64cbSPatrick Boettcher 3266173a64cbSPatrick Boettcher case CT_DEMOD_STEP_10: /* 40 */ 3267173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3268173a64cbSPatrick Boettcher if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ 3269173a64cbSPatrick Boettcher dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); 3270746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3271746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3272746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) 3273173a64cbSPatrick Boettcher /* signal to the upper layer, that there was a channel found and the parameters can be read */ 3274173a64cbSPatrick Boettcher state->status = FE_STATUS_DEMOD_SUCCESS; 3275173a64cbSPatrick Boettcher else 3276173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED; 3277173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3278173a64cbSPatrick Boettcher } else if (now > *timeout) { 3279746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3280746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3281746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) { /* continue to try init prbs autosearch */ 3282173a64cbSPatrick Boettcher state->subchannel += 3; 3283173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11; 3284173a64cbSPatrick 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 */ 3285173a64cbSPatrick Boettcher if (locks & (0x7<<5)) { 3286173a64cbSPatrick Boettcher dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); 3287173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED; 3288173a64cbSPatrick Boettcher } else 3289173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3290173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3291173a64cbSPatrick Boettcher } 3292173a64cbSPatrick Boettcher } 3293173a64cbSPatrick Boettcher break; 3294173a64cbSPatrick Boettcher 3295173a64cbSPatrick Boettcher case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */ 3296173a64cbSPatrick Boettcher if (state->subchannel <= 41) { 3297173a64cbSPatrick Boettcher dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); 3298173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9; 3299173a64cbSPatrick Boettcher } else { 3300173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3301173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3302173a64cbSPatrick Boettcher } 3303173a64cbSPatrick Boettcher break; 3304173a64cbSPatrick Boettcher 3305173a64cbSPatrick Boettcher default: 3306173a64cbSPatrick Boettcher break; 3307173a64cbSPatrick Boettcher } 3308173a64cbSPatrick Boettcher 3309173a64cbSPatrick Boettcher /* tuning is finished - cleanup the demod */ 3310173a64cbSPatrick Boettcher switch (*tune_state) { 3311173a64cbSPatrick Boettcher case CT_DEMOD_STOP: /* (42) */ 3312173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 3313173a64cbSPatrick Boettcher if ((state->revision != 0x8090) && (state->agc1_max != 0)) { 3314173a64cbSPatrick Boettcher dib8000_write_word(state, 108, state->agc1_max); 3315173a64cbSPatrick Boettcher dib8000_write_word(state, 109, state->agc1_min); 3316173a64cbSPatrick Boettcher dib8000_write_word(state, 110, state->agc2_max); 3317173a64cbSPatrick Boettcher dib8000_write_word(state, 111, state->agc2_min); 3318173a64cbSPatrick Boettcher state->agc1_max = 0; 3319173a64cbSPatrick Boettcher state->agc1_min = 0; 3320173a64cbSPatrick Boettcher state->agc2_max = 0; 3321173a64cbSPatrick Boettcher state->agc2_min = 0; 3322173a64cbSPatrick Boettcher } 3323173a64cbSPatrick Boettcher #endif 3324173a64cbSPatrick Boettcher ret = FE_CALLBACK_TIME_NEVER; 3325173a64cbSPatrick Boettcher break; 3326173a64cbSPatrick Boettcher default: 3327173a64cbSPatrick Boettcher break; 3328173a64cbSPatrick Boettcher } 3329173a64cbSPatrick Boettcher 3330173a64cbSPatrick Boettcher if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3)) 3331173a64cbSPatrick Boettcher return ret * state->symbol_duration; 3332173a64cbSPatrick Boettcher if ((ret > 0) && (ret < state->symbol_duration)) 3333173a64cbSPatrick Boettcher return state->symbol_duration; /* at least one symbol */ 33349a0bf528SMauro Carvalho Chehab return ret; 33359a0bf528SMauro Carvalho Chehab } 33369a0bf528SMauro Carvalho Chehab 33379a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe) 33389a0bf528SMauro Carvalho Chehab { 33399a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 33409a0bf528SMauro Carvalho Chehab u8 index_frontend; 33419a0bf528SMauro Carvalho Chehab int ret; 33429a0bf528SMauro Carvalho Chehab 33439a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 33449a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 33459a0bf528SMauro Carvalho Chehab if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) 33469a0bf528SMauro Carvalho Chehab dprintk("could not start Slow ADC"); 33479a0bf528SMauro Carvalho Chehab 3348173a64cbSPatrick Boettcher if (state->revision == 0x8090) 33499a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state); 33509a0bf528SMauro Carvalho Chehab 33519a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 33529a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); 33539a0bf528SMauro Carvalho Chehab if (ret < 0) 33549a0bf528SMauro Carvalho Chehab return ret; 33559a0bf528SMauro Carvalho Chehab } 33569a0bf528SMauro Carvalho Chehab 33579a0bf528SMauro Carvalho Chehab return 0; 33589a0bf528SMauro Carvalho Chehab } 33599a0bf528SMauro Carvalho Chehab 33609a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe) 33619a0bf528SMauro Carvalho Chehab { 33629a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 33639a0bf528SMauro Carvalho Chehab u8 index_frontend; 33649a0bf528SMauro Carvalho Chehab int ret; 33659a0bf528SMauro Carvalho Chehab 33669a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 33679a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); 33689a0bf528SMauro Carvalho Chehab if (ret < 0) 33699a0bf528SMauro Carvalho Chehab return ret; 33709a0bf528SMauro Carvalho Chehab } 33719a0bf528SMauro Carvalho Chehab 33729a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 33739a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); 33749a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); 33759a0bf528SMauro Carvalho Chehab return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); 33769a0bf528SMauro Carvalho Chehab } 33779a0bf528SMauro Carvalho Chehab 337870315b3eSMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat); 337970315b3eSMauro Carvalho Chehab 33809a0bf528SMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe) 33819a0bf528SMauro Carvalho Chehab { 33829a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 33839a0bf528SMauro Carvalho Chehab u16 i, val = 0; 338470315b3eSMauro Carvalho Chehab fe_status_t stat = 0; 33859a0bf528SMauro Carvalho Chehab u8 index_frontend, sub_index_frontend; 33869a0bf528SMauro Carvalho Chehab 33879a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.bandwidth_hz = 6000000; 33889a0bf528SMauro Carvalho Chehab 338970315b3eSMauro Carvalho Chehab /* 339070315b3eSMauro Carvalho Chehab * If called to early, get_frontend makes dib8000_tune to either 339170315b3eSMauro Carvalho Chehab * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail. 339270315b3eSMauro Carvalho Chehab * So, let's just return if frontend 0 has not locked. 339370315b3eSMauro Carvalho Chehab */ 339470315b3eSMauro Carvalho Chehab dib8000_read_status(fe, &stat); 339570315b3eSMauro Carvalho Chehab if (!(stat & FE_HAS_SYNC)) 339670315b3eSMauro Carvalho Chehab return 0; 339770315b3eSMauro Carvalho Chehab 339870315b3eSMauro Carvalho Chehab dprintk("TMCC lock"); 33999a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 34009a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); 34019a0bf528SMauro Carvalho Chehab if (stat&FE_HAS_SYNC) { 34029a0bf528SMauro Carvalho Chehab dprintk("TMCC lock on the slave%i", index_frontend); 34039a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 34049a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]); 34059a0bf528SMauro Carvalho Chehab for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { 34069a0bf528SMauro Carvalho Chehab if (sub_index_frontend != index_frontend) { 34079a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; 34089a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; 34099a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; 34109a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; 34119a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; 34129a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 34139a0bf528SMauro 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; 34149a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; 34159a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; 34169a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; 34179a0bf528SMauro Carvalho Chehab } 34189a0bf528SMauro Carvalho Chehab } 34199a0bf528SMauro Carvalho Chehab } 34209a0bf528SMauro Carvalho Chehab return 0; 34219a0bf528SMauro Carvalho Chehab } 34229a0bf528SMauro Carvalho Chehab } 34239a0bf528SMauro Carvalho Chehab 34249a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; 34259a0bf528SMauro Carvalho Chehab 34269a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 34279a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 572); 34289a0bf528SMauro Carvalho Chehab else 34299a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 570); 34309a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.inversion = (val & 0x40) >> 6; 34319a0bf528SMauro Carvalho Chehab switch ((val & 0x30) >> 4) { 34329a0bf528SMauro Carvalho Chehab case 1: 34339a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; 34349a0bf528SMauro Carvalho Chehab break; 34359a0bf528SMauro Carvalho Chehab case 3: 34369a0bf528SMauro Carvalho Chehab default: 34379a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; 34389a0bf528SMauro Carvalho Chehab break; 34399a0bf528SMauro Carvalho Chehab } 34409a0bf528SMauro Carvalho Chehab 34419a0bf528SMauro Carvalho Chehab switch (val & 0x3) { 34429a0bf528SMauro Carvalho Chehab case 0: 34439a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; 34449a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/32 "); 34459a0bf528SMauro Carvalho Chehab break; 34469a0bf528SMauro Carvalho Chehab case 1: 34479a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; 34489a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/16 "); 34499a0bf528SMauro Carvalho Chehab break; 34509a0bf528SMauro Carvalho Chehab case 2: 34519a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/8 "); 34529a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; 34539a0bf528SMauro Carvalho Chehab break; 34549a0bf528SMauro Carvalho Chehab case 3: 34559a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/4 "); 34569a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; 34579a0bf528SMauro Carvalho Chehab break; 34589a0bf528SMauro Carvalho Chehab } 34599a0bf528SMauro Carvalho Chehab 34609a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 505); 34619a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.isdbt_partial_reception = val & 1; 34629a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception); 34639a0bf528SMauro Carvalho Chehab 34649a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 34659a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 493 + i); 34669a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; 34679a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); 34689a0bf528SMauro Carvalho Chehab 346951fea113SMauro Carvalho Chehab val = dib8000_read_word(state, 499 + i) & 0x3; 347051fea113SMauro Carvalho Chehab /* Interleaving can be 0, 1, 2 or 4 */ 347151fea113SMauro Carvalho Chehab if (val == 3) 347251fea113SMauro Carvalho Chehab val = 4; 347351fea113SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].interleaving = val; 347451fea113SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", 347551fea113SMauro Carvalho Chehab i, fe->dtv_property_cache.layer[i].interleaving); 34769a0bf528SMauro Carvalho Chehab 34779a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 481 + i); 34789a0bf528SMauro Carvalho Chehab switch (val & 0x7) { 34799a0bf528SMauro Carvalho Chehab case 1: 34809a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_1_2; 34819a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i); 34829a0bf528SMauro Carvalho Chehab break; 34839a0bf528SMauro Carvalho Chehab case 2: 34849a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_2_3; 34859a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i); 34869a0bf528SMauro Carvalho Chehab break; 34879a0bf528SMauro Carvalho Chehab case 3: 34889a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_3_4; 34899a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i); 34909a0bf528SMauro Carvalho Chehab break; 34919a0bf528SMauro Carvalho Chehab case 5: 34929a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_5_6; 34939a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i); 34949a0bf528SMauro Carvalho Chehab break; 34959a0bf528SMauro Carvalho Chehab default: 34969a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_7_8; 34979a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i); 34989a0bf528SMauro Carvalho Chehab break; 34999a0bf528SMauro Carvalho Chehab } 35009a0bf528SMauro Carvalho Chehab 35019a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 487 + i); 35029a0bf528SMauro Carvalho Chehab switch (val & 0x3) { 35039a0bf528SMauro Carvalho Chehab case 0: 35049a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d DQPSK ", i); 35059a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = DQPSK; 35069a0bf528SMauro Carvalho Chehab break; 35079a0bf528SMauro Carvalho Chehab case 1: 35089a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = QPSK; 35099a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d QPSK ", i); 35109a0bf528SMauro Carvalho Chehab break; 35119a0bf528SMauro Carvalho Chehab case 2: 35129a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = QAM_16; 35139a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d QAM16 ", i); 35149a0bf528SMauro Carvalho Chehab break; 35159a0bf528SMauro Carvalho Chehab case 3: 35169a0bf528SMauro Carvalho Chehab default: 35179a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d QAM64 ", i); 35189a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = QAM_64; 35199a0bf528SMauro Carvalho Chehab break; 35209a0bf528SMauro Carvalho Chehab } 35219a0bf528SMauro Carvalho Chehab } 35229a0bf528SMauro Carvalho Chehab 35239a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 35249a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 35259a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode; 35269a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; 35279a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; 35289a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; 35299a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception; 35309a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 35319a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count; 35329a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving; 35339a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec; 35349a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation; 35359a0bf528SMauro Carvalho Chehab } 35369a0bf528SMauro Carvalho Chehab } 35379a0bf528SMauro Carvalho Chehab return 0; 35389a0bf528SMauro Carvalho Chehab } 35399a0bf528SMauro Carvalho Chehab 35409a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe) 35419a0bf528SMauro Carvalho Chehab { 35429a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 3543c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 35444d8d5d92SGeert Uytterhoeven int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER; 3545173a64cbSPatrick Boettcher u8 exit_condition, index_frontend; 3546173a64cbSPatrick Boettcher u32 delay, callback_time; 35479a0bf528SMauro Carvalho Chehab 3548c82056d0SMauro Carvalho Chehab if (c->frequency == 0) { 35499a0bf528SMauro Carvalho Chehab dprintk("dib8000: must at least specify frequency "); 35509a0bf528SMauro Carvalho Chehab return 0; 35519a0bf528SMauro Carvalho Chehab } 35529a0bf528SMauro Carvalho Chehab 3553c82056d0SMauro Carvalho Chehab if (c->bandwidth_hz == 0) { 35549a0bf528SMauro Carvalho Chehab dprintk("dib8000: no bandwidth specified, set to default "); 3555c82056d0SMauro Carvalho Chehab c->bandwidth_hz = 6000000; 35569a0bf528SMauro Carvalho Chehab } 35579a0bf528SMauro Carvalho Chehab 35589a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 35599a0bf528SMauro Carvalho Chehab /* synchronization of the cache */ 35609a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; 35619a0bf528SMauro Carvalho Chehab memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); 35629a0bf528SMauro Carvalho Chehab 3563173a64cbSPatrick Boettcher /* set output mode and diversity input */ 3564173a64cbSPatrick Boettcher if (state->revision != 0x8090) { 3565173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend], 1); 3566173a64cbSPatrick Boettcher if (index_frontend != 0) 35679a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[index_frontend], 3568173a64cbSPatrick Boettcher OUTMODE_DIVERSITY); 35699a0bf528SMauro Carvalho Chehab else 3570173a64cbSPatrick Boettcher dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); 3571173a64cbSPatrick Boettcher } else { 3572173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend], 1); 3573173a64cbSPatrick Boettcher if (index_frontend != 0) 35749a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[index_frontend], 3575173a64cbSPatrick Boettcher OUTMODE_DIVERSITY); 3576173a64cbSPatrick Boettcher else 3577173a64cbSPatrick Boettcher dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); 3578173a64cbSPatrick Boettcher } 3579173a64cbSPatrick Boettcher 3580173a64cbSPatrick Boettcher /* tune the tuner */ 35819a0bf528SMauro Carvalho Chehab if (state->fe[index_frontend]->ops.tuner_ops.set_params) 35829a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]); 35839a0bf528SMauro Carvalho Chehab 35849a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); 35859a0bf528SMauro Carvalho Chehab } 35869a0bf528SMauro Carvalho Chehab 3587173a64cbSPatrick Boettcher /* turn off the diversity of the last chip */ 3588173a64cbSPatrick Boettcher if (state->revision != 0x8090) 3589173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend - 1], 0); 3590173a64cbSPatrick Boettcher else 3591173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0); 3592173a64cbSPatrick Boettcher 35939a0bf528SMauro Carvalho Chehab /* start up the AGC */ 35949a0bf528SMauro Carvalho Chehab do { 35959a0bf528SMauro Carvalho Chehab time = dib8000_agc_startup(state->fe[0]); 35969a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 35979a0bf528SMauro Carvalho Chehab time_slave = dib8000_agc_startup(state->fe[index_frontend]); 35989a0bf528SMauro Carvalho Chehab if (time == FE_CALLBACK_TIME_NEVER) 35999a0bf528SMauro Carvalho Chehab time = time_slave; 36009a0bf528SMauro Carvalho Chehab else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time)) 36019a0bf528SMauro Carvalho Chehab time = time_slave; 36029a0bf528SMauro Carvalho Chehab } 36039a0bf528SMauro Carvalho Chehab if (time != FE_CALLBACK_TIME_NEVER) 36049a0bf528SMauro Carvalho Chehab msleep(time / 10); 36059a0bf528SMauro Carvalho Chehab else 36069a0bf528SMauro Carvalho Chehab break; 36079a0bf528SMauro Carvalho Chehab exit_condition = 1; 36089a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 36099a0bf528SMauro Carvalho Chehab if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { 36109a0bf528SMauro Carvalho Chehab exit_condition = 0; 36119a0bf528SMauro Carvalho Chehab break; 36129a0bf528SMauro Carvalho Chehab } 36139a0bf528SMauro Carvalho Chehab } 36149a0bf528SMauro Carvalho Chehab } while (exit_condition == 0); 36159a0bf528SMauro Carvalho Chehab 36169a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 36179a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); 36189a0bf528SMauro Carvalho Chehab 3619173a64cbSPatrick Boettcher active = 1; 36209a0bf528SMauro Carvalho Chehab do { 3621173a64cbSPatrick Boettcher callback_time = FE_CALLBACK_TIME_NEVER; 36229a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 3623173a64cbSPatrick Boettcher delay = dib8000_tune(state->fe[index_frontend]); 3624173a64cbSPatrick Boettcher if (delay != FE_CALLBACK_TIME_NEVER) 3625173a64cbSPatrick Boettcher delay += systime(); 3626173a64cbSPatrick Boettcher 3627173a64cbSPatrick Boettcher /* we are in autosearch */ 3628173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* searching */ 3629173a64cbSPatrick Boettcher if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) { 3630173a64cbSPatrick Boettcher dprintk("autosearch succeeded on fe%i", index_frontend); 3631173a64cbSPatrick Boettcher dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */ 3632173a64cbSPatrick Boettcher state->channel_parameters_set = 1; 3633173a64cbSPatrick Boettcher 3634173a64cbSPatrick Boettcher for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) { 3635173a64cbSPatrick Boettcher if (l != index_frontend) { /* and for all frontend except the successful one */ 3636173a64cbSPatrick Boettcher dib8000_tune_restart_from_demod(state->fe[l]); 3637173a64cbSPatrick Boettcher 3638173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; 3639173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; 3640173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; 3641173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; 3642173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; 3643173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) { 3644173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; 3645173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; 3646173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; 3647173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; 3648173a64cbSPatrick Boettcher } 3649173a64cbSPatrick Boettcher 36509a0bf528SMauro Carvalho Chehab } 36519a0bf528SMauro Carvalho Chehab } 36529a0bf528SMauro Carvalho Chehab } 3653173a64cbSPatrick Boettcher } 3654173a64cbSPatrick Boettcher if (delay < callback_time) 3655173a64cbSPatrick Boettcher callback_time = delay; 3656173a64cbSPatrick Boettcher } 3657173a64cbSPatrick Boettcher /* tuning is done when the master frontend is done (failed or success) */ 3658173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED || 3659173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED || 3660173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) { 3661173a64cbSPatrick Boettcher active = 0; 3662173a64cbSPatrick Boettcher /* we need to wait for all frontends to be finished */ 3663173a64cbSPatrick Boettcher for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 3664173a64cbSPatrick Boettcher if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP) 3665173a64cbSPatrick Boettcher active = 1; 3666173a64cbSPatrick Boettcher } 3667173a64cbSPatrick Boettcher if (active == 0) 3668173a64cbSPatrick Boettcher dprintk("tuning done with status %d", dib8000_get_status(state->fe[0])); 36699a0bf528SMauro Carvalho Chehab } 36709a0bf528SMauro Carvalho Chehab 3671173a64cbSPatrick Boettcher if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) { 3672173a64cbSPatrick Boettcher dprintk("strange callback time something went wrong"); 3673173a64cbSPatrick Boettcher active = 0; 36749a0bf528SMauro Carvalho Chehab } 36759a0bf528SMauro Carvalho Chehab 3676173a64cbSPatrick Boettcher while ((active == 1) && (systime() < callback_time)) 3677173a64cbSPatrick Boettcher msleep(100); 3678173a64cbSPatrick Boettcher } while (active); 36799a0bf528SMauro Carvalho Chehab 3680173a64cbSPatrick Boettcher /* set output mode */ 3681173a64cbSPatrick Boettcher if (state->revision != 0x8090) 36829a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); 3683173a64cbSPatrick Boettcher else { 36849a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode); 36859a0bf528SMauro Carvalho Chehab if (state->cfg.enMpegOutput == 0) { 36869a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, MPEG_ON_DIBTX); 36879a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 36889a0bf528SMauro Carvalho Chehab } 36899a0bf528SMauro Carvalho Chehab } 36909a0bf528SMauro Carvalho Chehab 36914d8d5d92SGeert Uytterhoeven return 0; 36929a0bf528SMauro Carvalho Chehab } 36939a0bf528SMauro Carvalho Chehab 36946ef06e78SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat); 36956ef06e78SMauro Carvalho Chehab 36969a0bf528SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) 36979a0bf528SMauro Carvalho Chehab { 36989a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 36999a0bf528SMauro Carvalho Chehab u16 lock_slave = 0, lock; 37009a0bf528SMauro Carvalho Chehab u8 index_frontend; 37019a0bf528SMauro Carvalho Chehab 3702173a64cbSPatrick Boettcher lock = dib8000_read_lock(fe); 37039a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 37049a0bf528SMauro Carvalho Chehab lock_slave |= dib8000_read_lock(state->fe[index_frontend]); 37059a0bf528SMauro Carvalho Chehab 37069a0bf528SMauro Carvalho Chehab *stat = 0; 37079a0bf528SMauro Carvalho Chehab 37089a0bf528SMauro Carvalho Chehab if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1)) 37099a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SIGNAL; 37109a0bf528SMauro Carvalho Chehab 37119a0bf528SMauro Carvalho Chehab if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */ 37129a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_CARRIER; 37139a0bf528SMauro Carvalho Chehab 37149a0bf528SMauro Carvalho Chehab if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */ 37159a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SYNC; 37169a0bf528SMauro Carvalho Chehab 37179a0bf528SMauro Carvalho Chehab if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */ 37189a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_LOCK; 37199a0bf528SMauro Carvalho Chehab 37209a0bf528SMauro Carvalho Chehab if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) { 37219a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ 37229a0bf528SMauro Carvalho Chehab if (lock & 0x01) 37239a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 37249a0bf528SMauro Carvalho Chehab 37259a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ 37269a0bf528SMauro Carvalho Chehab if (lock & 0x01) 37279a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 37289a0bf528SMauro Carvalho Chehab 37299a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ 37309a0bf528SMauro Carvalho Chehab if (lock & 0x01) 37319a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 37329a0bf528SMauro Carvalho Chehab } 37336ef06e78SMauro Carvalho Chehab dib8000_get_stats(fe, *stat); 37349a0bf528SMauro Carvalho Chehab 37359a0bf528SMauro Carvalho Chehab return 0; 37369a0bf528SMauro Carvalho Chehab } 37379a0bf528SMauro Carvalho Chehab 37389a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) 37399a0bf528SMauro Carvalho Chehab { 37409a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37419a0bf528SMauro Carvalho Chehab 37429a0bf528SMauro Carvalho Chehab /* 13 segments */ 37439a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 37449a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 562) << 16) | 37459a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 563); 37469a0bf528SMauro Carvalho Chehab else 37479a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 560) << 16) | 37489a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 561); 37499a0bf528SMauro Carvalho Chehab return 0; 37509a0bf528SMauro Carvalho Chehab } 37519a0bf528SMauro Carvalho Chehab 37529a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) 37539a0bf528SMauro Carvalho Chehab { 37549a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37559a0bf528SMauro Carvalho Chehab 37569a0bf528SMauro Carvalho Chehab /* packet error on 13 seg */ 37579a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 37589a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 567); 37599a0bf528SMauro Carvalho Chehab else 37609a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 565); 37619a0bf528SMauro Carvalho Chehab return 0; 37629a0bf528SMauro Carvalho Chehab } 37639a0bf528SMauro Carvalho Chehab 37649a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 37659a0bf528SMauro Carvalho Chehab { 37669a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37679a0bf528SMauro Carvalho Chehab u8 index_frontend; 37689a0bf528SMauro Carvalho Chehab u16 val; 37699a0bf528SMauro Carvalho Chehab 37709a0bf528SMauro Carvalho Chehab *strength = 0; 37719a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 37729a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); 37739a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 37749a0bf528SMauro Carvalho Chehab *strength = 65535; 37759a0bf528SMauro Carvalho Chehab else 37769a0bf528SMauro Carvalho Chehab *strength += val; 37779a0bf528SMauro Carvalho Chehab } 37789a0bf528SMauro Carvalho Chehab 37799a0bf528SMauro Carvalho Chehab val = 65535 - dib8000_read_word(state, 390); 37809a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 37819a0bf528SMauro Carvalho Chehab *strength = 65535; 37829a0bf528SMauro Carvalho Chehab else 37839a0bf528SMauro Carvalho Chehab *strength += val; 37849a0bf528SMauro Carvalho Chehab return 0; 37859a0bf528SMauro Carvalho Chehab } 37869a0bf528SMauro Carvalho Chehab 37879a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe) 37889a0bf528SMauro Carvalho Chehab { 37899a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37909a0bf528SMauro Carvalho Chehab u32 n, s, exp; 37919a0bf528SMauro Carvalho Chehab u16 val; 37929a0bf528SMauro Carvalho Chehab 37939a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 37949a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 542); 37959a0bf528SMauro Carvalho Chehab else 37969a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 544); 37979a0bf528SMauro Carvalho Chehab n = (val >> 6) & 0xff; 37989a0bf528SMauro Carvalho Chehab exp = (val & 0x3f); 37999a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 38009a0bf528SMauro Carvalho Chehab exp -= 0x40; 38019a0bf528SMauro Carvalho Chehab n <<= exp+16; 38029a0bf528SMauro Carvalho Chehab 38039a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 38049a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 543); 38059a0bf528SMauro Carvalho Chehab else 38069a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 545); 38079a0bf528SMauro Carvalho Chehab s = (val >> 6) & 0xff; 38089a0bf528SMauro Carvalho Chehab exp = (val & 0x3f); 38099a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 38109a0bf528SMauro Carvalho Chehab exp -= 0x40; 38119a0bf528SMauro Carvalho Chehab s <<= exp+16; 38129a0bf528SMauro Carvalho Chehab 38139a0bf528SMauro Carvalho Chehab if (n > 0) { 38149a0bf528SMauro Carvalho Chehab u32 t = (s/n) << 16; 38159a0bf528SMauro Carvalho Chehab return t + ((s << 16) - n*t) / n; 38169a0bf528SMauro Carvalho Chehab } 38179a0bf528SMauro Carvalho Chehab return 0xffffffff; 38189a0bf528SMauro Carvalho Chehab } 38199a0bf528SMauro Carvalho Chehab 38209a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) 38219a0bf528SMauro Carvalho Chehab { 38229a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 38239a0bf528SMauro Carvalho Chehab u8 index_frontend; 38249a0bf528SMauro Carvalho Chehab u32 snr_master; 38259a0bf528SMauro Carvalho Chehab 38269a0bf528SMauro Carvalho Chehab snr_master = dib8000_get_snr(fe); 38279a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 38289a0bf528SMauro Carvalho Chehab snr_master += dib8000_get_snr(state->fe[index_frontend]); 38299a0bf528SMauro Carvalho Chehab 38309a0bf528SMauro Carvalho Chehab if ((snr_master >> 16) != 0) { 38319a0bf528SMauro Carvalho Chehab snr_master = 10*intlog10(snr_master>>16); 38329a0bf528SMauro Carvalho Chehab *snr = snr_master / ((1 << 24) / 10); 38339a0bf528SMauro Carvalho Chehab } 38349a0bf528SMauro Carvalho Chehab else 38359a0bf528SMauro Carvalho Chehab *snr = 0; 38369a0bf528SMauro Carvalho Chehab 38379a0bf528SMauro Carvalho Chehab return 0; 38389a0bf528SMauro Carvalho Chehab } 38399a0bf528SMauro Carvalho Chehab 38406ef06e78SMauro Carvalho Chehab struct per_layer_regs { 38416ef06e78SMauro Carvalho Chehab u16 lock, ber, per; 38426ef06e78SMauro Carvalho Chehab }; 38436ef06e78SMauro Carvalho Chehab 38446ef06e78SMauro Carvalho Chehab static const struct per_layer_regs per_layer_regs[] = { 38456ef06e78SMauro Carvalho Chehab { 554, 560, 562 }, 38466ef06e78SMauro Carvalho Chehab { 555, 576, 578 }, 38476ef06e78SMauro Carvalho Chehab { 556, 581, 583 }, 38486ef06e78SMauro Carvalho Chehab }; 38496ef06e78SMauro Carvalho Chehab 385042ff76bdSMauro Carvalho Chehab struct linear_segments { 385142ff76bdSMauro Carvalho Chehab unsigned x; 385242ff76bdSMauro Carvalho Chehab signed y; 385342ff76bdSMauro Carvalho Chehab }; 385442ff76bdSMauro Carvalho Chehab 385542ff76bdSMauro Carvalho Chehab /* 385642ff76bdSMauro Carvalho Chehab * Table to estimate signal strength in dBm. 385742ff76bdSMauro Carvalho Chehab * This table was empirically determinated by measuring the signal 385842ff76bdSMauro Carvalho Chehab * strength generated by a DTA-2111 RF generator directly connected into 385942ff76bdSMauro Carvalho Chehab * a dib8076 device (a PixelView PV-D231U stick), using a good quality 386042ff76bdSMauro Carvalho Chehab * 3 meters RC6 cable and good RC6 connectors. 386142ff76bdSMauro Carvalho Chehab * The real value can actually be different on other devices, depending 386242ff76bdSMauro Carvalho Chehab * on several factors, like if LNA is enabled or not, if diversity is 386342ff76bdSMauro Carvalho Chehab * enabled, type of connectors, etc. 386442ff76bdSMauro Carvalho Chehab * Yet, it is better to use this measure in dB than a random non-linear 386542ff76bdSMauro Carvalho Chehab * percentage value, especially for antenna adjustments. 386642ff76bdSMauro Carvalho Chehab * On my tests, the precision of the measure using this table is about 386742ff76bdSMauro Carvalho Chehab * 0.5 dB, with sounds reasonable enough. 386842ff76bdSMauro Carvalho Chehab */ 386942ff76bdSMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = { 387042ff76bdSMauro Carvalho Chehab { 55953, 108500 }, /* -22.5 dBm */ 387142ff76bdSMauro Carvalho Chehab { 55394, 108000 }, 387242ff76bdSMauro Carvalho Chehab { 53834, 107000 }, 387342ff76bdSMauro Carvalho Chehab { 52863, 106000 }, 387442ff76bdSMauro Carvalho Chehab { 52239, 105000 }, 387542ff76bdSMauro Carvalho Chehab { 52012, 104000 }, 387642ff76bdSMauro Carvalho Chehab { 51803, 103000 }, 387742ff76bdSMauro Carvalho Chehab { 51566, 102000 }, 387842ff76bdSMauro Carvalho Chehab { 51356, 101000 }, 387942ff76bdSMauro Carvalho Chehab { 51112, 100000 }, 388042ff76bdSMauro Carvalho Chehab { 50869, 99000 }, 388142ff76bdSMauro Carvalho Chehab { 50600, 98000 }, 388242ff76bdSMauro Carvalho Chehab { 50363, 97000 }, 388342ff76bdSMauro Carvalho Chehab { 50117, 96000 }, /* -35 dBm */ 388442ff76bdSMauro Carvalho Chehab { 49889, 95000 }, 388542ff76bdSMauro Carvalho Chehab { 49680, 94000 }, 388642ff76bdSMauro Carvalho Chehab { 49493, 93000 }, 388742ff76bdSMauro Carvalho Chehab { 49302, 92000 }, 388842ff76bdSMauro Carvalho Chehab { 48929, 91000 }, 388942ff76bdSMauro Carvalho Chehab { 48416, 90000 }, 389042ff76bdSMauro Carvalho Chehab { 48035, 89000 }, 389142ff76bdSMauro Carvalho Chehab { 47593, 88000 }, 389242ff76bdSMauro Carvalho Chehab { 47282, 87000 }, 389342ff76bdSMauro Carvalho Chehab { 46953, 86000 }, 389442ff76bdSMauro Carvalho Chehab { 46698, 85000 }, 389542ff76bdSMauro Carvalho Chehab { 45617, 84000 }, 389642ff76bdSMauro Carvalho Chehab { 44773, 83000 }, 389742ff76bdSMauro Carvalho Chehab { 43845, 82000 }, 389842ff76bdSMauro Carvalho Chehab { 43020, 81000 }, 389942ff76bdSMauro Carvalho Chehab { 42010, 80000 }, /* -51 dBm */ 390042ff76bdSMauro Carvalho Chehab { 0, 0 }, 390142ff76bdSMauro Carvalho Chehab }; 390242ff76bdSMauro Carvalho Chehab 390342ff76bdSMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments, 390442ff76bdSMauro Carvalho Chehab unsigned len) 390542ff76bdSMauro Carvalho Chehab { 390642ff76bdSMauro Carvalho Chehab u64 tmp64; 390742ff76bdSMauro Carvalho Chehab u32 dx; 390842ff76bdSMauro Carvalho Chehab s32 dy; 390942ff76bdSMauro Carvalho Chehab int i, ret; 391042ff76bdSMauro Carvalho Chehab 391142ff76bdSMauro Carvalho Chehab if (value >= segments[0].x) 391242ff76bdSMauro Carvalho Chehab return segments[0].y; 391342ff76bdSMauro Carvalho Chehab if (value < segments[len-1].x) 391442ff76bdSMauro Carvalho Chehab return segments[len-1].y; 391542ff76bdSMauro Carvalho Chehab 391642ff76bdSMauro Carvalho Chehab for (i = 1; i < len - 1; i++) { 391742ff76bdSMauro Carvalho Chehab /* If value is identical, no need to interpolate */ 391842ff76bdSMauro Carvalho Chehab if (value == segments[i].x) 391942ff76bdSMauro Carvalho Chehab return segments[i].y; 392042ff76bdSMauro Carvalho Chehab if (value > segments[i].x) 392142ff76bdSMauro Carvalho Chehab break; 392242ff76bdSMauro Carvalho Chehab } 392342ff76bdSMauro Carvalho Chehab 392442ff76bdSMauro Carvalho Chehab /* Linear interpolation between the two (x,y) points */ 392542ff76bdSMauro Carvalho Chehab dy = segments[i - 1].y - segments[i].y; 392642ff76bdSMauro Carvalho Chehab dx = segments[i - 1].x - segments[i].x; 392742ff76bdSMauro Carvalho Chehab 392842ff76bdSMauro Carvalho Chehab tmp64 = value - segments[i].x; 392942ff76bdSMauro Carvalho Chehab tmp64 *= dy; 393042ff76bdSMauro Carvalho Chehab do_div(tmp64, dx); 393142ff76bdSMauro Carvalho Chehab ret = segments[i].y + tmp64; 393242ff76bdSMauro Carvalho Chehab 393342ff76bdSMauro Carvalho Chehab return ret; 393442ff76bdSMauro Carvalho Chehab } 393542ff76bdSMauro Carvalho Chehab 3936704f01bbSMauro Carvalho Chehab static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer) 3937704f01bbSMauro Carvalho Chehab { 3938704f01bbSMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 3939704f01bbSMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 3940704f01bbSMauro Carvalho Chehab int ini_layer, end_layer, i; 39414bf48150SMauro Carvalho Chehab u64 time_us, tmp64; 3942704f01bbSMauro Carvalho Chehab u32 tmp, denom; 3943e4a3bc1cSMauro Carvalho Chehab int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs; 3944e4a3bc1cSMauro Carvalho Chehab int interleaving = 0, fft_div; 3945704f01bbSMauro Carvalho Chehab 3946704f01bbSMauro Carvalho Chehab if (layer >= 0) { 3947704f01bbSMauro Carvalho Chehab ini_layer = layer; 3948704f01bbSMauro Carvalho Chehab end_layer = layer + 1; 3949704f01bbSMauro Carvalho Chehab } else { 3950704f01bbSMauro Carvalho Chehab ini_layer = 0; 3951704f01bbSMauro Carvalho Chehab end_layer = 3; 3952704f01bbSMauro Carvalho Chehab } 3953704f01bbSMauro Carvalho Chehab 3954704f01bbSMauro Carvalho Chehab switch (c->guard_interval) { 3955704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 3956704f01bbSMauro Carvalho Chehab guard = 4; 3957704f01bbSMauro Carvalho Chehab break; 3958704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 3959704f01bbSMauro Carvalho Chehab guard = 8; 3960704f01bbSMauro Carvalho Chehab break; 3961704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 3962704f01bbSMauro Carvalho Chehab guard = 16; 3963704f01bbSMauro Carvalho Chehab break; 3964704f01bbSMauro Carvalho Chehab default: 3965704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 3966704f01bbSMauro Carvalho Chehab guard = 32; 3967704f01bbSMauro Carvalho Chehab break; 3968704f01bbSMauro Carvalho Chehab } 3969704f01bbSMauro Carvalho Chehab 3970704f01bbSMauro Carvalho Chehab switch (c->transmission_mode) { 3971704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 3972704f01bbSMauro Carvalho Chehab fft_div = 4; 3973704f01bbSMauro Carvalho Chehab break; 3974704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 3975704f01bbSMauro Carvalho Chehab fft_div = 2; 3976704f01bbSMauro Carvalho Chehab break; 3977704f01bbSMauro Carvalho Chehab default: 3978704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 3979704f01bbSMauro Carvalho Chehab fft_div = 1; 3980704f01bbSMauro Carvalho Chehab break; 3981704f01bbSMauro Carvalho Chehab } 3982704f01bbSMauro Carvalho Chehab 3983704f01bbSMauro Carvalho Chehab denom = 0; 3984704f01bbSMauro Carvalho Chehab for (i = ini_layer; i < end_layer; i++) { 3985704f01bbSMauro Carvalho Chehab nsegs = c->layer[i].segment_count; 3986704f01bbSMauro Carvalho Chehab if (nsegs == 0 || nsegs > 13) 3987704f01bbSMauro Carvalho Chehab continue; 3988704f01bbSMauro Carvalho Chehab 3989704f01bbSMauro Carvalho Chehab switch (c->layer[i].modulation) { 3990704f01bbSMauro Carvalho Chehab case DQPSK: 3991704f01bbSMauro Carvalho Chehab case QPSK: 3992704f01bbSMauro Carvalho Chehab bits_per_symbol = 2; 3993704f01bbSMauro Carvalho Chehab break; 3994704f01bbSMauro Carvalho Chehab case QAM_16: 3995704f01bbSMauro Carvalho Chehab bits_per_symbol = 4; 3996704f01bbSMauro Carvalho Chehab break; 3997704f01bbSMauro Carvalho Chehab default: 3998704f01bbSMauro Carvalho Chehab case QAM_64: 3999704f01bbSMauro Carvalho Chehab bits_per_symbol = 6; 4000704f01bbSMauro Carvalho Chehab break; 4001704f01bbSMauro Carvalho Chehab } 4002704f01bbSMauro Carvalho Chehab 4003704f01bbSMauro Carvalho Chehab switch (c->layer[i].fec) { 4004704f01bbSMauro Carvalho Chehab case FEC_1_2: 4005704f01bbSMauro Carvalho Chehab rate_num = 1; 4006704f01bbSMauro Carvalho Chehab rate_denum = 2; 4007704f01bbSMauro Carvalho Chehab break; 4008704f01bbSMauro Carvalho Chehab case FEC_2_3: 4009704f01bbSMauro Carvalho Chehab rate_num = 2; 4010704f01bbSMauro Carvalho Chehab rate_denum = 3; 4011704f01bbSMauro Carvalho Chehab break; 4012704f01bbSMauro Carvalho Chehab case FEC_3_4: 4013704f01bbSMauro Carvalho Chehab rate_num = 3; 4014704f01bbSMauro Carvalho Chehab rate_denum = 4; 4015704f01bbSMauro Carvalho Chehab break; 4016704f01bbSMauro Carvalho Chehab case FEC_5_6: 4017704f01bbSMauro Carvalho Chehab rate_num = 5; 4018704f01bbSMauro Carvalho Chehab rate_denum = 6; 4019704f01bbSMauro Carvalho Chehab break; 4020704f01bbSMauro Carvalho Chehab default: 4021704f01bbSMauro Carvalho Chehab case FEC_7_8: 4022704f01bbSMauro Carvalho Chehab rate_num = 7; 4023704f01bbSMauro Carvalho Chehab rate_denum = 8; 4024704f01bbSMauro Carvalho Chehab break; 4025704f01bbSMauro Carvalho Chehab } 4026704f01bbSMauro Carvalho Chehab 4027704f01bbSMauro Carvalho Chehab interleaving = c->layer[i].interleaving; 4028704f01bbSMauro Carvalho Chehab 4029704f01bbSMauro Carvalho Chehab denom += bits_per_symbol * rate_num * fft_div * nsegs * 384; 4030704f01bbSMauro Carvalho Chehab } 4031704f01bbSMauro Carvalho Chehab 4032704f01bbSMauro Carvalho Chehab /* If all goes wrong, wait for 1s for the next stats */ 4033704f01bbSMauro Carvalho Chehab if (!denom) 4034704f01bbSMauro Carvalho Chehab return 0; 4035704f01bbSMauro Carvalho Chehab 4036704f01bbSMauro Carvalho Chehab /* Estimate the period for the total bit rate */ 4037704f01bbSMauro Carvalho Chehab time_us = rate_denum * (1008 * 1562500L); 40384bf48150SMauro Carvalho Chehab tmp64 = time_us; 40394bf48150SMauro Carvalho Chehab do_div(tmp64, guard); 40404bf48150SMauro Carvalho Chehab time_us = time_us + tmp64; 4041704f01bbSMauro Carvalho Chehab time_us += denom / 2; 4042704f01bbSMauro Carvalho Chehab do_div(time_us, denom); 4043704f01bbSMauro Carvalho Chehab 4044704f01bbSMauro Carvalho Chehab tmp = 1008 * 96 * interleaving; 4045704f01bbSMauro Carvalho Chehab time_us += tmp + tmp / guard; 4046704f01bbSMauro Carvalho Chehab 4047704f01bbSMauro Carvalho Chehab return time_us; 4048704f01bbSMauro Carvalho Chehab } 4049704f01bbSMauro Carvalho Chehab 40506ef06e78SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat) 40516ef06e78SMauro Carvalho Chehab { 40526ef06e78SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 40536ef06e78SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 4054704f01bbSMauro Carvalho Chehab int i; 40550400c535SMauro Carvalho Chehab int show_per_stats = 0; 40560400c535SMauro Carvalho Chehab u32 time_us = 0, snr, val; 40570400c535SMauro Carvalho Chehab u64 blocks; 405842ff76bdSMauro Carvalho Chehab s32 db; 40596ef06e78SMauro Carvalho Chehab u16 strength; 40606ef06e78SMauro Carvalho Chehab 40616ef06e78SMauro Carvalho Chehab /* Get Signal strength */ 40626ef06e78SMauro Carvalho Chehab dib8000_read_signal_strength(fe, &strength); 406342ff76bdSMauro Carvalho Chehab val = strength; 406442ff76bdSMauro Carvalho Chehab db = interpolate_value(val, 406542ff76bdSMauro Carvalho Chehab strength_to_db_table, 406642ff76bdSMauro Carvalho Chehab ARRAY_SIZE(strength_to_db_table)) - 131000; 406742ff76bdSMauro Carvalho Chehab c->strength.stat[0].svalue = db; 40686ef06e78SMauro Carvalho Chehab 4069704f01bbSMauro Carvalho Chehab /* UCB/BER/CNR measures require lock */ 4070704f01bbSMauro Carvalho Chehab if (!(stat & FE_HAS_LOCK)) { 4071704f01bbSMauro Carvalho Chehab c->cnr.len = 1; 40720400c535SMauro Carvalho Chehab c->block_count.len = 1; 4073704f01bbSMauro Carvalho Chehab c->block_error.len = 1; 4074704f01bbSMauro Carvalho Chehab c->post_bit_error.len = 1; 4075704f01bbSMauro Carvalho Chehab c->post_bit_count.len = 1; 4076704f01bbSMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4077704f01bbSMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4078704f01bbSMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4079704f01bbSMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 40800400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 40816ef06e78SMauro Carvalho Chehab return 0; 4082704f01bbSMauro Carvalho Chehab } 4083704f01bbSMauro Carvalho Chehab 4084704f01bbSMauro Carvalho Chehab /* Check if time for stats was elapsed */ 40850400c535SMauro Carvalho Chehab if (time_after(jiffies, state->per_jiffies_stats)) { 40860400c535SMauro Carvalho Chehab state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000); 40876ef06e78SMauro Carvalho Chehab 40886ef06e78SMauro Carvalho Chehab /* Get SNR */ 40896ef06e78SMauro Carvalho Chehab snr = dib8000_get_snr(fe); 40906ef06e78SMauro Carvalho Chehab for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) { 40916ef06e78SMauro Carvalho Chehab if (state->fe[i]) 40926ef06e78SMauro Carvalho Chehab snr += dib8000_get_snr(state->fe[i]); 40936ef06e78SMauro Carvalho Chehab } 40946ef06e78SMauro Carvalho Chehab snr = snr >> 16; 40956ef06e78SMauro Carvalho Chehab 40966ef06e78SMauro Carvalho Chehab if (snr) { 40976ef06e78SMauro Carvalho Chehab snr = 10 * intlog10(snr); 40986ef06e78SMauro Carvalho Chehab snr = (1000L * snr) >> 24; 40996ef06e78SMauro Carvalho Chehab } else { 41006ef06e78SMauro Carvalho Chehab snr = 0; 41016ef06e78SMauro Carvalho Chehab } 41026ef06e78SMauro Carvalho Chehab c->cnr.stat[0].svalue = snr; 41036ef06e78SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 41046ef06e78SMauro Carvalho Chehab 41050400c535SMauro Carvalho Chehab /* Get UCB measures */ 41060400c535SMauro Carvalho Chehab dib8000_read_unc_blocks(fe, &val); 41070400c535SMauro Carvalho Chehab if (val < state->init_ucb) 41085dc8526bSMauro Carvalho Chehab state->init_ucb += 0x100000000LL; 41090400c535SMauro Carvalho Chehab 41100400c535SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_COUNTER; 41110400c535SMauro Carvalho Chehab c->block_error.stat[0].uvalue = val + state->init_ucb; 41120400c535SMauro Carvalho Chehab 41130400c535SMauro Carvalho Chehab /* Estimate the number of packets based on bitrate */ 41140400c535SMauro Carvalho Chehab if (!time_us) 41150400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, -1); 41160400c535SMauro Carvalho Chehab 41170400c535SMauro Carvalho Chehab if (time_us) { 41185dc8526bSMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL; 41190400c535SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204); 41200400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER; 41210400c535SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks; 41220400c535SMauro Carvalho Chehab } 41230400c535SMauro Carvalho Chehab 41240400c535SMauro Carvalho Chehab show_per_stats = 1; 41250400c535SMauro Carvalho Chehab } 41260400c535SMauro Carvalho Chehab 41270400c535SMauro Carvalho Chehab /* Get post-BER measures */ 41280400c535SMauro Carvalho Chehab if (time_after(jiffies, state->ber_jiffies_stats)) { 41290400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, -1); 41300400c535SMauro Carvalho Chehab state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000); 41310400c535SMauro Carvalho Chehab 41320400c535SMauro Carvalho Chehab dprintk("Next all layers stats available in %u us.", time_us); 41336ef06e78SMauro Carvalho Chehab 41346ef06e78SMauro Carvalho Chehab dib8000_read_ber(fe, &val); 41356ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 41366ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].uvalue += val; 41376ef06e78SMauro Carvalho Chehab 41386ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 41396ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].uvalue += 100000000; 4140704f01bbSMauro Carvalho Chehab } 41416ef06e78SMauro Carvalho Chehab 41426ef06e78SMauro Carvalho Chehab if (state->revision < 0x8002) 41436ef06e78SMauro Carvalho Chehab return 0; 41446ef06e78SMauro Carvalho Chehab 41456ef06e78SMauro Carvalho Chehab c->block_error.len = 4; 41466ef06e78SMauro Carvalho Chehab c->post_bit_error.len = 4; 41476ef06e78SMauro Carvalho Chehab c->post_bit_count.len = 4; 41486ef06e78SMauro Carvalho Chehab 41496ef06e78SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 41500400c535SMauro Carvalho Chehab unsigned nsegs = c->layer[i].segment_count; 41510400c535SMauro Carvalho Chehab 41520400c535SMauro Carvalho Chehab if (nsegs == 0 || nsegs > 13) 4153704f01bbSMauro Carvalho Chehab continue; 4154704f01bbSMauro Carvalho Chehab 41550400c535SMauro Carvalho Chehab time_us = 0; 41560400c535SMauro Carvalho Chehab 41570400c535SMauro Carvalho Chehab if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) { 41580400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, i); 41590400c535SMauro Carvalho Chehab 41600400c535SMauro Carvalho Chehab state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000); 4161704f01bbSMauro Carvalho Chehab dprintk("Next layer %c stats will be available in %u us\n", 4162704f01bbSMauro Carvalho Chehab 'A' + i, time_us); 4163704f01bbSMauro Carvalho Chehab 41646ef06e78SMauro Carvalho Chehab val = dib8000_read_word(state, per_layer_regs[i].ber); 41656ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER; 41666ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[1 + i].uvalue += val; 41676ef06e78SMauro Carvalho Chehab 41686ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER; 41696ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[1 + i].uvalue += 100000000; 41700400c535SMauro Carvalho Chehab } 41716ef06e78SMauro Carvalho Chehab 41720400c535SMauro Carvalho Chehab if (show_per_stats) { 41736ef06e78SMauro Carvalho Chehab val = dib8000_read_word(state, per_layer_regs[i].per); 41746ef06e78SMauro Carvalho Chehab 41756ef06e78SMauro Carvalho Chehab c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER; 41766ef06e78SMauro Carvalho Chehab c->block_error.stat[1 + i].uvalue += val; 41770400c535SMauro Carvalho Chehab 41780400c535SMauro Carvalho Chehab if (!time_us) 41790400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, i); 41800400c535SMauro Carvalho Chehab if (time_us) { 41815dc8526bSMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL; 41820400c535SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204); 41830400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER; 41840400c535SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks; 41850400c535SMauro Carvalho Chehab } 41860400c535SMauro Carvalho Chehab } 41876ef06e78SMauro Carvalho Chehab } 41886ef06e78SMauro Carvalho Chehab return 0; 41896ef06e78SMauro Carvalho Chehab } 41906ef06e78SMauro Carvalho Chehab 4191d44913c1SMauro Carvalho Chehab static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) 41929a0bf528SMauro Carvalho Chehab { 41939a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 41949a0bf528SMauro Carvalho Chehab u8 index_frontend = 1; 41959a0bf528SMauro Carvalho Chehab 41969a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 41979a0bf528SMauro Carvalho Chehab index_frontend++; 41989a0bf528SMauro Carvalho Chehab if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { 41999a0bf528SMauro Carvalho Chehab dprintk("set slave fe %p to index %i", fe_slave, index_frontend); 42009a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = fe_slave; 42019a0bf528SMauro Carvalho Chehab return 0; 42029a0bf528SMauro Carvalho Chehab } 42039a0bf528SMauro Carvalho Chehab 42049a0bf528SMauro Carvalho Chehab dprintk("too many slave frontend"); 42059a0bf528SMauro Carvalho Chehab return -ENOMEM; 42069a0bf528SMauro Carvalho Chehab } 42079a0bf528SMauro Carvalho Chehab 4208d44913c1SMauro Carvalho Chehab static int dib8000_remove_slave_frontend(struct dvb_frontend *fe) 42099a0bf528SMauro Carvalho Chehab { 42109a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 42119a0bf528SMauro Carvalho Chehab u8 index_frontend = 1; 42129a0bf528SMauro Carvalho Chehab 42139a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 42149a0bf528SMauro Carvalho Chehab index_frontend++; 42159a0bf528SMauro Carvalho Chehab if (index_frontend != 1) { 42169a0bf528SMauro Carvalho Chehab dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); 42179a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = NULL; 42189a0bf528SMauro Carvalho Chehab return 0; 42199a0bf528SMauro Carvalho Chehab } 42209a0bf528SMauro Carvalho Chehab 42219a0bf528SMauro Carvalho Chehab dprintk("no frontend to be removed"); 42229a0bf528SMauro Carvalho Chehab return -ENODEV; 42239a0bf528SMauro Carvalho Chehab } 42249a0bf528SMauro Carvalho Chehab 4225d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) 42269a0bf528SMauro Carvalho Chehab { 42279a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 42289a0bf528SMauro Carvalho Chehab 42299a0bf528SMauro Carvalho Chehab if (slave_index >= MAX_NUMBER_OF_FRONTENDS) 42309a0bf528SMauro Carvalho Chehab return NULL; 42319a0bf528SMauro Carvalho Chehab return state->fe[slave_index]; 42329a0bf528SMauro Carvalho Chehab } 42339a0bf528SMauro Carvalho Chehab 4234d44913c1SMauro Carvalho Chehab static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, 42359a0bf528SMauro Carvalho Chehab u8 default_addr, u8 first_addr, u8 is_dib8096p) 42369a0bf528SMauro Carvalho Chehab { 42379a0bf528SMauro Carvalho Chehab int k = 0, ret = 0; 42389a0bf528SMauro Carvalho Chehab u8 new_addr = 0; 42399a0bf528SMauro Carvalho Chehab struct i2c_device client = {.adap = host }; 42409a0bf528SMauro Carvalho Chehab 42419a0bf528SMauro Carvalho Chehab client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); 42429a0bf528SMauro Carvalho Chehab if (!client.i2c_write_buffer) { 42439a0bf528SMauro Carvalho Chehab dprintk("%s: not enough memory", __func__); 42449a0bf528SMauro Carvalho Chehab return -ENOMEM; 42459a0bf528SMauro Carvalho Chehab } 42469a0bf528SMauro Carvalho Chehab client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); 42479a0bf528SMauro Carvalho Chehab if (!client.i2c_read_buffer) { 42489a0bf528SMauro Carvalho Chehab dprintk("%s: not enough memory", __func__); 42499a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 42509a0bf528SMauro Carvalho Chehab goto error_memory_read; 42519a0bf528SMauro Carvalho Chehab } 42529a0bf528SMauro Carvalho Chehab client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); 42539a0bf528SMauro Carvalho Chehab if (!client.i2c_buffer_lock) { 42549a0bf528SMauro Carvalho Chehab dprintk("%s: not enough memory", __func__); 42559a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 42569a0bf528SMauro Carvalho Chehab goto error_memory_lock; 42579a0bf528SMauro Carvalho Chehab } 42589a0bf528SMauro Carvalho Chehab mutex_init(client.i2c_buffer_lock); 42599a0bf528SMauro Carvalho Chehab 42609a0bf528SMauro Carvalho Chehab for (k = no_of_demods - 1; k >= 0; k--) { 42619a0bf528SMauro Carvalho Chehab /* designated i2c address */ 42629a0bf528SMauro Carvalho Chehab new_addr = first_addr + (k << 1); 42639a0bf528SMauro Carvalho Chehab 42649a0bf528SMauro Carvalho Chehab client.addr = new_addr; 42659a0bf528SMauro Carvalho Chehab if (!is_dib8096p) 42669a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ 42679a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) { 42689a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */ 42699a0bf528SMauro Carvalho Chehab if (!is_dib8096p) 42709a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003); 42719a0bf528SMauro Carvalho Chehab client.addr = default_addr; 42729a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) { 42739a0bf528SMauro Carvalho Chehab dprintk("#%d: not identified", k); 42749a0bf528SMauro Carvalho Chehab ret = -EINVAL; 42759a0bf528SMauro Carvalho Chehab goto error; 42769a0bf528SMauro Carvalho Chehab } 42779a0bf528SMauro Carvalho Chehab } 42789a0bf528SMauro Carvalho Chehab 42799a0bf528SMauro Carvalho Chehab /* start diversity to pull_down div_str - just for i2c-enumeration */ 42809a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6)); 42819a0bf528SMauro Carvalho Chehab 42829a0bf528SMauro Carvalho Chehab /* set new i2c address and force divstart */ 42839a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2); 42849a0bf528SMauro Carvalho Chehab client.addr = new_addr; 42859a0bf528SMauro Carvalho Chehab dib8000_identify(&client); 42869a0bf528SMauro Carvalho Chehab 42879a0bf528SMauro Carvalho Chehab dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); 42889a0bf528SMauro Carvalho Chehab } 42899a0bf528SMauro Carvalho Chehab 42909a0bf528SMauro Carvalho Chehab for (k = 0; k < no_of_demods; k++) { 42919a0bf528SMauro Carvalho Chehab new_addr = first_addr | (k << 1); 42929a0bf528SMauro Carvalho Chehab client.addr = new_addr; 42939a0bf528SMauro Carvalho Chehab 42949a0bf528SMauro Carvalho Chehab // unforce divstr 42959a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, new_addr << 2); 42969a0bf528SMauro Carvalho Chehab 42979a0bf528SMauro Carvalho Chehab /* deactivate div - it was just for i2c-enumeration */ 42989a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, 0); 42999a0bf528SMauro Carvalho Chehab } 43009a0bf528SMauro Carvalho Chehab 43019a0bf528SMauro Carvalho Chehab error: 43029a0bf528SMauro Carvalho Chehab kfree(client.i2c_buffer_lock); 43039a0bf528SMauro Carvalho Chehab error_memory_lock: 43049a0bf528SMauro Carvalho Chehab kfree(client.i2c_read_buffer); 43059a0bf528SMauro Carvalho Chehab error_memory_read: 43069a0bf528SMauro Carvalho Chehab kfree(client.i2c_write_buffer); 43079a0bf528SMauro Carvalho Chehab 43089a0bf528SMauro Carvalho Chehab return ret; 43099a0bf528SMauro Carvalho Chehab } 43109a0bf528SMauro Carvalho Chehab 43119a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) 43129a0bf528SMauro Carvalho Chehab { 43139a0bf528SMauro Carvalho Chehab tune->min_delay_ms = 1000; 43149a0bf528SMauro Carvalho Chehab tune->step_size = 0; 43159a0bf528SMauro Carvalho Chehab tune->max_drift = 0; 43169a0bf528SMauro Carvalho Chehab return 0; 43179a0bf528SMauro Carvalho Chehab } 43189a0bf528SMauro Carvalho Chehab 43199a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe) 43209a0bf528SMauro Carvalho Chehab { 43219a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 43229a0bf528SMauro Carvalho Chehab u8 index_frontend; 43239a0bf528SMauro Carvalho Chehab 43249a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) 43259a0bf528SMauro Carvalho Chehab dvb_frontend_detach(st->fe[index_frontend]); 43269a0bf528SMauro Carvalho Chehab 43279a0bf528SMauro Carvalho Chehab dibx000_exit_i2c_master(&st->i2c_master); 43289a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->dib8096p_tuner_adap); 43299a0bf528SMauro Carvalho Chehab kfree(st->fe[0]); 43309a0bf528SMauro Carvalho Chehab kfree(st); 43319a0bf528SMauro Carvalho Chehab } 43329a0bf528SMauro Carvalho Chehab 4333d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) 43349a0bf528SMauro Carvalho Chehab { 43359a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 43369a0bf528SMauro Carvalho Chehab return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); 43379a0bf528SMauro Carvalho Chehab } 43389a0bf528SMauro Carvalho Chehab 4339d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) 43409a0bf528SMauro Carvalho Chehab { 43419a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 43429a0bf528SMauro Carvalho Chehab u16 val = dib8000_read_word(st, 299) & 0xffef; 43439a0bf528SMauro Carvalho Chehab val |= (onoff & 0x1) << 4; 43449a0bf528SMauro Carvalho Chehab 43459a0bf528SMauro Carvalho Chehab dprintk("pid filter enabled %d", onoff); 43469a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 299, val); 43479a0bf528SMauro Carvalho Chehab } 43489a0bf528SMauro Carvalho Chehab 4349d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) 43509a0bf528SMauro Carvalho Chehab { 43519a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 43529a0bf528SMauro Carvalho Chehab dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); 43539a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); 43549a0bf528SMauro Carvalho Chehab } 43559a0bf528SMauro Carvalho Chehab 43569a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = { 43579a0bf528SMauro Carvalho Chehab .delsys = { SYS_ISDBT }, 43589a0bf528SMauro Carvalho Chehab .info = { 43599a0bf528SMauro Carvalho Chehab .name = "DiBcom 8000 ISDB-T", 43609a0bf528SMauro Carvalho Chehab .frequency_min = 44250000, 43619a0bf528SMauro Carvalho Chehab .frequency_max = 867250000, 43629a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 43639a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | 43649a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 43659a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 43669a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 43679a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, 43689a0bf528SMauro Carvalho Chehab }, 43699a0bf528SMauro Carvalho Chehab 43709a0bf528SMauro Carvalho Chehab .release = dib8000_release, 43719a0bf528SMauro Carvalho Chehab 43729a0bf528SMauro Carvalho Chehab .init = dib8000_wakeup, 43739a0bf528SMauro Carvalho Chehab .sleep = dib8000_sleep, 43749a0bf528SMauro Carvalho Chehab 43759a0bf528SMauro Carvalho Chehab .set_frontend = dib8000_set_frontend, 43769a0bf528SMauro Carvalho Chehab .get_tune_settings = dib8000_fe_get_tune_settings, 43779a0bf528SMauro Carvalho Chehab .get_frontend = dib8000_get_frontend, 43789a0bf528SMauro Carvalho Chehab 43799a0bf528SMauro Carvalho Chehab .read_status = dib8000_read_status, 43809a0bf528SMauro Carvalho Chehab .read_ber = dib8000_read_ber, 43819a0bf528SMauro Carvalho Chehab .read_signal_strength = dib8000_read_signal_strength, 43829a0bf528SMauro Carvalho Chehab .read_snr = dib8000_read_snr, 43839a0bf528SMauro Carvalho Chehab .read_ucblocks = dib8000_read_unc_blocks, 43849a0bf528SMauro Carvalho Chehab }; 43859a0bf528SMauro Carvalho Chehab 4386d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) 43879a0bf528SMauro Carvalho Chehab { 43889a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe; 43899a0bf528SMauro Carvalho Chehab struct dib8000_state *state; 43909a0bf528SMauro Carvalho Chehab 4391b9bc7d59SMauro Carvalho Chehab dprintk("dib8000_init"); 43929a0bf528SMauro Carvalho Chehab 43939a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); 43949a0bf528SMauro Carvalho Chehab if (state == NULL) 43959a0bf528SMauro Carvalho Chehab return NULL; 43969a0bf528SMauro Carvalho Chehab fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); 43979a0bf528SMauro Carvalho Chehab if (fe == NULL) 43989a0bf528SMauro Carvalho Chehab goto error; 43999a0bf528SMauro Carvalho Chehab 44009a0bf528SMauro Carvalho Chehab memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); 44019a0bf528SMauro Carvalho Chehab state->i2c.adap = i2c_adap; 44029a0bf528SMauro Carvalho Chehab state->i2c.addr = i2c_addr; 44039a0bf528SMauro Carvalho Chehab state->i2c.i2c_write_buffer = state->i2c_write_buffer; 44049a0bf528SMauro Carvalho Chehab state->i2c.i2c_read_buffer = state->i2c_read_buffer; 44059a0bf528SMauro Carvalho Chehab mutex_init(&state->i2c_buffer_lock); 44069a0bf528SMauro Carvalho Chehab state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock; 44079a0bf528SMauro Carvalho Chehab state->gpio_val = cfg->gpio_val; 44089a0bf528SMauro Carvalho Chehab state->gpio_dir = cfg->gpio_dir; 44099a0bf528SMauro Carvalho Chehab 44109a0bf528SMauro Carvalho Chehab /* Ensure the output mode remains at the previous default if it's 44119a0bf528SMauro Carvalho Chehab * not specifically set by the caller. 44129a0bf528SMauro Carvalho Chehab */ 44139a0bf528SMauro Carvalho Chehab if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) 44149a0bf528SMauro Carvalho Chehab state->cfg.output_mode = OUTMODE_MPEG2_FIFO; 44159a0bf528SMauro Carvalho Chehab 44169a0bf528SMauro Carvalho Chehab state->fe[0] = fe; 44179a0bf528SMauro Carvalho Chehab fe->demodulator_priv = state; 44189a0bf528SMauro Carvalho Chehab memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); 44199a0bf528SMauro Carvalho Chehab 44209a0bf528SMauro Carvalho Chehab state->timf_default = cfg->pll->timf; 44219a0bf528SMauro Carvalho Chehab 44229a0bf528SMauro Carvalho Chehab if (dib8000_identify(&state->i2c) == 0) 44239a0bf528SMauro Carvalho Chehab goto error; 44249a0bf528SMauro Carvalho Chehab 44259a0bf528SMauro Carvalho Chehab dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); 44269a0bf528SMauro Carvalho Chehab 44279a0bf528SMauro Carvalho Chehab /* init 8096p tuner adapter */ 44289a0bf528SMauro Carvalho Chehab strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", 44299a0bf528SMauro Carvalho Chehab sizeof(state->dib8096p_tuner_adap.name)); 44309a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo; 44319a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo_data = NULL; 44329a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent; 44339a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&state->dib8096p_tuner_adap, state); 44349a0bf528SMauro Carvalho Chehab i2c_add_adapter(&state->dib8096p_tuner_adap); 44359a0bf528SMauro Carvalho Chehab 44369a0bf528SMauro Carvalho Chehab dib8000_reset(fe); 44379a0bf528SMauro Carvalho Chehab 44389a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ 4439173a64cbSPatrick Boettcher state->current_demod_bw = 6000; 44409a0bf528SMauro Carvalho Chehab 44419a0bf528SMauro Carvalho Chehab return fe; 44429a0bf528SMauro Carvalho Chehab 44439a0bf528SMauro Carvalho Chehab error: 44449a0bf528SMauro Carvalho Chehab kfree(state); 44459a0bf528SMauro Carvalho Chehab return NULL; 44469a0bf528SMauro Carvalho Chehab } 44479a0bf528SMauro Carvalho Chehab 4448d44913c1SMauro Carvalho Chehab void *dib8000_attach(struct dib8000_ops *ops) 4449d44913c1SMauro Carvalho Chehab { 4450d44913c1SMauro Carvalho Chehab if (!ops) 4451d44913c1SMauro Carvalho Chehab return NULL; 4452d44913c1SMauro Carvalho Chehab 4453d44913c1SMauro Carvalho Chehab ops->pwm_agc_reset = dib8000_pwm_agc_reset; 4454d44913c1SMauro Carvalho Chehab ops->get_dc_power = dib8090p_get_dc_power; 4455d44913c1SMauro Carvalho Chehab ops->set_gpio = dib8000_set_gpio; 4456d44913c1SMauro Carvalho Chehab ops->get_slave_frontend = dib8000_get_slave_frontend; 4457d44913c1SMauro Carvalho Chehab ops->set_tune_state = dib8000_set_tune_state; 4458d44913c1SMauro Carvalho Chehab ops->pid_filter_ctrl = dib8000_pid_filter_ctrl; 4459d44913c1SMauro Carvalho Chehab ops->remove_slave_frontend = dib8000_remove_slave_frontend; 4460d44913c1SMauro Carvalho Chehab ops->get_adc_power = dib8000_get_adc_power; 4461d44913c1SMauro Carvalho Chehab ops->update_pll = dib8000_update_pll; 4462d44913c1SMauro Carvalho Chehab ops->tuner_sleep = dib8096p_tuner_sleep; 4463d44913c1SMauro Carvalho Chehab ops->get_tune_state = dib8000_get_tune_state; 4464d44913c1SMauro Carvalho Chehab ops->get_i2c_tuner = dib8096p_get_i2c_tuner; 4465d44913c1SMauro Carvalho Chehab ops->set_slave_frontend = dib8000_set_slave_frontend; 4466d44913c1SMauro Carvalho Chehab ops->pid_filter = dib8000_pid_filter; 4467d44913c1SMauro Carvalho Chehab ops->ctrl_timf = dib8000_ctrl_timf; 4468d44913c1SMauro Carvalho Chehab ops->init = dib8000_init; 4469d44913c1SMauro Carvalho Chehab ops->get_i2c_master = dib8000_get_i2c_master; 4470d44913c1SMauro Carvalho Chehab ops->i2c_enumeration = dib8000_i2c_enumeration; 4471d44913c1SMauro Carvalho Chehab ops->set_wbd_ref = dib8000_set_wbd_ref; 4472d44913c1SMauro Carvalho Chehab 4473d44913c1SMauro Carvalho Chehab return ops; 4474d44913c1SMauro Carvalho Chehab } 4475d44913c1SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_attach); 44769a0bf528SMauro Carvalho Chehab 44779a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>"); 44789a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator"); 44799a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 4480