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> 149a0bf528SMauro Carvalho Chehab 159a0bf528SMauro Carvalho Chehab #include "dvb_math.h" 169a0bf528SMauro Carvalho Chehab 179a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h" 189a0bf528SMauro Carvalho Chehab 199a0bf528SMauro Carvalho Chehab #include "dib8000.h" 209a0bf528SMauro Carvalho Chehab 219a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1 229a0bf528SMauro Carvalho Chehab #define LAYER_A 1 239a0bf528SMauro Carvalho Chehab #define LAYER_B 2 249a0bf528SMauro Carvalho Chehab #define LAYER_C 3 259a0bf528SMauro Carvalho Chehab 269a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6 27173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */ 289a0bf528SMauro Carvalho Chehab 299a0bf528SMauro Carvalho Chehab static int debug; 309a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 319a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 329a0bf528SMauro Carvalho Chehab 339a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) 349a0bf528SMauro Carvalho Chehab 359a0bf528SMauro Carvalho Chehab struct i2c_device { 369a0bf528SMauro Carvalho Chehab struct i2c_adapter *adap; 379a0bf528SMauro Carvalho Chehab u8 addr; 389a0bf528SMauro Carvalho Chehab u8 *i2c_write_buffer; 399a0bf528SMauro Carvalho Chehab u8 *i2c_read_buffer; 409a0bf528SMauro Carvalho Chehab struct mutex *i2c_buffer_lock; 419a0bf528SMauro Carvalho Chehab }; 429a0bf528SMauro Carvalho Chehab 43173a64cbSPatrick Boettcher enum param_loop_step { 44173a64cbSPatrick Boettcher LOOP_TUNE_1, 45173a64cbSPatrick Boettcher LOOP_TUNE_2 46173a64cbSPatrick Boettcher }; 47173a64cbSPatrick Boettcher 48173a64cbSPatrick Boettcher enum dib8000_autosearch_step { 49173a64cbSPatrick Boettcher AS_START = 0, 50173a64cbSPatrick Boettcher AS_SEARCHING_FFT, 51173a64cbSPatrick Boettcher AS_SEARCHING_GUARD, 52173a64cbSPatrick Boettcher AS_DONE = 100, 53173a64cbSPatrick Boettcher }; 54173a64cbSPatrick Boettcher 55173a64cbSPatrick Boettcher enum timeout_mode { 56173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_OFF = 0, 57173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_ON, 58173a64cbSPatrick Boettcher }; 59173a64cbSPatrick Boettcher 609a0bf528SMauro Carvalho Chehab struct dib8000_state { 619a0bf528SMauro Carvalho Chehab struct dib8000_config cfg; 629a0bf528SMauro Carvalho Chehab 639a0bf528SMauro Carvalho Chehab struct i2c_device i2c; 649a0bf528SMauro Carvalho Chehab 659a0bf528SMauro Carvalho Chehab struct dibx000_i2c_master i2c_master; 669a0bf528SMauro Carvalho Chehab 679a0bf528SMauro Carvalho Chehab u16 wbd_ref; 689a0bf528SMauro Carvalho Chehab 699a0bf528SMauro Carvalho Chehab u8 current_band; 709a0bf528SMauro Carvalho Chehab u32 current_bandwidth; 719a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *current_agc; 729a0bf528SMauro Carvalho Chehab u32 timf; 739a0bf528SMauro Carvalho Chehab u32 timf_default; 749a0bf528SMauro Carvalho Chehab 759a0bf528SMauro Carvalho Chehab u8 div_force_off:1; 769a0bf528SMauro Carvalho Chehab u8 div_state:1; 779a0bf528SMauro Carvalho Chehab u16 div_sync_wait; 789a0bf528SMauro Carvalho Chehab 799a0bf528SMauro Carvalho Chehab u8 agc_state; 809a0bf528SMauro Carvalho Chehab u8 differential_constellation; 819a0bf528SMauro Carvalho Chehab u8 diversity_onoff; 829a0bf528SMauro Carvalho Chehab 839a0bf528SMauro Carvalho Chehab s16 ber_monitored_layer; 849a0bf528SMauro Carvalho Chehab u16 gpio_dir; 859a0bf528SMauro Carvalho Chehab u16 gpio_val; 869a0bf528SMauro Carvalho Chehab 879a0bf528SMauro Carvalho Chehab u16 revision; 889a0bf528SMauro Carvalho Chehab u8 isdbt_cfg_loaded; 899a0bf528SMauro Carvalho Chehab enum frontend_tune_state tune_state; 90173a64cbSPatrick Boettcher s32 status; 919a0bf528SMauro Carvalho Chehab 929a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; 939a0bf528SMauro Carvalho Chehab 949a0bf528SMauro Carvalho Chehab /* for the I2C transfer */ 959a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2]; 969a0bf528SMauro Carvalho Chehab u8 i2c_write_buffer[4]; 979a0bf528SMauro Carvalho Chehab u8 i2c_read_buffer[2]; 989a0bf528SMauro Carvalho Chehab struct mutex i2c_buffer_lock; 999a0bf528SMauro Carvalho Chehab u8 input_mode_mpeg; 1009a0bf528SMauro Carvalho Chehab 1019a0bf528SMauro Carvalho Chehab u16 tuner_enable; 1029a0bf528SMauro Carvalho Chehab struct i2c_adapter dib8096p_tuner_adap; 103173a64cbSPatrick Boettcher u16 current_demod_bw; 104173a64cbSPatrick Boettcher 105173a64cbSPatrick Boettcher u16 seg_mask; 106173a64cbSPatrick Boettcher u16 seg_diff_mask; 107173a64cbSPatrick Boettcher u16 mode; 108173a64cbSPatrick Boettcher u8 layer_b_nb_seg; 109173a64cbSPatrick Boettcher u8 layer_c_nb_seg; 110173a64cbSPatrick Boettcher 111173a64cbSPatrick Boettcher u8 channel_parameters_set; 112173a64cbSPatrick Boettcher u16 autosearch_state; 113173a64cbSPatrick Boettcher u16 found_nfft; 114173a64cbSPatrick Boettcher u16 found_guard; 115173a64cbSPatrick Boettcher u8 subchannel; 116173a64cbSPatrick Boettcher u8 symbol_duration; 117173a64cbSPatrick Boettcher u32 timeout; 118173a64cbSPatrick Boettcher u8 longest_intlv_layer; 119173a64cbSPatrick Boettcher u16 output_mode; 120173a64cbSPatrick Boettcher 121173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 122173a64cbSPatrick Boettcher u16 agc1_max; 123173a64cbSPatrick Boettcher u16 agc1_min; 124173a64cbSPatrick Boettcher u16 agc2_max; 125173a64cbSPatrick Boettcher u16 agc2_min; 126173a64cbSPatrick Boettcher #endif 1279a0bf528SMauro Carvalho Chehab }; 1289a0bf528SMauro Carvalho Chehab 1299a0bf528SMauro Carvalho Chehab enum dib8000_power_mode { 1309a0bf528SMauro Carvalho Chehab DIB8000_POWER_ALL = 0, 1319a0bf528SMauro Carvalho Chehab DIB8000_POWER_INTERFACE_ONLY, 1329a0bf528SMauro Carvalho Chehab }; 1339a0bf528SMauro Carvalho Chehab 1349a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) 1359a0bf528SMauro Carvalho Chehab { 1369a0bf528SMauro Carvalho Chehab u16 ret; 1379a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2] = { 1389a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = 0, .len = 2}, 1399a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2}, 1409a0bf528SMauro Carvalho Chehab }; 1419a0bf528SMauro Carvalho Chehab 1429a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { 1439a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 1449a0bf528SMauro Carvalho Chehab return 0; 1459a0bf528SMauro Carvalho Chehab } 1469a0bf528SMauro Carvalho Chehab 1479a0bf528SMauro Carvalho Chehab msg[0].buf = i2c->i2c_write_buffer; 1489a0bf528SMauro Carvalho Chehab msg[0].buf[0] = reg >> 8; 1499a0bf528SMauro Carvalho Chehab msg[0].buf[1] = reg & 0xff; 1509a0bf528SMauro Carvalho Chehab msg[1].buf = i2c->i2c_read_buffer; 1519a0bf528SMauro Carvalho Chehab 1529a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c->adap, msg, 2) != 2) 1539a0bf528SMauro Carvalho Chehab dprintk("i2c read error on %d", reg); 1549a0bf528SMauro Carvalho Chehab 1559a0bf528SMauro Carvalho Chehab ret = (msg[1].buf[0] << 8) | msg[1].buf[1]; 1569a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock); 1579a0bf528SMauro Carvalho Chehab return ret; 1589a0bf528SMauro Carvalho Chehab } 1599a0bf528SMauro Carvalho Chehab 1605ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg) 1619a0bf528SMauro Carvalho Chehab { 1629a0bf528SMauro Carvalho Chehab u16 ret; 1639a0bf528SMauro Carvalho Chehab 1649a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = reg >> 8; 1659a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 1669a0bf528SMauro Carvalho Chehab 1679a0bf528SMauro Carvalho Chehab memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 1689a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1; 1699a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 1709a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 1719a0bf528SMauro Carvalho Chehab state->msg[0].len = 2; 1729a0bf528SMauro Carvalho Chehab state->msg[1].addr = state->i2c.addr >> 1; 1739a0bf528SMauro Carvalho Chehab state->msg[1].flags = I2C_M_RD; 1749a0bf528SMauro Carvalho Chehab state->msg[1].buf = state->i2c_read_buffer; 1759a0bf528SMauro Carvalho Chehab state->msg[1].len = 2; 1769a0bf528SMauro Carvalho Chehab 1779a0bf528SMauro Carvalho Chehab if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) 1789a0bf528SMauro Carvalho Chehab dprintk("i2c read error on %d", reg); 1799a0bf528SMauro Carvalho Chehab 1809a0bf528SMauro Carvalho Chehab ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 1815ac64ba1SMauro Carvalho Chehab 1825ac64ba1SMauro Carvalho Chehab return ret; 1835ac64ba1SMauro Carvalho Chehab } 1845ac64ba1SMauro Carvalho Chehab 1855ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) 1865ac64ba1SMauro Carvalho Chehab { 1875ac64ba1SMauro Carvalho Chehab u16 ret; 1885ac64ba1SMauro Carvalho Chehab 1895ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 1905ac64ba1SMauro Carvalho Chehab dprintk("could not acquire lock"); 1915ac64ba1SMauro Carvalho Chehab return 0; 1925ac64ba1SMauro Carvalho Chehab } 1935ac64ba1SMauro Carvalho Chehab 1945ac64ba1SMauro Carvalho Chehab ret = __dib8000_read_word(state, reg); 1955ac64ba1SMauro Carvalho Chehab 1969a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 1979a0bf528SMauro Carvalho Chehab 1989a0bf528SMauro Carvalho Chehab return ret; 1999a0bf528SMauro Carvalho Chehab } 2009a0bf528SMauro Carvalho Chehab 2019a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg) 2029a0bf528SMauro Carvalho Chehab { 2039a0bf528SMauro Carvalho Chehab u16 rw[2]; 2049a0bf528SMauro Carvalho Chehab 2055ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 2065ac64ba1SMauro Carvalho Chehab dprintk("could not acquire lock"); 2075ac64ba1SMauro Carvalho Chehab return 0; 2085ac64ba1SMauro Carvalho Chehab } 2095ac64ba1SMauro Carvalho Chehab 2105ac64ba1SMauro Carvalho Chehab rw[0] = __dib8000_read_word(state, reg + 0); 2115ac64ba1SMauro Carvalho Chehab rw[1] = __dib8000_read_word(state, reg + 1); 2125ac64ba1SMauro Carvalho Chehab 2135ac64ba1SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2149a0bf528SMauro Carvalho Chehab 2159a0bf528SMauro Carvalho Chehab return ((rw[0] << 16) | (rw[1])); 2169a0bf528SMauro Carvalho Chehab } 2179a0bf528SMauro Carvalho Chehab 2189a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) 2199a0bf528SMauro Carvalho Chehab { 2209a0bf528SMauro Carvalho Chehab struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4}; 2219a0bf528SMauro Carvalho Chehab int ret = 0; 2229a0bf528SMauro Carvalho Chehab 2239a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { 2249a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 2259a0bf528SMauro Carvalho Chehab return -EINVAL; 2269a0bf528SMauro Carvalho Chehab } 2279a0bf528SMauro Carvalho Chehab 2289a0bf528SMauro Carvalho Chehab msg.buf = i2c->i2c_write_buffer; 2299a0bf528SMauro Carvalho Chehab msg.buf[0] = (reg >> 8) & 0xff; 2309a0bf528SMauro Carvalho Chehab msg.buf[1] = reg & 0xff; 2319a0bf528SMauro Carvalho Chehab msg.buf[2] = (val >> 8) & 0xff; 2329a0bf528SMauro Carvalho Chehab msg.buf[3] = val & 0xff; 2339a0bf528SMauro Carvalho Chehab 2349a0bf528SMauro Carvalho Chehab ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; 2359a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock); 2369a0bf528SMauro Carvalho Chehab 2379a0bf528SMauro Carvalho Chehab return ret; 2389a0bf528SMauro Carvalho Chehab } 2399a0bf528SMauro Carvalho Chehab 2409a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) 2419a0bf528SMauro Carvalho Chehab { 2429a0bf528SMauro Carvalho Chehab int ret; 2439a0bf528SMauro Carvalho Chehab 2449a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 2459a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 2469a0bf528SMauro Carvalho Chehab return -EINVAL; 2479a0bf528SMauro Carvalho Chehab } 2489a0bf528SMauro Carvalho Chehab 2499a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = (reg >> 8) & 0xff; 2509a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 2519a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[2] = (val >> 8) & 0xff; 2529a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[3] = val & 0xff; 2539a0bf528SMauro Carvalho Chehab 2549a0bf528SMauro Carvalho Chehab memset(&state->msg[0], 0, sizeof(struct i2c_msg)); 2559a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1; 2569a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 2579a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 2589a0bf528SMauro Carvalho Chehab state->msg[0].len = 4; 2599a0bf528SMauro Carvalho Chehab 2609a0bf528SMauro Carvalho Chehab ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? 2619a0bf528SMauro Carvalho Chehab -EREMOTEIO : 0); 2629a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 2639a0bf528SMauro Carvalho Chehab 2649a0bf528SMauro Carvalho Chehab return ret; 2659a0bf528SMauro Carvalho Chehab } 2669a0bf528SMauro Carvalho Chehab 2679a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = { 2689a0bf528SMauro Carvalho Chehab (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, 2699a0bf528SMauro Carvalho Chehab (920 << 5) | 0x09 2709a0bf528SMauro Carvalho Chehab }; 2719a0bf528SMauro Carvalho Chehab 2729a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = { 2739a0bf528SMauro Carvalho Chehab (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f 2749a0bf528SMauro Carvalho Chehab }; 2759a0bf528SMauro Carvalho Chehab 2769a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { 2779a0bf528SMauro Carvalho Chehab (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, 2789a0bf528SMauro Carvalho Chehab (-931 << 5) | 0x0f 2799a0bf528SMauro Carvalho Chehab }; 2809a0bf528SMauro Carvalho Chehab 2819a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = { 2829a0bf528SMauro Carvalho Chehab (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, 2839a0bf528SMauro Carvalho Chehab (982 << 5) | 0x0c 2849a0bf528SMauro Carvalho Chehab }; 2859a0bf528SMauro Carvalho Chehab 2869a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = { 2879a0bf528SMauro Carvalho Chehab (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, 2889a0bf528SMauro Carvalho Chehab (-720 << 5) | 0x0d 2899a0bf528SMauro Carvalho Chehab }; 2909a0bf528SMauro Carvalho Chehab 2919a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = { 2929a0bf528SMauro Carvalho Chehab (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, 2939a0bf528SMauro Carvalho Chehab (-610 << 5) | 0x0a 2949a0bf528SMauro Carvalho Chehab }; 2959a0bf528SMauro Carvalho Chehab 2969a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = { 2979a0bf528SMauro Carvalho Chehab (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, 2989a0bf528SMauro Carvalho Chehab (-922 << 5) | 0x0d 2999a0bf528SMauro Carvalho Chehab }; 3009a0bf528SMauro Carvalho Chehab 3019a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = { 3029a0bf528SMauro Carvalho Chehab (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, 3039a0bf528SMauro Carvalho Chehab (-655 << 5) | 0x0a 3049a0bf528SMauro Carvalho Chehab }; 3059a0bf528SMauro Carvalho Chehab 3069a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { 3079a0bf528SMauro Carvalho Chehab (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, 3089a0bf528SMauro Carvalho Chehab (-958 << 5) | 0x13 3099a0bf528SMauro Carvalho Chehab }; 3109a0bf528SMauro Carvalho Chehab 3119a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = { 3129a0bf528SMauro Carvalho Chehab (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, 3139a0bf528SMauro Carvalho Chehab (-568 << 5) | 0x0f 3149a0bf528SMauro Carvalho Chehab }; 3159a0bf528SMauro Carvalho Chehab 3169a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = { 3179a0bf528SMauro Carvalho Chehab (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, 3189a0bf528SMauro Carvalho Chehab (-848 << 5) | 0x13 3199a0bf528SMauro Carvalho Chehab }; 3209a0bf528SMauro Carvalho Chehab 3219a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = { 3229a0bf528SMauro Carvalho Chehab (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, 3239a0bf528SMauro Carvalho Chehab (-869 << 5) | 0x13 3249a0bf528SMauro Carvalho Chehab }; 3259a0bf528SMauro Carvalho Chehab 3269a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = { 3279a0bf528SMauro Carvalho Chehab (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, 3289a0bf528SMauro Carvalho Chehab (-598 << 5) | 0x10 3299a0bf528SMauro Carvalho Chehab }; 3309a0bf528SMauro Carvalho Chehab 3319a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = { 3329a0bf528SMauro Carvalho Chehab (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, 3339a0bf528SMauro Carvalho Chehab (585 << 5) | 0x0f 3349a0bf528SMauro Carvalho Chehab }; 3359a0bf528SMauro Carvalho Chehab 3369a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { 3379a0bf528SMauro Carvalho Chehab (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, 3389a0bf528SMauro Carvalho Chehab (0 << 5) | 0x14 3399a0bf528SMauro Carvalho Chehab }; 3409a0bf528SMauro Carvalho Chehab 3419a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = { 3429a0bf528SMauro Carvalho Chehab (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, 3439a0bf528SMauro Carvalho Chehab (-877 << 5) | 0x15 3449a0bf528SMauro Carvalho Chehab }; 3459a0bf528SMauro Carvalho Chehab 3469a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = { 3479a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, 3489a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x14 3499a0bf528SMauro Carvalho Chehab }; 3509a0bf528SMauro Carvalho Chehab 3519a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = { 3529a0bf528SMauro Carvalho Chehab (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, 3539a0bf528SMauro Carvalho Chehab (690 << 5) | 0x14 3549a0bf528SMauro Carvalho Chehab }; 3559a0bf528SMauro Carvalho Chehab 3569a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = { 3579a0bf528SMauro 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 3589a0bf528SMauro Carvalho Chehab }; 3599a0bf528SMauro Carvalho Chehab 3609a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = { 3619a0bf528SMauro 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 3629a0bf528SMauro Carvalho Chehab }; 3639a0bf528SMauro Carvalho Chehab 3649a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = { 3659a0bf528SMauro 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 3669a0bf528SMauro Carvalho Chehab }; 3679a0bf528SMauro Carvalho Chehab 3689a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state) 3699a0bf528SMauro Carvalho Chehab { 3709a0bf528SMauro Carvalho Chehab u16 mode; 3719a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) { 3729a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 3739a0bf528SMauro Carvalho Chehab mode = 1; 3749a0bf528SMauro Carvalho Chehab break; 3759a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 3769a0bf528SMauro Carvalho Chehab mode = 2; 3779a0bf528SMauro Carvalho Chehab break; 3789a0bf528SMauro Carvalho Chehab default: 3799a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_AUTO: 3809a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 3819a0bf528SMauro Carvalho Chehab mode = 3; 3829a0bf528SMauro Carvalho Chehab break; 3839a0bf528SMauro Carvalho Chehab } 3849a0bf528SMauro Carvalho Chehab return mode; 3859a0bf528SMauro Carvalho Chehab } 3869a0bf528SMauro Carvalho Chehab 3879a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state) 3889a0bf528SMauro Carvalho Chehab { 3899a0bf528SMauro Carvalho Chehab u16 nud = dib8000_read_word(state, 298); 3909a0bf528SMauro Carvalho Chehab nud |= (1 << 3) | (1 << 0); 3919a0bf528SMauro Carvalho Chehab dprintk("acquisition mode activated"); 3929a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 298, nud); 3939a0bf528SMauro Carvalho Chehab } 3949a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) 3959a0bf528SMauro Carvalho Chehab { 3969a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 3979a0bf528SMauro Carvalho Chehab u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ 3989a0bf528SMauro Carvalho Chehab 399173a64cbSPatrick Boettcher state->output_mode = mode; 4009a0bf528SMauro Carvalho Chehab outreg = 0; 4019a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 4029a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); 4039a0bf528SMauro Carvalho Chehab 4049a0bf528SMauro Carvalho Chehab dprintk("-I- Setting output mode for demod %p to %d", 4059a0bf528SMauro Carvalho Chehab &state->fe[0], mode); 4069a0bf528SMauro Carvalho Chehab 4079a0bf528SMauro Carvalho Chehab switch (mode) { 4089a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock 4099a0bf528SMauro Carvalho Chehab outreg = (1 << 10); /* 0x0400 */ 4109a0bf528SMauro Carvalho Chehab break; 4119a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock 4129a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (1 << 6); /* 0x0440 */ 4139a0bf528SMauro Carvalho Chehab break; 4149a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: // STBs with serial input 4159a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ 4169a0bf528SMauro Carvalho Chehab break; 4179a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 4189a0bf528SMauro Carvalho Chehab if (state->cfg.hostbus_diversity) { 4199a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (4 << 6); /* 0x0500 */ 4209a0bf528SMauro Carvalho Chehab sram &= 0xfdff; 4219a0bf528SMauro Carvalho Chehab } else 4229a0bf528SMauro Carvalho Chehab sram |= 0x0c00; 4239a0bf528SMauro Carvalho Chehab break; 4249a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: // e.g. USB feeding 4259a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 4269a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 4279a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (5 << 6); 4289a0bf528SMauro Carvalho Chehab break; 4299a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: // disable 4309a0bf528SMauro Carvalho Chehab outreg = 0; 4319a0bf528SMauro Carvalho Chehab break; 4329a0bf528SMauro Carvalho Chehab 4339a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 4349a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (3 << 6); 4359a0bf528SMauro Carvalho Chehab dib8000_set_acquisition_mode(state); 4369a0bf528SMauro Carvalho Chehab break; 4379a0bf528SMauro Carvalho Chehab 4389a0bf528SMauro Carvalho Chehab default: 4399a0bf528SMauro Carvalho Chehab dprintk("Unhandled output_mode passed to be set for demod %p", 4409a0bf528SMauro Carvalho Chehab &state->fe[0]); 4419a0bf528SMauro Carvalho Chehab return -EINVAL; 4429a0bf528SMauro Carvalho Chehab } 4439a0bf528SMauro Carvalho Chehab 4449a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 4459a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 4469a0bf528SMauro Carvalho Chehab 4479a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 299, smo_mode); 4489a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */ 4499a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1286, outreg); 4509a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1291, sram); 4519a0bf528SMauro Carvalho Chehab 4529a0bf528SMauro Carvalho Chehab return 0; 4539a0bf528SMauro Carvalho Chehab } 4549a0bf528SMauro Carvalho Chehab 4559a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) 4569a0bf528SMauro Carvalho Chehab { 4579a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 458173a64cbSPatrick Boettcher u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0; 4599a0bf528SMauro Carvalho Chehab 460173a64cbSPatrick Boettcher dprintk("set diversity input to %i", onoff); 4619a0bf528SMauro Carvalho Chehab if (!state->differential_constellation) { 4629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 4639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 4649a0bf528SMauro Carvalho Chehab } else { 4659a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0 4669a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0 4679a0bf528SMauro Carvalho Chehab } 4689a0bf528SMauro Carvalho Chehab state->diversity_onoff = onoff; 4699a0bf528SMauro Carvalho Chehab 4709a0bf528SMauro Carvalho Chehab switch (onoff) { 4719a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */ 4729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 1); 4739a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 0); 4749a0bf528SMauro Carvalho Chehab break; 4759a0bf528SMauro Carvalho Chehab case 1: /* both ways */ 4769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 6); 4779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 6); 4789a0bf528SMauro Carvalho Chehab break; 4799a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */ 4809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 0); 4819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 1); 4829a0bf528SMauro Carvalho Chehab break; 4839a0bf528SMauro Carvalho Chehab } 484173a64cbSPatrick Boettcher 485173a64cbSPatrick Boettcher if (state->revision == 0x8002) { 486173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 903); 487173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp & ~(1 << 3)); 488173a64cbSPatrick Boettcher msleep(30); 489173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp | (1 << 3)); 490173a64cbSPatrick Boettcher } 4919a0bf528SMauro Carvalho Chehab return 0; 4929a0bf528SMauro Carvalho Chehab } 4939a0bf528SMauro Carvalho Chehab 4949a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode) 4959a0bf528SMauro Carvalho Chehab { 4969a0bf528SMauro Carvalho Chehab /* by default everything is going to be powered off */ 4979a0bf528SMauro Carvalho Chehab u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, 4989a0bf528SMauro Carvalho Chehab reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, 4999a0bf528SMauro Carvalho Chehab reg_1280; 5009a0bf528SMauro Carvalho Chehab 5019a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5029a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; 5039a0bf528SMauro Carvalho Chehab else 5049a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80; 5059a0bf528SMauro Carvalho Chehab 5069a0bf528SMauro Carvalho Chehab /* now, depending on the requested mode, we power on */ 5079a0bf528SMauro Carvalho Chehab switch (mode) { 5089a0bf528SMauro Carvalho Chehab /* power up everything in the demod */ 5099a0bf528SMauro Carvalho Chehab case DIB8000_POWER_ALL: 5109a0bf528SMauro Carvalho Chehab reg_774 = 0x0000; 5119a0bf528SMauro Carvalho Chehab reg_775 = 0x0000; 5129a0bf528SMauro Carvalho Chehab reg_776 = 0x0000; 5139a0bf528SMauro Carvalho Chehab reg_900 &= 0xfffc; 5149a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5159a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff; 5169a0bf528SMauro Carvalho Chehab else 5179a0bf528SMauro Carvalho Chehab reg_1280 &= 0x707f; 5189a0bf528SMauro Carvalho Chehab break; 5199a0bf528SMauro Carvalho Chehab case DIB8000_POWER_INTERFACE_ONLY: 5209a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 5219a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff; 5229a0bf528SMauro Carvalho Chehab else 5239a0bf528SMauro Carvalho Chehab reg_1280 &= 0xfa7b; 5249a0bf528SMauro Carvalho Chehab break; 5259a0bf528SMauro Carvalho Chehab } 5269a0bf528SMauro Carvalho Chehab 5279a0bf528SMauro Carvalho Chehab dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280); 5289a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 774, reg_774); 5299a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 775, reg_775); 5309a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 776, reg_776); 5319a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 900, reg_900); 5329a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, reg_1280); 5339a0bf528SMauro Carvalho Chehab } 5349a0bf528SMauro Carvalho Chehab 5359a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) 5369a0bf528SMauro Carvalho Chehab { 5379a0bf528SMauro Carvalho Chehab int ret = 0; 5389a0bf528SMauro Carvalho Chehab u16 reg, reg_907 = dib8000_read_word(state, 907); 5399a0bf528SMauro Carvalho Chehab u16 reg_908 = dib8000_read_word(state, 908); 5409a0bf528SMauro Carvalho Chehab 5419a0bf528SMauro Carvalho Chehab switch (no) { 5429a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_ON: 5439a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 5449a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0); 5459a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908); 5469a0bf528SMauro Carvalho Chehab reg_908 &= ~(1 << 1); 5479a0bf528SMauro Carvalho Chehab } else { 5489a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5499a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 1 */ 5509a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg | 5519a0bf528SMauro Carvalho Chehab (1<<4) | (1<<2)); 5529a0bf528SMauro Carvalho Chehab 5539a0bf528SMauro Carvalho Chehab /* read acces to make it works... strange ... */ 5549a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5559a0bf528SMauro Carvalho Chehab msleep(20); 5569a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 0 */ 5579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg & ~(1<<4)); 5589a0bf528SMauro Carvalho Chehab 5599a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 921) & ~((0x3 << 14) 5609a0bf528SMauro Carvalho Chehab | (0x3 << 12)); 5619a0bf528SMauro Carvalho Chehab /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; 5629a0bf528SMauro Carvalho Chehab (Vin2 = Vcm) */ 5639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, reg | (1 << 14) 5649a0bf528SMauro Carvalho Chehab | (3 << 12)); 5659a0bf528SMauro Carvalho Chehab } 5669a0bf528SMauro Carvalho Chehab break; 5679a0bf528SMauro Carvalho Chehab 5689a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_OFF: 5699a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 5709a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925); 5719a0bf528SMauro Carvalho Chehab /* reset_sladc = 1 en_slowAdc = 0 */ 5729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, 5739a0bf528SMauro Carvalho Chehab (reg & ~(1<<2)) | (1<<4)); 5749a0bf528SMauro Carvalho Chehab } 5759a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0); 5769a0bf528SMauro Carvalho Chehab break; 5779a0bf528SMauro Carvalho Chehab 5789a0bf528SMauro Carvalho Chehab case DIBX000_ADC_ON: 5799a0bf528SMauro Carvalho Chehab reg_907 &= 0x0fff; 5809a0bf528SMauro Carvalho Chehab reg_908 &= 0x0003; 5819a0bf528SMauro Carvalho Chehab break; 5829a0bf528SMauro Carvalho Chehab 5839a0bf528SMauro Carvalho Chehab case DIBX000_ADC_OFF: // leave the VBG voltage on 5849a0bf528SMauro Carvalho Chehab reg_907 |= (1 << 14) | (1 << 13) | (1 << 12); 5859a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); 5869a0bf528SMauro Carvalho Chehab break; 5879a0bf528SMauro Carvalho Chehab 5889a0bf528SMauro Carvalho Chehab case DIBX000_VBG_ENABLE: 5899a0bf528SMauro Carvalho Chehab reg_907 &= ~(1 << 15); 5909a0bf528SMauro Carvalho Chehab break; 5919a0bf528SMauro Carvalho Chehab 5929a0bf528SMauro Carvalho Chehab case DIBX000_VBG_DISABLE: 5939a0bf528SMauro Carvalho Chehab reg_907 |= (1 << 15); 5949a0bf528SMauro Carvalho Chehab break; 5959a0bf528SMauro Carvalho Chehab 5969a0bf528SMauro Carvalho Chehab default: 5979a0bf528SMauro Carvalho Chehab break; 5989a0bf528SMauro Carvalho Chehab } 5999a0bf528SMauro Carvalho Chehab 6009a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 907, reg_907); 6019a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908); 6029a0bf528SMauro Carvalho Chehab 6039a0bf528SMauro Carvalho Chehab return ret; 6049a0bf528SMauro Carvalho Chehab } 6059a0bf528SMauro Carvalho Chehab 6069a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) 6079a0bf528SMauro Carvalho Chehab { 6089a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 6099a0bf528SMauro Carvalho Chehab u32 timf; 6109a0bf528SMauro Carvalho Chehab 6119a0bf528SMauro Carvalho Chehab if (bw == 0) 6129a0bf528SMauro Carvalho Chehab bw = 6000; 6139a0bf528SMauro Carvalho Chehab 6149a0bf528SMauro Carvalho Chehab if (state->timf == 0) { 6159a0bf528SMauro Carvalho Chehab dprintk("using default timf"); 6169a0bf528SMauro Carvalho Chehab timf = state->timf_default; 6179a0bf528SMauro Carvalho Chehab } else { 6189a0bf528SMauro Carvalho Chehab dprintk("using updated timf"); 6199a0bf528SMauro Carvalho Chehab timf = state->timf; 6209a0bf528SMauro Carvalho Chehab } 6219a0bf528SMauro Carvalho Chehab 6229a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff)); 6239a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) ((timf) & 0xffff)); 6249a0bf528SMauro Carvalho Chehab 6259a0bf528SMauro Carvalho Chehab return 0; 6269a0bf528SMauro Carvalho Chehab } 6279a0bf528SMauro Carvalho Chehab 6289a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state) 6299a0bf528SMauro Carvalho Chehab { 630173a64cbSPatrick Boettcher u8 sad_sel = 3; 631173a64cbSPatrick Boettcher 6329a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 633173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2)); 634173a64cbSPatrick Boettcher dib8000_write_word(state, 923, 2048); 635173a64cbSPatrick Boettcher 636173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2) | 0x1); 637173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2)); 638173a64cbSPatrick Boettcher } else { 6399a0bf528SMauro Carvalho Chehab /* internal */ 6409a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); 641173a64cbSPatrick Boettcher dib8000_write_word(state, 924, 776); 6429a0bf528SMauro Carvalho Chehab 6439a0bf528SMauro Carvalho Chehab /* do the calibration */ 6449a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (1 << 0)); 6459a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 0)); 646173a64cbSPatrick Boettcher } 6479a0bf528SMauro Carvalho Chehab 6489a0bf528SMauro Carvalho Chehab msleep(1); 6499a0bf528SMauro Carvalho Chehab return 0; 6509a0bf528SMauro Carvalho Chehab } 6519a0bf528SMauro Carvalho Chehab 6529a0bf528SMauro Carvalho Chehab int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) 6539a0bf528SMauro Carvalho Chehab { 6549a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 6559a0bf528SMauro Carvalho Chehab if (value > 4095) 6569a0bf528SMauro Carvalho Chehab value = 4095; 6579a0bf528SMauro Carvalho Chehab state->wbd_ref = value; 6589a0bf528SMauro Carvalho Chehab return dib8000_write_word(state, 106, value); 6599a0bf528SMauro Carvalho Chehab } 6609a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_wbd_ref); 661173a64cbSPatrick Boettcher 6629a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) 6639a0bf528SMauro Carvalho Chehab { 6649a0bf528SMauro Carvalho Chehab dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); 6659a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 6669a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, 6679a0bf528SMauro Carvalho Chehab (u16) (((bw->internal * 1000) >> 16) & 0xffff)); 6689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, 6699a0bf528SMauro Carvalho Chehab (u16) ((bw->internal * 1000) & 0xffff)); 6709a0bf528SMauro Carvalho Chehab } else { 6719a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff)); 6729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, 6739a0bf528SMauro Carvalho Chehab (u16) ((bw->internal / 2 * 1000) & 0xffff)); 6749a0bf528SMauro Carvalho Chehab } 6759a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); 6769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); 6779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); 6789a0bf528SMauro Carvalho Chehab 6799a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 6809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, bw->sad_cfg); 6819a0bf528SMauro Carvalho Chehab } 6829a0bf528SMauro Carvalho Chehab 6839a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state) 6849a0bf528SMauro Carvalho Chehab { 6859a0bf528SMauro Carvalho Chehab const struct dibx000_bandwidth_config *pll = state->cfg.pll; 6869a0bf528SMauro Carvalho Chehab u16 clk_cfg1, reg; 6879a0bf528SMauro Carvalho Chehab 6889a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 6899a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 901, 6909a0bf528SMauro Carvalho Chehab (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); 6919a0bf528SMauro Carvalho Chehab 6929a0bf528SMauro Carvalho Chehab clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | 6939a0bf528SMauro Carvalho Chehab (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | 6949a0bf528SMauro Carvalho Chehab (1 << 3) | (pll->pll_range << 1) | 6959a0bf528SMauro Carvalho Chehab (pll->pll_reset << 0); 6969a0bf528SMauro Carvalho Chehab 6979a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1); 6989a0bf528SMauro Carvalho Chehab clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); 6999a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1); 7009a0bf528SMauro Carvalho Chehab 7019a0bf528SMauro Carvalho Chehab dprintk("clk_cfg1: 0x%04x", clk_cfg1); 7029a0bf528SMauro Carvalho Chehab 7039a0bf528SMauro Carvalho Chehab /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ 7049a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ADClkSrc == 0) 7059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, 7069a0bf528SMauro Carvalho Chehab (0 << 15) | (0 << 12) | (0 << 10) | 7079a0bf528SMauro Carvalho Chehab (pll->modulo << 8) | 7089a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7099a0bf528SMauro Carvalho Chehab else if (state->cfg.refclksel != 0) 7109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | 7119a0bf528SMauro Carvalho Chehab ((state->cfg.refclksel & 0x3) << 10) | 7129a0bf528SMauro Carvalho Chehab (pll->modulo << 8) | 7139a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7149a0bf528SMauro Carvalho Chehab else 7159a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | 7169a0bf528SMauro Carvalho Chehab (3 << 10) | (pll->modulo << 8) | 7179a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1)); 7189a0bf528SMauro Carvalho Chehab } else { 7199a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, (!pll->pll_reset<<13) | 7209a0bf528SMauro Carvalho Chehab (pll->pll_range<<12) | (pll->pll_ratio<<6) | 7219a0bf528SMauro Carvalho Chehab (pll->pll_prediv)); 7229a0bf528SMauro Carvalho Chehab 7239a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1857); 7249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15)); 7259a0bf528SMauro Carvalho Chehab 7269a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */ 7279a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1858, reg | 1); 7289a0bf528SMauro Carvalho Chehab 7299a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (pll->modulo << 8)); 7309a0bf528SMauro Carvalho Chehab } 7319a0bf528SMauro Carvalho Chehab 7329a0bf528SMauro Carvalho Chehab dib8000_reset_pll_common(state, pll); 7339a0bf528SMauro Carvalho Chehab } 7349a0bf528SMauro Carvalho Chehab 7359a0bf528SMauro Carvalho Chehab int dib8000_update_pll(struct dvb_frontend *fe, 736173a64cbSPatrick Boettcher struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio) 7379a0bf528SMauro Carvalho Chehab { 7389a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 7399a0bf528SMauro Carvalho Chehab u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856); 740173a64cbSPatrick Boettcher u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ; 7419a0bf528SMauro Carvalho Chehab u32 internal, xtal; 7429a0bf528SMauro Carvalho Chehab 7439a0bf528SMauro Carvalho Chehab /* get back old values */ 7449a0bf528SMauro Carvalho Chehab prediv = reg_1856 & 0x3f; 7459a0bf528SMauro Carvalho Chehab loopdiv = (reg_1856 >> 6) & 0x3f; 7469a0bf528SMauro Carvalho Chehab 747173a64cbSPatrick Boettcher if ((pll == NULL) || (pll->pll_prediv == prediv && 748173a64cbSPatrick Boettcher pll->pll_ratio == loopdiv)) 749173a64cbSPatrick Boettcher return -EINVAL; 750173a64cbSPatrick Boettcher 7519a0bf528SMauro Carvalho Chehab dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); 752173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 7539a0bf528SMauro Carvalho Chehab reg_1856 &= 0xf000; 7549a0bf528SMauro Carvalho Chehab reg_1857 = dib8000_read_word(state, 1857); 7559a0bf528SMauro Carvalho Chehab /* disable PLL */ 7569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15)); 7579a0bf528SMauro Carvalho Chehab 7589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, reg_1856 | 7599a0bf528SMauro Carvalho Chehab ((pll->pll_ratio & 0x3f) << 6) | 7609a0bf528SMauro Carvalho Chehab (pll->pll_prediv & 0x3f)); 7619a0bf528SMauro Carvalho Chehab 7629a0bf528SMauro Carvalho Chehab /* write new system clk into P_sec_len */ 7639a0bf528SMauro Carvalho Chehab internal = dib8000_read32(state, 23) / 1000; 7649a0bf528SMauro Carvalho Chehab dprintk("Old Internal = %d", internal); 7659a0bf528SMauro Carvalho Chehab xtal = 2 * (internal / loopdiv) * prediv; 7669a0bf528SMauro Carvalho Chehab internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio; 7679a0bf528SMauro Carvalho Chehab dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000); 7689a0bf528SMauro Carvalho Chehab dprintk("New Internal = %d", internal); 7699a0bf528SMauro Carvalho Chehab 7709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, 7719a0bf528SMauro Carvalho Chehab (u16) (((internal / 2) >> 16) & 0xffff)); 7729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff)); 7739a0bf528SMauro Carvalho Chehab /* enable PLL */ 7749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 | (1 << 15)); 7759a0bf528SMauro Carvalho Chehab 7769a0bf528SMauro Carvalho Chehab while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1) 7779a0bf528SMauro Carvalho Chehab dprintk("Waiting for PLL to lock"); 7789a0bf528SMauro Carvalho Chehab 7799a0bf528SMauro Carvalho Chehab /* verify */ 7809a0bf528SMauro Carvalho Chehab reg_1856 = dib8000_read_word(state, 1856); 7819a0bf528SMauro Carvalho Chehab dprintk("PLL Updated with prediv = %d and loopdiv = %d", 7829a0bf528SMauro Carvalho Chehab reg_1856&0x3f, (reg_1856>>6)&0x3f); 783173a64cbSPatrick Boettcher } else { 784173a64cbSPatrick Boettcher if (bw != state->current_demod_bw) { 785173a64cbSPatrick Boettcher /** Bandwidth change => force PLL update **/ 786173a64cbSPatrick 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); 787173a64cbSPatrick Boettcher 788173a64cbSPatrick Boettcher if (state->cfg.pll->pll_prediv != oldprediv) { 789173a64cbSPatrick Boettcher /** Full PLL change only if prediv is changed **/ 790173a64cbSPatrick Boettcher 791173a64cbSPatrick Boettcher /** full update => bypass and reconfigure **/ 792173a64cbSPatrick 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); 793173a64cbSPatrick Boettcher dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */ 794173a64cbSPatrick Boettcher dib8000_reset_pll(state); 795173a64cbSPatrick Boettcher dib8000_write_word(state, 898, 0x0004); /* sad */ 796173a64cbSPatrick Boettcher } else 797173a64cbSPatrick Boettcher ratio = state->cfg.pll->pll_ratio; 798173a64cbSPatrick Boettcher 799173a64cbSPatrick Boettcher state->current_demod_bw = bw; 800173a64cbSPatrick Boettcher } 801173a64cbSPatrick Boettcher 802173a64cbSPatrick Boettcher if (ratio != 0) { 803173a64cbSPatrick Boettcher /** ratio update => only change ratio **/ 804173a64cbSPatrick Boettcher dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio); 805173a64cbSPatrick Boettcher dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ 806173a64cbSPatrick Boettcher } 807173a64cbSPatrick Boettcher } 8089a0bf528SMauro Carvalho Chehab 8099a0bf528SMauro Carvalho Chehab return 0; 8109a0bf528SMauro Carvalho Chehab } 8119a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_update_pll); 8129a0bf528SMauro Carvalho Chehab 8139a0bf528SMauro Carvalho Chehab 8149a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st) 8159a0bf528SMauro Carvalho Chehab { 8169a0bf528SMauro Carvalho Chehab /* reset the GPIOs */ 8179a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir); 8189a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val); 8199a0bf528SMauro Carvalho Chehab 8209a0bf528SMauro Carvalho Chehab /* TODO 782 is P_gpio_od */ 8219a0bf528SMauro Carvalho Chehab 8229a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos); 8239a0bf528SMauro Carvalho Chehab 8249a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1037, st->cfg.pwm_freq_div); 8259a0bf528SMauro Carvalho Chehab return 0; 8269a0bf528SMauro Carvalho Chehab } 8279a0bf528SMauro Carvalho Chehab 8289a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val) 8299a0bf528SMauro Carvalho Chehab { 8309a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir = dib8000_read_word(st, 1029); 8319a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */ 8329a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */ 8339a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir); 8349a0bf528SMauro Carvalho Chehab 8359a0bf528SMauro Carvalho Chehab st->cfg.gpio_val = dib8000_read_word(st, 1030); 8369a0bf528SMauro Carvalho Chehab st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */ 8379a0bf528SMauro Carvalho Chehab st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */ 8389a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val); 8399a0bf528SMauro Carvalho Chehab 8409a0bf528SMauro Carvalho Chehab dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val); 8419a0bf528SMauro Carvalho Chehab 8429a0bf528SMauro Carvalho Chehab return 0; 8439a0bf528SMauro Carvalho Chehab } 8449a0bf528SMauro Carvalho Chehab 8459a0bf528SMauro Carvalho Chehab int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) 8469a0bf528SMauro Carvalho Chehab { 8479a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 8489a0bf528SMauro Carvalho Chehab return dib8000_cfg_gpio(state, num, dir, val); 8499a0bf528SMauro Carvalho Chehab } 8509a0bf528SMauro Carvalho Chehab 8519a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_gpio); 8529a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = { 8539a0bf528SMauro Carvalho Chehab /* auto search configuration - lock0 by default waiting 8549a0bf528SMauro Carvalho Chehab * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */ 8559a0bf528SMauro Carvalho Chehab 3, 7, 8569a0bf528SMauro Carvalho Chehab 0x0004, 8579a0bf528SMauro Carvalho Chehab 0x0400, 8589a0bf528SMauro Carvalho Chehab 0x0814, 8599a0bf528SMauro Carvalho Chehab 8609a0bf528SMauro Carvalho Chehab 12, 11, 8619a0bf528SMauro Carvalho Chehab 0x001b, 8629a0bf528SMauro Carvalho Chehab 0x7740, 8639a0bf528SMauro Carvalho Chehab 0x005b, 8649a0bf528SMauro Carvalho Chehab 0x8d80, 8659a0bf528SMauro Carvalho Chehab 0x01c9, 8669a0bf528SMauro Carvalho Chehab 0xc380, 8679a0bf528SMauro Carvalho Chehab 0x0000, 8689a0bf528SMauro Carvalho Chehab 0x0080, 8699a0bf528SMauro Carvalho Chehab 0x0000, 8709a0bf528SMauro Carvalho Chehab 0x0090, 8719a0bf528SMauro Carvalho Chehab 0x0001, 8729a0bf528SMauro Carvalho Chehab 0xd4c0, 8739a0bf528SMauro Carvalho Chehab 8749a0bf528SMauro Carvalho Chehab /*1, 32, 8759a0bf528SMauro Carvalho Chehab 0x6680 // P_corm_thres Lock algorithms configuration */ 8769a0bf528SMauro Carvalho Chehab 8779a0bf528SMauro Carvalho Chehab 11, 80, /* set ADC level to -16 */ 8789a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117, 8799a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117, 8809a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117, 8819a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117, 8829a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117, 8839a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117, 8849a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117, 8859a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117, 8869a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117, 8879a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117, 8889a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117, 8899a0bf528SMauro Carvalho Chehab 8909a0bf528SMauro Carvalho Chehab 4, 108, 8919a0bf528SMauro Carvalho Chehab 0, 8929a0bf528SMauro Carvalho Chehab 0, 8939a0bf528SMauro Carvalho Chehab 0, 8949a0bf528SMauro Carvalho Chehab 0, 8959a0bf528SMauro Carvalho Chehab 8969a0bf528SMauro Carvalho Chehab 1, 175, 8979a0bf528SMauro Carvalho Chehab 0x0410, 8989a0bf528SMauro Carvalho Chehab 1, 179, 8999a0bf528SMauro Carvalho Chehab 8192, // P_fft_nb_to_cut 9009a0bf528SMauro Carvalho Chehab 9019a0bf528SMauro Carvalho Chehab 6, 181, 9029a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800 9039a0bf528SMauro Carvalho Chehab 0x2800, 9049a0bf528SMauro Carvalho Chehab 0x2800, 9059a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800 9069a0bf528SMauro Carvalho Chehab 0x2800, 9079a0bf528SMauro Carvalho Chehab 0x2800, 9089a0bf528SMauro Carvalho Chehab 9099a0bf528SMauro Carvalho Chehab 2, 193, 9109a0bf528SMauro Carvalho Chehab 0x0666, // P_pha3_thres 9119a0bf528SMauro Carvalho Chehab 0x0000, // P_cti_use_cpe, P_cti_use_prog 9129a0bf528SMauro Carvalho Chehab 9139a0bf528SMauro Carvalho Chehab 2, 205, 9149a0bf528SMauro Carvalho Chehab 0x200f, // P_cspu_regul, P_cspu_win_cut 9159a0bf528SMauro Carvalho Chehab 0x000f, // P_des_shift_work 9169a0bf528SMauro Carvalho Chehab 9179a0bf528SMauro Carvalho Chehab 5, 215, 9189a0bf528SMauro Carvalho Chehab 0x023d, // P_adp_regul_cnt 9199a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_noise_cnt 9209a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_regul_ext 9219a0bf528SMauro Carvalho Chehab 0x7ff0, // P_adp_noise_ext 9229a0bf528SMauro Carvalho Chehab 0x3ccc, // P_adp_fil 9239a0bf528SMauro Carvalho Chehab 9249a0bf528SMauro Carvalho Chehab 1, 230, 9259a0bf528SMauro Carvalho Chehab 0x0000, // P_2d_byp_ti_num 9269a0bf528SMauro Carvalho Chehab 9279a0bf528SMauro Carvalho Chehab 1, 263, 9289a0bf528SMauro Carvalho Chehab 0x800, //P_equal_thres_wgn 9299a0bf528SMauro Carvalho Chehab 9309a0bf528SMauro Carvalho Chehab 1, 268, 9319a0bf528SMauro Carvalho Chehab (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode 9329a0bf528SMauro Carvalho Chehab 9339a0bf528SMauro Carvalho Chehab 1, 270, 9349a0bf528SMauro Carvalho Chehab 0x0001, // P_div_lock0_wait 9359a0bf528SMauro Carvalho Chehab 1, 285, 9369a0bf528SMauro Carvalho Chehab 0x0020, //p_fec_ 9379a0bf528SMauro Carvalho Chehab 1, 299, 9389a0bf528SMauro Carvalho Chehab 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */ 9399a0bf528SMauro Carvalho Chehab 9409a0bf528SMauro Carvalho Chehab 1, 338, 9419a0bf528SMauro Carvalho Chehab (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 9429a0bf528SMauro Carvalho Chehab (1 << 10) | 9439a0bf528SMauro Carvalho Chehab (0 << 9) | /* P_ctrl_pre_freq_inh=0 */ 9449a0bf528SMauro Carvalho Chehab (3 << 5) | /* P_ctrl_pre_freq_step=3 */ 9459a0bf528SMauro Carvalho Chehab (1 << 0), /* P_pre_freq_win_len=1 */ 9469a0bf528SMauro Carvalho Chehab 9479a0bf528SMauro Carvalho Chehab 0, 9489a0bf528SMauro Carvalho Chehab }; 9499a0bf528SMauro Carvalho Chehab 9509a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client) 9519a0bf528SMauro Carvalho Chehab { 9529a0bf528SMauro Carvalho Chehab u16 value; 9539a0bf528SMauro Carvalho Chehab 9549a0bf528SMauro Carvalho Chehab //because of glitches sometimes 9559a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 896); 9569a0bf528SMauro Carvalho Chehab 9579a0bf528SMauro Carvalho Chehab if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) { 9589a0bf528SMauro Carvalho Chehab dprintk("wrong Vendor ID (read=0x%x)", value); 9599a0bf528SMauro Carvalho Chehab return 0; 9609a0bf528SMauro Carvalho Chehab } 9619a0bf528SMauro Carvalho Chehab 9629a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 897); 9639a0bf528SMauro Carvalho Chehab if (value != 0x8000 && value != 0x8001 && 9649a0bf528SMauro Carvalho Chehab value != 0x8002 && value != 0x8090) { 9659a0bf528SMauro Carvalho Chehab dprintk("wrong Device ID (%x)", value); 9669a0bf528SMauro Carvalho Chehab return 0; 9679a0bf528SMauro Carvalho Chehab } 9689a0bf528SMauro Carvalho Chehab 9699a0bf528SMauro Carvalho Chehab switch (value) { 9709a0bf528SMauro Carvalho Chehab case 0x8000: 9719a0bf528SMauro Carvalho Chehab dprintk("found DiB8000A"); 9729a0bf528SMauro Carvalho Chehab break; 9739a0bf528SMauro Carvalho Chehab case 0x8001: 9749a0bf528SMauro Carvalho Chehab dprintk("found DiB8000B"); 9759a0bf528SMauro Carvalho Chehab break; 9769a0bf528SMauro Carvalho Chehab case 0x8002: 9779a0bf528SMauro Carvalho Chehab dprintk("found DiB8000C"); 9789a0bf528SMauro Carvalho Chehab break; 9799a0bf528SMauro Carvalho Chehab case 0x8090: 9809a0bf528SMauro Carvalho Chehab dprintk("found DiB8096P"); 9819a0bf528SMauro Carvalho Chehab break; 9829a0bf528SMauro Carvalho Chehab } 9839a0bf528SMauro Carvalho Chehab return value; 9849a0bf528SMauro Carvalho Chehab } 9859a0bf528SMauro Carvalho Chehab 9869a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe) 9879a0bf528SMauro Carvalho Chehab { 9889a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 9899a0bf528SMauro Carvalho Chehab 9909a0bf528SMauro Carvalho Chehab if ((state->revision = dib8000_identify(&state->i2c)) == 0) 9919a0bf528SMauro Carvalho Chehab return -EINVAL; 9929a0bf528SMauro Carvalho Chehab 9939a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */ 9949a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 9959a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, 0x0003); 9969a0bf528SMauro Carvalho Chehab 9979a0bf528SMauro Carvalho Chehab if (state->revision == 0x8000) 9989a0bf528SMauro Carvalho Chehab dprintk("error : dib8000 MA not supported"); 9999a0bf528SMauro Carvalho Chehab 10009a0bf528SMauro Carvalho Chehab dibx000_reset_i2c_master(&state->i2c_master); 10019a0bf528SMauro Carvalho Chehab 10029a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 10039a0bf528SMauro Carvalho Chehab 10049a0bf528SMauro Carvalho Chehab /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ 1005173a64cbSPatrick Boettcher dib8000_set_adc_state(state, DIBX000_ADC_OFF); 10069a0bf528SMauro Carvalho Chehab 10079a0bf528SMauro Carvalho Chehab /* restart all parts */ 10089a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0xffff); 10099a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0xffff); 10109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0xfffc); 10119a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 10129a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0045); 10139a0bf528SMauro Carvalho Chehab else 10149a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x004d); 10159a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x000c); 10169a0bf528SMauro Carvalho Chehab 10179a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000); 10189a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0x0000); 10199a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0x0000); 10209a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004); // sad 10219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0000); 10229a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x0000); 10239a0bf528SMauro Carvalho Chehab 10249a0bf528SMauro Carvalho Chehab /* drives */ 10259a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) { 10269a0bf528SMauro Carvalho Chehab if (state->cfg.drives) 10279a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, state->cfg.drives); 10289a0bf528SMauro Carvalho Chehab else { 10299a0bf528SMauro Carvalho Chehab dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); 10309a0bf528SMauro Carvalho Chehab /* min drive SDRAM - not optimal - adjust */ 10319a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, 0x2d98); 10329a0bf528SMauro Carvalho Chehab } 10339a0bf528SMauro Carvalho Chehab } 10349a0bf528SMauro Carvalho Chehab 10359a0bf528SMauro Carvalho Chehab dib8000_reset_pll(state); 10369a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 10379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004); 10389a0bf528SMauro Carvalho Chehab 10399a0bf528SMauro Carvalho Chehab if (dib8000_reset_gpio(state) != 0) 10409a0bf528SMauro Carvalho Chehab dprintk("GPIO reset was not successful."); 10419a0bf528SMauro Carvalho Chehab 10429a0bf528SMauro Carvalho Chehab if ((state->revision != 0x8090) && 10439a0bf528SMauro Carvalho Chehab (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)) 10449a0bf528SMauro Carvalho Chehab dprintk("OUTPUT_MODE could not be resetted."); 10459a0bf528SMauro Carvalho Chehab 10469a0bf528SMauro Carvalho Chehab state->current_agc = NULL; 10479a0bf528SMauro Carvalho Chehab 10489a0bf528SMauro Carvalho Chehab // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... 10499a0bf528SMauro Carvalho Chehab /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */ 10509a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ifreq == 0) 10519a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */ 10529a0bf528SMauro Carvalho Chehab else 10539a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */ 10549a0bf528SMauro Carvalho Chehab 10559a0bf528SMauro Carvalho Chehab { 10569a0bf528SMauro Carvalho Chehab u16 l = 0, r; 10579a0bf528SMauro Carvalho Chehab const u16 *n; 10589a0bf528SMauro Carvalho Chehab n = dib8000_defaults; 10599a0bf528SMauro Carvalho Chehab l = *n++; 10609a0bf528SMauro Carvalho Chehab while (l) { 10619a0bf528SMauro Carvalho Chehab r = *n++; 10629a0bf528SMauro Carvalho Chehab do { 10639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, r, *n++); 10649a0bf528SMauro Carvalho Chehab r++; 10659a0bf528SMauro Carvalho Chehab } while (--l); 10669a0bf528SMauro Carvalho Chehab l = *n++; 10679a0bf528SMauro Carvalho Chehab } 10689a0bf528SMauro Carvalho Chehab } 1069173a64cbSPatrick Boettcher 10709a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0; 10719a0bf528SMauro Carvalho Chehab 10729a0bf528SMauro Carvalho Chehab //div_cfg override for special configs 1073173a64cbSPatrick Boettcher if ((state->revision != 8090) && (state->cfg.div_cfg != 0)) 10749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 903, state->cfg.div_cfg); 10759a0bf528SMauro Carvalho Chehab 10769a0bf528SMauro Carvalho Chehab /* unforce divstr regardless whether i2c enumeration was done or not */ 10779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1)); 10789a0bf528SMauro Carvalho Chehab 10799a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(fe, 6000); 10809a0bf528SMauro Carvalho Chehab 10819a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); 10829a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state); 1083173a64cbSPatrick Boettcher if (state->revision != 0x8090) 10849a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); 1085173a64cbSPatrick Boettcher 1086173a64cbSPatrick Boettcher /* ber_rs_len = 3 */ 1087173a64cbSPatrick Boettcher dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); 10889a0bf528SMauro Carvalho Chehab 10899a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); 10909a0bf528SMauro Carvalho Chehab 10919a0bf528SMauro Carvalho Chehab return 0; 10929a0bf528SMauro Carvalho Chehab } 10939a0bf528SMauro Carvalho Chehab 10949a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state) 10959a0bf528SMauro Carvalho Chehab { 10969a0bf528SMauro Carvalho Chehab // P_restart_iqc & P_restart_agc 10979a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0a00); 10989a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000); 10999a0bf528SMauro Carvalho Chehab } 11009a0bf528SMauro Carvalho Chehab 11019a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state) 11029a0bf528SMauro Carvalho Chehab { 11039a0bf528SMauro Carvalho Chehab u16 dyn_gain; 11049a0bf528SMauro Carvalho Chehab 11059a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna) { 11069a0bf528SMauro Carvalho Chehab // read dyn_gain here (because it is demod-dependent and not tuner) 11079a0bf528SMauro Carvalho Chehab dyn_gain = dib8000_read_word(state, 390); 11089a0bf528SMauro Carvalho Chehab 11099a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna(state->fe[0], dyn_gain)) { 11109a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state); 11119a0bf528SMauro Carvalho Chehab return 1; 11129a0bf528SMauro Carvalho Chehab } 11139a0bf528SMauro Carvalho Chehab } 11149a0bf528SMauro Carvalho Chehab return 0; 11159a0bf528SMauro Carvalho Chehab } 11169a0bf528SMauro Carvalho Chehab 11179a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) 11189a0bf528SMauro Carvalho Chehab { 11199a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *agc = NULL; 11209a0bf528SMauro Carvalho Chehab int i; 11219a0bf528SMauro Carvalho Chehab u16 reg; 11229a0bf528SMauro Carvalho Chehab 11239a0bf528SMauro Carvalho Chehab if (state->current_band == band && state->current_agc != NULL) 11249a0bf528SMauro Carvalho Chehab return 0; 11259a0bf528SMauro Carvalho Chehab state->current_band = band; 11269a0bf528SMauro Carvalho Chehab 11279a0bf528SMauro Carvalho Chehab for (i = 0; i < state->cfg.agc_config_count; i++) 11289a0bf528SMauro Carvalho Chehab if (state->cfg.agc[i].band_caps & band) { 11299a0bf528SMauro Carvalho Chehab agc = &state->cfg.agc[i]; 11309a0bf528SMauro Carvalho Chehab break; 11319a0bf528SMauro Carvalho Chehab } 11329a0bf528SMauro Carvalho Chehab 11339a0bf528SMauro Carvalho Chehab if (agc == NULL) { 11349a0bf528SMauro Carvalho Chehab dprintk("no valid AGC configuration found for band 0x%02x", band); 11359a0bf528SMauro Carvalho Chehab return -EINVAL; 11369a0bf528SMauro Carvalho Chehab } 11379a0bf528SMauro Carvalho Chehab 11389a0bf528SMauro Carvalho Chehab state->current_agc = agc; 11399a0bf528SMauro Carvalho Chehab 11409a0bf528SMauro Carvalho Chehab /* AGC */ 11419a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 76, agc->setup); 11429a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 77, agc->inv_gain); 11439a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 78, agc->time_stabiliz); 11449a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock); 11459a0bf528SMauro Carvalho Chehab 11469a0bf528SMauro Carvalho Chehab // Demod AGC loop configuration 11479a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp); 11489a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp); 11499a0bf528SMauro Carvalho Chehab 11509a0bf528SMauro Carvalho Chehab dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", 11519a0bf528SMauro Carvalho Chehab state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); 11529a0bf528SMauro Carvalho Chehab 11539a0bf528SMauro Carvalho Chehab /* AGC continued */ 11549a0bf528SMauro Carvalho Chehab if (state->wbd_ref != 0) 11559a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, state->wbd_ref); 11569a0bf528SMauro Carvalho Chehab else // use default 11579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, agc->wbd_ref); 11589a0bf528SMauro Carvalho Chehab 11599a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) { 11609a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 922) & (0x3 << 2); 11619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2)); 11629a0bf528SMauro Carvalho Chehab } 11639a0bf528SMauro Carvalho Chehab 11649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); 11659a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 108, agc->agc1_max); 11669a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 109, agc->agc1_min); 11679a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 110, agc->agc2_max); 11689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 111, agc->agc2_min); 11699a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2); 11709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); 11719a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); 11729a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); 11739a0bf528SMauro Carvalho Chehab 11749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 75, agc->agc1_pt3); 11759a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 11769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, 11779a0bf528SMauro Carvalho Chehab (dib8000_read_word(state, 923) & 0xffe3) | 11789a0bf528SMauro Carvalho Chehab (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); 11799a0bf528SMauro Carvalho Chehab 11809a0bf528SMauro Carvalho Chehab return 0; 11819a0bf528SMauro Carvalho Chehab } 11829a0bf528SMauro Carvalho Chehab 11839a0bf528SMauro Carvalho Chehab void dib8000_pwm_agc_reset(struct dvb_frontend *fe) 11849a0bf528SMauro Carvalho Chehab { 11859a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 11869a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 11879a0bf528SMauro Carvalho Chehab dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); 11889a0bf528SMauro Carvalho Chehab } 11899a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pwm_agc_reset); 11909a0bf528SMauro Carvalho Chehab 11919a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state) 11929a0bf528SMauro Carvalho Chehab { 11939a0bf528SMauro Carvalho Chehab u16 agc, split_offset; 11949a0bf528SMauro Carvalho Chehab 11959a0bf528SMauro Carvalho Chehab if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) 11969a0bf528SMauro Carvalho Chehab return FE_CALLBACK_TIME_NEVER; 11979a0bf528SMauro Carvalho Chehab 11989a0bf528SMauro Carvalho Chehab // n_agc_global 11999a0bf528SMauro Carvalho Chehab agc = dib8000_read_word(state, 390); 12009a0bf528SMauro Carvalho Chehab 12019a0bf528SMauro Carvalho Chehab if (agc > state->current_agc->split.min_thres) 12029a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.min; 12039a0bf528SMauro Carvalho Chehab else if (agc < state->current_agc->split.max_thres) 12049a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max; 12059a0bf528SMauro Carvalho Chehab else 12069a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max * 12079a0bf528SMauro Carvalho Chehab (agc - state->current_agc->split.min_thres) / 12089a0bf528SMauro Carvalho Chehab (state->current_agc->split.max_thres - state->current_agc->split.min_thres); 12099a0bf528SMauro Carvalho Chehab 12109a0bf528SMauro Carvalho Chehab dprintk("AGC split_offset: %d", split_offset); 12119a0bf528SMauro Carvalho Chehab 12129a0bf528SMauro Carvalho Chehab // P_agc_force_split and P_agc_split_offset 12139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset); 12149a0bf528SMauro Carvalho Chehab return 5000; 12159a0bf528SMauro Carvalho Chehab } 12169a0bf528SMauro Carvalho Chehab 12179a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe) 12189a0bf528SMauro Carvalho Chehab { 12199a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 12209a0bf528SMauro Carvalho Chehab enum frontend_tune_state *tune_state = &state->tune_state; 12219a0bf528SMauro Carvalho Chehab int ret = 0; 12229a0bf528SMauro Carvalho Chehab u16 reg, upd_demod_gain_period = 0x8000; 12239a0bf528SMauro Carvalho Chehab 12249a0bf528SMauro Carvalho Chehab switch (*tune_state) { 12259a0bf528SMauro Carvalho Chehab case CT_AGC_START: 12269a0bf528SMauro Carvalho Chehab // set power-up level: interf+analog+AGC 12279a0bf528SMauro Carvalho Chehab 12289a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 12299a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 12309a0bf528SMauro Carvalho Chehab else { 12319a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 12329a0bf528SMauro Carvalho Chehab 12339a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1947)&0xff00; 12349a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1946, 12359a0bf528SMauro Carvalho Chehab upd_demod_gain_period & 0xFFFF); 12369a0bf528SMauro Carvalho Chehab /* bit 14 = enDemodGain */ 12379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1947, reg | (1<<14) | 12389a0bf528SMauro Carvalho Chehab ((upd_demod_gain_period >> 16) & 0xFF)); 12399a0bf528SMauro Carvalho Chehab 12409a0bf528SMauro Carvalho Chehab /* enable adc i & q */ 12419a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1920); 12429a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1920, (reg | 0x3) & 12439a0bf528SMauro Carvalho Chehab (~(1 << 7))); 12449a0bf528SMauro Carvalho Chehab } 12459a0bf528SMauro Carvalho Chehab 12469a0bf528SMauro Carvalho Chehab if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { 12479a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP; 12489a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_TUNE_FAILED; 12499a0bf528SMauro Carvalho Chehab break; 12509a0bf528SMauro Carvalho Chehab } 12519a0bf528SMauro Carvalho Chehab 12529a0bf528SMauro Carvalho Chehab ret = 70; 12539a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_0; 12549a0bf528SMauro Carvalho Chehab break; 12559a0bf528SMauro Carvalho Chehab 12569a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_0: 12579a0bf528SMauro Carvalho Chehab //AGC initialization 12589a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 12599a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 1); 12609a0bf528SMauro Carvalho Chehab 12619a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state); 12629a0bf528SMauro Carvalho Chehab 12639a0bf528SMauro Carvalho Chehab // wait AGC rough lock time 12649a0bf528SMauro Carvalho Chehab ret = 50; 12659a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_1; 12669a0bf528SMauro Carvalho Chehab break; 12679a0bf528SMauro Carvalho Chehab 12689a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_1: 12699a0bf528SMauro Carvalho Chehab // wait AGC accurate lock time 12709a0bf528SMauro Carvalho Chehab ret = 70; 12719a0bf528SMauro Carvalho Chehab 12729a0bf528SMauro Carvalho Chehab if (dib8000_update_lna(state)) 12739a0bf528SMauro Carvalho Chehab // wait only AGC rough lock time 12749a0bf528SMauro Carvalho Chehab ret = 50; 12759a0bf528SMauro Carvalho Chehab else 12769a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_2; 12779a0bf528SMauro Carvalho Chehab break; 12789a0bf528SMauro Carvalho Chehab 12799a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_2: 12809a0bf528SMauro Carvalho Chehab dib8000_agc_soft_split(state); 12819a0bf528SMauro Carvalho Chehab 12829a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 12839a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 0); 12849a0bf528SMauro Carvalho Chehab 12859a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP; 12869a0bf528SMauro Carvalho Chehab break; 12879a0bf528SMauro Carvalho Chehab default: 12889a0bf528SMauro Carvalho Chehab ret = dib8000_agc_soft_split(state); 12899a0bf528SMauro Carvalho Chehab break; 12909a0bf528SMauro Carvalho Chehab } 12919a0bf528SMauro Carvalho Chehab return ret; 12929a0bf528SMauro Carvalho Chehab 12939a0bf528SMauro Carvalho Chehab } 12949a0bf528SMauro Carvalho Chehab 12959a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive) 12969a0bf528SMauro Carvalho Chehab { 12979a0bf528SMauro Carvalho Chehab u16 reg; 12989a0bf528SMauro Carvalho Chehab 12999a0bf528SMauro Carvalho Chehab drive &= 0x7; 13009a0bf528SMauro Carvalho Chehab 13019a0bf528SMauro Carvalho Chehab /* drive host bus 2, 3, 4 */ 13029a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1798) & 13039a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13049a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1798, reg); 13069a0bf528SMauro Carvalho Chehab 13079a0bf528SMauro Carvalho Chehab /* drive host bus 5,6 */ 13089a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); 13099a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2); 13109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1799, reg); 13119a0bf528SMauro Carvalho Chehab 13129a0bf528SMauro Carvalho Chehab /* drive host bus 7, 8, 9 */ 13139a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1800) & 13149a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13159a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13169a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1800, reg); 13179a0bf528SMauro Carvalho Chehab 13189a0bf528SMauro Carvalho Chehab /* drive host bus 10, 11 */ 13199a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); 13209a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2); 13219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1801, reg); 13229a0bf528SMauro Carvalho Chehab 13239a0bf528SMauro Carvalho Chehab /* drive host bus 12, 13, 14 */ 13249a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1802) & 13259a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12)); 13269a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive; 13279a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1802, reg); 13289a0bf528SMauro Carvalho Chehab } 13299a0bf528SMauro Carvalho Chehab 13309a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout, 13319a0bf528SMauro Carvalho Chehab u32 insertExtSynchro, u32 syncSize) 13329a0bf528SMauro Carvalho Chehab { 13339a0bf528SMauro Carvalho Chehab u32 quantif = 3; 13349a0bf528SMauro Carvalho Chehab u32 nom = (insertExtSynchro * P_Kin+syncSize); 13359a0bf528SMauro Carvalho Chehab u32 denom = P_Kout; 13369a0bf528SMauro Carvalho Chehab u32 syncFreq = ((nom << quantif) / denom); 13379a0bf528SMauro Carvalho Chehab 13389a0bf528SMauro Carvalho Chehab if ((syncFreq & ((1 << quantif) - 1)) != 0) 13399a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif) + 1; 13409a0bf528SMauro Carvalho Chehab else 13419a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif); 13429a0bf528SMauro Carvalho Chehab 13439a0bf528SMauro Carvalho Chehab if (syncFreq != 0) 13449a0bf528SMauro Carvalho Chehab syncFreq = syncFreq - 1; 13459a0bf528SMauro Carvalho Chehab 13469a0bf528SMauro Carvalho Chehab return syncFreq; 13479a0bf528SMauro Carvalho Chehab } 13489a0bf528SMauro Carvalho Chehab 13499a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin, 13509a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, 13519a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize) 13529a0bf528SMauro Carvalho Chehab { 13539a0bf528SMauro Carvalho Chehab dprintk("Configure DibStream Tx"); 13549a0bf528SMauro Carvalho Chehab 13559a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 1); 13569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1603, P_Kin); 13579a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1605, P_Kout); 13589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1606, insertExtSynchro); 13599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1608, synchroMode); 13609a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff); 13619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1610, syncWord & 0xffff); 13629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1612, syncSize); 13639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 0); 13649a0bf528SMauro Carvalho Chehab } 13659a0bf528SMauro Carvalho Chehab 13669a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin, 13679a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, 13689a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize, u32 dataOutRate) 13699a0bf528SMauro Carvalho Chehab { 13709a0bf528SMauro Carvalho Chehab u32 syncFreq; 13719a0bf528SMauro Carvalho Chehab 13729a0bf528SMauro Carvalho Chehab dprintk("Configure DibStream Rx synchroMode = %d", synchroMode); 13739a0bf528SMauro Carvalho Chehab 13749a0bf528SMauro Carvalho Chehab if ((P_Kin != 0) && (P_Kout != 0)) { 13759a0bf528SMauro Carvalho Chehab syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout, 13769a0bf528SMauro Carvalho Chehab insertExtSynchro, syncSize); 13779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1542, syncFreq); 13789a0bf528SMauro Carvalho Chehab } 13799a0bf528SMauro Carvalho Chehab 13809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 1); 13819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1536, P_Kin); 13829a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1537, P_Kout); 13839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1539, synchroMode); 13849a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff); 13859a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1541, syncWord & 0xffff); 13869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1543, syncSize); 13879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1544, dataOutRate); 13889a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 0); 13899a0bf528SMauro Carvalho Chehab } 13909a0bf528SMauro Carvalho Chehab 13919a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff) 13929a0bf528SMauro Carvalho Chehab { 13939a0bf528SMauro Carvalho Chehab u16 reg_1287; 13949a0bf528SMauro Carvalho Chehab 13959a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287); 13969a0bf528SMauro Carvalho Chehab 13979a0bf528SMauro Carvalho Chehab switch (onoff) { 13989a0bf528SMauro Carvalho Chehab case 1: 13999a0bf528SMauro Carvalho Chehab reg_1287 &= ~(1 << 8); 14009a0bf528SMauro Carvalho Chehab break; 14019a0bf528SMauro Carvalho Chehab case 0: 14029a0bf528SMauro Carvalho Chehab reg_1287 |= (1 << 8); 14039a0bf528SMauro Carvalho Chehab break; 14049a0bf528SMauro Carvalho Chehab } 14059a0bf528SMauro Carvalho Chehab 14069a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 14079a0bf528SMauro Carvalho Chehab } 14089a0bf528SMauro Carvalho Chehab 14099a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state, 14109a0bf528SMauro Carvalho Chehab u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) 14119a0bf528SMauro Carvalho Chehab { 14129a0bf528SMauro Carvalho Chehab u16 reg_1287; 14139a0bf528SMauro Carvalho Chehab 14149a0bf528SMauro Carvalho Chehab dprintk("Enable Mpeg mux"); 14159a0bf528SMauro Carvalho Chehab 14169a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 14179a0bf528SMauro Carvalho Chehab 14189a0bf528SMauro Carvalho Chehab /* If the input mode is MPEG do not divide the serial clock */ 14199a0bf528SMauro Carvalho Chehab if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) 14209a0bf528SMauro Carvalho Chehab enSerialClkDiv2 = 0; 14219a0bf528SMauro Carvalho Chehab 14229a0bf528SMauro Carvalho Chehab reg_1287 = ((pulseWidth & 0x1f) << 3) | 14239a0bf528SMauro Carvalho Chehab ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1); 14249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 14259a0bf528SMauro Carvalho Chehab 14269a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 1); 14279a0bf528SMauro Carvalho Chehab } 14289a0bf528SMauro Carvalho Chehab 14299a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode) 14309a0bf528SMauro Carvalho Chehab { 14319a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7); 14329a0bf528SMauro Carvalho Chehab 14339a0bf528SMauro Carvalho Chehab switch (mode) { 14349a0bf528SMauro Carvalho Chehab case MPEG_ON_DIBTX: 14359a0bf528SMauro Carvalho Chehab dprintk("SET MPEG ON DIBSTREAM TX"); 14369a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); 14379a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 9); break; 14389a0bf528SMauro Carvalho Chehab case DIV_ON_DIBTX: 14399a0bf528SMauro Carvalho Chehab dprintk("SET DIV_OUT ON DIBSTREAM TX"); 14409a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); 14419a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 8); break; 14429a0bf528SMauro Carvalho Chehab case ADC_ON_DIBTX: 14439a0bf528SMauro Carvalho Chehab dprintk("SET ADC_OUT ON DIBSTREAM TX"); 14449a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); 14459a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 7); break; 14469a0bf528SMauro Carvalho Chehab default: 14479a0bf528SMauro Carvalho Chehab break; 14489a0bf528SMauro Carvalho Chehab } 14499a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288); 14509a0bf528SMauro Carvalho Chehab } 14519a0bf528SMauro Carvalho Chehab 14529a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode) 14539a0bf528SMauro Carvalho Chehab { 14549a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4); 14559a0bf528SMauro Carvalho Chehab 14569a0bf528SMauro Carvalho Chehab switch (mode) { 14579a0bf528SMauro Carvalho Chehab case DEMOUT_ON_HOSTBUS: 14589a0bf528SMauro Carvalho Chehab dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); 14599a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 14609a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 6); 14619a0bf528SMauro Carvalho Chehab break; 14629a0bf528SMauro Carvalho Chehab case DIBTX_ON_HOSTBUS: 14639a0bf528SMauro Carvalho Chehab dprintk("SET DIBSTREAM TX ON HOST BUS"); 14649a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0); 14659a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 5); 14669a0bf528SMauro Carvalho Chehab break; 14679a0bf528SMauro Carvalho Chehab case MPEG_ON_HOSTBUS: 14689a0bf528SMauro Carvalho Chehab dprintk("SET MPEG MUX ON HOST BUS"); 14699a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 4); 14709a0bf528SMauro Carvalho Chehab break; 14719a0bf528SMauro Carvalho Chehab default: 14729a0bf528SMauro Carvalho Chehab break; 14739a0bf528SMauro Carvalho Chehab } 14749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288); 14759a0bf528SMauro Carvalho Chehab } 14769a0bf528SMauro Carvalho Chehab 14779a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff) 14789a0bf528SMauro Carvalho Chehab { 14799a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 14809a0bf528SMauro Carvalho Chehab u16 reg_1287; 14819a0bf528SMauro Carvalho Chehab 14829a0bf528SMauro Carvalho Chehab switch (onoff) { 14839a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */ 14849a0bf528SMauro Carvalho Chehab dprintk("%s mode OFF : by default Enable Mpeg INPUT", 14859a0bf528SMauro Carvalho Chehab __func__); 14869a0bf528SMauro Carvalho Chehab /* outputRate = 8 */ 14879a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); 14889a0bf528SMauro Carvalho Chehab 14899a0bf528SMauro Carvalho Chehab /* Do not divide the serial clock of MPEG MUX in 14909a0bf528SMauro Carvalho Chehab SERIAL MODE in case input mode MPEG is used */ 14919a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287); 14929a0bf528SMauro Carvalho Chehab /* enSerialClkDiv2 == 1 ? */ 14939a0bf528SMauro Carvalho Chehab if ((reg_1287 & 0x1) == 1) { 14949a0bf528SMauro Carvalho Chehab /* force enSerialClkDiv2 = 0 */ 14959a0bf528SMauro Carvalho Chehab reg_1287 &= ~0x1; 14969a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287); 14979a0bf528SMauro Carvalho Chehab } 14989a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 1; 14999a0bf528SMauro Carvalho Chehab break; 15009a0bf528SMauro Carvalho Chehab case 1: /* both ways */ 15019a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */ 15029a0bf528SMauro Carvalho Chehab dprintk("%s ON : Enable diversity INPUT", __func__); 15039a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); 15049a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 0; 15059a0bf528SMauro Carvalho Chehab break; 15069a0bf528SMauro Carvalho Chehab } 15079a0bf528SMauro Carvalho Chehab 15089a0bf528SMauro Carvalho Chehab dib8000_set_diversity_in(state->fe[0], onoff); 15099a0bf528SMauro Carvalho Chehab return 0; 15109a0bf528SMauro Carvalho Chehab } 15119a0bf528SMauro Carvalho Chehab 15129a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) 15139a0bf528SMauro Carvalho Chehab { 15149a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 15159a0bf528SMauro Carvalho Chehab u16 outreg, smo_mode, fifo_threshold; 15169a0bf528SMauro Carvalho Chehab u8 prefer_mpeg_mux_use = 1; 15179a0bf528SMauro Carvalho Chehab int ret = 0; 15189a0bf528SMauro Carvalho Chehab 1519173a64cbSPatrick Boettcher state->output_mode = mode; 15209a0bf528SMauro Carvalho Chehab dib8096p_host_bus_drive(state, 1); 15219a0bf528SMauro Carvalho Chehab 15229a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 15239a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); 15249a0bf528SMauro Carvalho Chehab outreg = dib8000_read_word(state, 1286) & 15259a0bf528SMauro Carvalho Chehab ~((1 << 10) | (0x7 << 6) | (1 << 1)); 15269a0bf528SMauro Carvalho Chehab 15279a0bf528SMauro Carvalho Chehab switch (mode) { 15289a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: 15299a0bf528SMauro Carvalho Chehab outreg = 0; 15309a0bf528SMauro Carvalho Chehab break; 15319a0bf528SMauro Carvalho Chehab 15329a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 15339a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 15349a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux"); 15359a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 3, 1, 1); 15369a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); 15379a0bf528SMauro Carvalho Chehab } else {/* Use Smooth block */ 15389a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc"); 15399a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, 15409a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS); 15419a0bf528SMauro Carvalho Chehab outreg |= (2 << 6) | (0 << 1); 15429a0bf528SMauro Carvalho Chehab } 15439a0bf528SMauro Carvalho Chehab break; 15449a0bf528SMauro Carvalho Chehab 15459a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 15469a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 15479a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); 15489a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 2, 0, 0); 15499a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); 15509a0bf528SMauro Carvalho Chehab } else { /* Use Smooth block */ 15519a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block"); 15529a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, 15539a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS); 15549a0bf528SMauro Carvalho Chehab outreg |= (0 << 6); 15559a0bf528SMauro Carvalho Chehab } 15569a0bf528SMauro Carvalho Chehab break; 15579a0bf528SMauro Carvalho Chehab 15589a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ 15599a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block"); 15609a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 15619a0bf528SMauro Carvalho Chehab outreg |= (1 << 6); 15629a0bf528SMauro Carvalho Chehab break; 15639a0bf528SMauro Carvalho Chehab 15649a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: 15659a0bf528SMauro Carvalho Chehab /* Using Smooth block because not supported 15669a0bf528SMauro Carvalho Chehab by new Mpeg Mux bloc */ 15679a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_FIFO using Smooth block"); 15689a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 15699a0bf528SMauro Carvalho Chehab outreg |= (5 << 6); 15709a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 15719a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 15729a0bf528SMauro Carvalho Chehab break; 15739a0bf528SMauro Carvalho Chehab 15749a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 15759a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_DIVERSITY"); 15769a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, DIV_ON_DIBTX); 15779a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 15789a0bf528SMauro Carvalho Chehab break; 15799a0bf528SMauro Carvalho Chehab 15809a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 15819a0bf528SMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_ANALOG_ADC"); 15829a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, ADC_ON_DIBTX); 15839a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 15849a0bf528SMauro Carvalho Chehab break; 15859a0bf528SMauro Carvalho Chehab } 15869a0bf528SMauro Carvalho Chehab 15879a0bf528SMauro Carvalho Chehab if (mode != OUTMODE_HIGH_Z) 15889a0bf528SMauro Carvalho Chehab outreg |= (1<<10); 15899a0bf528SMauro Carvalho Chehab 15909a0bf528SMauro Carvalho Chehab dprintk("output_mpeg2_in_188_bytes = %d", 15919a0bf528SMauro Carvalho Chehab state->cfg.output_mpeg2_in_188_bytes); 15929a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 15939a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 15949a0bf528SMauro Carvalho Chehab 15959a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299, smo_mode); 15969a0bf528SMauro Carvalho Chehab /* synchronous fread */ 15979a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299 + 1, fifo_threshold); 15989a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 1286, outreg); 15999a0bf528SMauro Carvalho Chehab 16009a0bf528SMauro Carvalho Chehab return ret; 16019a0bf528SMauro Carvalho Chehab } 16029a0bf528SMauro Carvalho Chehab 16039a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg) 16049a0bf528SMauro Carvalho Chehab { 16059a0bf528SMauro Carvalho Chehab if (msg->buf[0] <= 15) 16069a0bf528SMauro Carvalho Chehab msg->buf[0] -= 1; 16079a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 17) 16089a0bf528SMauro Carvalho Chehab msg->buf[0] = 15; 16099a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 16) 16109a0bf528SMauro Carvalho Chehab msg->buf[0] = 17; 16119a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 19) 16129a0bf528SMauro Carvalho Chehab msg->buf[0] = 16; 16139a0bf528SMauro Carvalho Chehab else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) 16149a0bf528SMauro Carvalho Chehab msg->buf[0] -= 3; 16159a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 28) 16169a0bf528SMauro Carvalho Chehab msg->buf[0] = 23; 16179a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 99) 16189a0bf528SMauro Carvalho Chehab msg->buf[0] = 99; 16199a0bf528SMauro Carvalho Chehab else 16209a0bf528SMauro Carvalho Chehab return -EINVAL; 16219a0bf528SMauro Carvalho Chehab return 0; 16229a0bf528SMauro Carvalho Chehab } 16239a0bf528SMauro Carvalho Chehab 16249a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap, 16259a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 16269a0bf528SMauro Carvalho Chehab { 16279a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 16289a0bf528SMauro Carvalho Chehab u8 n_overflow = 1; 16299a0bf528SMauro Carvalho Chehab u16 i = 1000; 16309a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 16319a0bf528SMauro Carvalho Chehab 16329a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 16339a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; 16349a0bf528SMauro Carvalho Chehab i--; 16359a0bf528SMauro Carvalho Chehab if (i == 0) 16369a0bf528SMauro Carvalho Chehab dprintk("Tuner ITF: write busy (overflow)"); 16379a0bf528SMauro Carvalho Chehab } 16389a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); 16399a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); 16409a0bf528SMauro Carvalho Chehab 16419a0bf528SMauro Carvalho Chehab return num; 16429a0bf528SMauro Carvalho Chehab } 16439a0bf528SMauro Carvalho Chehab 16449a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap, 16459a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 16469a0bf528SMauro Carvalho Chehab { 16479a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 16489a0bf528SMauro Carvalho Chehab u8 n_overflow = 1, n_empty = 1; 16499a0bf528SMauro Carvalho Chehab u16 i = 1000; 16509a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 16519a0bf528SMauro Carvalho Chehab u16 read_word; 16529a0bf528SMauro Carvalho Chehab 16539a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 16549a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; 16559a0bf528SMauro Carvalho Chehab i--; 16569a0bf528SMauro Carvalho Chehab if (i == 0) 16579a0bf528SMauro Carvalho Chehab dprintk("TunerITF: read busy (overflow)"); 16589a0bf528SMauro Carvalho Chehab } 16599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f)); 16609a0bf528SMauro Carvalho Chehab 16619a0bf528SMauro Carvalho Chehab i = 1000; 16629a0bf528SMauro Carvalho Chehab while (n_empty == 1 && i) { 16639a0bf528SMauro Carvalho Chehab n_empty = dib8000_read_word(state, 1984)&0x1; 16649a0bf528SMauro Carvalho Chehab i--; 16659a0bf528SMauro Carvalho Chehab if (i == 0) 16669a0bf528SMauro Carvalho Chehab dprintk("TunerITF: read busy (empty)"); 16679a0bf528SMauro Carvalho Chehab } 16689a0bf528SMauro Carvalho Chehab 16699a0bf528SMauro Carvalho Chehab read_word = dib8000_read_word(state, 1987); 16709a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (read_word >> 8) & 0xff; 16719a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (read_word) & 0xff; 16729a0bf528SMauro Carvalho Chehab 16739a0bf528SMauro Carvalho Chehab return num; 16749a0bf528SMauro Carvalho Chehab } 16759a0bf528SMauro Carvalho Chehab 16769a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, 16779a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 16789a0bf528SMauro Carvalho Chehab { 16799a0bf528SMauro Carvalho Chehab if (map_addr_to_serpar_number(&msg[0]) == 0) { 16809a0bf528SMauro Carvalho Chehab if (num == 1) /* write */ 16819a0bf528SMauro Carvalho Chehab return dib8096p_tuner_write_serpar(i2c_adap, msg, 1); 16829a0bf528SMauro Carvalho Chehab else /* read */ 16839a0bf528SMauro Carvalho Chehab return dib8096p_tuner_read_serpar(i2c_adap, msg, 2); 16849a0bf528SMauro Carvalho Chehab } 16859a0bf528SMauro Carvalho Chehab return num; 16869a0bf528SMauro Carvalho Chehab } 16879a0bf528SMauro Carvalho Chehab 16889a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap, 16899a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num, u16 apb_address) 16909a0bf528SMauro Carvalho Chehab { 16919a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 16929a0bf528SMauro Carvalho Chehab u16 word; 16939a0bf528SMauro Carvalho Chehab 16949a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 16959a0bf528SMauro Carvalho Chehab dib8000_write_word(state, apb_address, 16969a0bf528SMauro Carvalho Chehab ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); 16979a0bf528SMauro Carvalho Chehab } else { 16989a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, apb_address); 16999a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 17009a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 17019a0bf528SMauro Carvalho Chehab } 17029a0bf528SMauro Carvalho Chehab return num; 17039a0bf528SMauro Carvalho Chehab } 17049a0bf528SMauro Carvalho Chehab 17059a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap, 17069a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num) 17079a0bf528SMauro Carvalho Chehab { 17089a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap); 17099a0bf528SMauro Carvalho Chehab u16 apb_address = 0, word; 17109a0bf528SMauro Carvalho Chehab int i = 0; 17119a0bf528SMauro Carvalho Chehab 17129a0bf528SMauro Carvalho Chehab switch (msg[0].buf[0]) { 17139a0bf528SMauro Carvalho Chehab case 0x12: 17149a0bf528SMauro Carvalho Chehab apb_address = 1920; 17159a0bf528SMauro Carvalho Chehab break; 17169a0bf528SMauro Carvalho Chehab case 0x14: 17179a0bf528SMauro Carvalho Chehab apb_address = 1921; 17189a0bf528SMauro Carvalho Chehab break; 17199a0bf528SMauro Carvalho Chehab case 0x24: 17209a0bf528SMauro Carvalho Chehab apb_address = 1922; 17219a0bf528SMauro Carvalho Chehab break; 17229a0bf528SMauro Carvalho Chehab case 0x1a: 17239a0bf528SMauro Carvalho Chehab apb_address = 1923; 17249a0bf528SMauro Carvalho Chehab break; 17259a0bf528SMauro Carvalho Chehab case 0x22: 17269a0bf528SMauro Carvalho Chehab apb_address = 1924; 17279a0bf528SMauro Carvalho Chehab break; 17289a0bf528SMauro Carvalho Chehab case 0x33: 17299a0bf528SMauro Carvalho Chehab apb_address = 1926; 17309a0bf528SMauro Carvalho Chehab break; 17319a0bf528SMauro Carvalho Chehab case 0x34: 17329a0bf528SMauro Carvalho Chehab apb_address = 1927; 17339a0bf528SMauro Carvalho Chehab break; 17349a0bf528SMauro Carvalho Chehab case 0x35: 17359a0bf528SMauro Carvalho Chehab apb_address = 1928; 17369a0bf528SMauro Carvalho Chehab break; 17379a0bf528SMauro Carvalho Chehab case 0x36: 17389a0bf528SMauro Carvalho Chehab apb_address = 1929; 17399a0bf528SMauro Carvalho Chehab break; 17409a0bf528SMauro Carvalho Chehab case 0x37: 17419a0bf528SMauro Carvalho Chehab apb_address = 1930; 17429a0bf528SMauro Carvalho Chehab break; 17439a0bf528SMauro Carvalho Chehab case 0x38: 17449a0bf528SMauro Carvalho Chehab apb_address = 1931; 17459a0bf528SMauro Carvalho Chehab break; 17469a0bf528SMauro Carvalho Chehab case 0x39: 17479a0bf528SMauro Carvalho Chehab apb_address = 1932; 17489a0bf528SMauro Carvalho Chehab break; 17499a0bf528SMauro Carvalho Chehab case 0x2a: 17509a0bf528SMauro Carvalho Chehab apb_address = 1935; 17519a0bf528SMauro Carvalho Chehab break; 17529a0bf528SMauro Carvalho Chehab case 0x2b: 17539a0bf528SMauro Carvalho Chehab apb_address = 1936; 17549a0bf528SMauro Carvalho Chehab break; 17559a0bf528SMauro Carvalho Chehab case 0x2c: 17569a0bf528SMauro Carvalho Chehab apb_address = 1937; 17579a0bf528SMauro Carvalho Chehab break; 17589a0bf528SMauro Carvalho Chehab case 0x2d: 17599a0bf528SMauro Carvalho Chehab apb_address = 1938; 17609a0bf528SMauro Carvalho Chehab break; 17619a0bf528SMauro Carvalho Chehab case 0x2e: 17629a0bf528SMauro Carvalho Chehab apb_address = 1939; 17639a0bf528SMauro Carvalho Chehab break; 17649a0bf528SMauro Carvalho Chehab case 0x2f: 17659a0bf528SMauro Carvalho Chehab apb_address = 1940; 17669a0bf528SMauro Carvalho Chehab break; 17679a0bf528SMauro Carvalho Chehab case 0x30: 17689a0bf528SMauro Carvalho Chehab apb_address = 1941; 17699a0bf528SMauro Carvalho Chehab break; 17709a0bf528SMauro Carvalho Chehab case 0x31: 17719a0bf528SMauro Carvalho Chehab apb_address = 1942; 17729a0bf528SMauro Carvalho Chehab break; 17739a0bf528SMauro Carvalho Chehab case 0x32: 17749a0bf528SMauro Carvalho Chehab apb_address = 1943; 17759a0bf528SMauro Carvalho Chehab break; 17769a0bf528SMauro Carvalho Chehab case 0x3e: 17779a0bf528SMauro Carvalho Chehab apb_address = 1944; 17789a0bf528SMauro Carvalho Chehab break; 17799a0bf528SMauro Carvalho Chehab case 0x3f: 17809a0bf528SMauro Carvalho Chehab apb_address = 1945; 17819a0bf528SMauro Carvalho Chehab break; 17829a0bf528SMauro Carvalho Chehab case 0x40: 17839a0bf528SMauro Carvalho Chehab apb_address = 1948; 17849a0bf528SMauro Carvalho Chehab break; 17859a0bf528SMauro Carvalho Chehab case 0x25: 17869a0bf528SMauro Carvalho Chehab apb_address = 936; 17879a0bf528SMauro Carvalho Chehab break; 17889a0bf528SMauro Carvalho Chehab case 0x26: 17899a0bf528SMauro Carvalho Chehab apb_address = 937; 17909a0bf528SMauro Carvalho Chehab break; 17919a0bf528SMauro Carvalho Chehab case 0x27: 17929a0bf528SMauro Carvalho Chehab apb_address = 938; 17939a0bf528SMauro Carvalho Chehab break; 17949a0bf528SMauro Carvalho Chehab case 0x28: 17959a0bf528SMauro Carvalho Chehab apb_address = 939; 17969a0bf528SMauro Carvalho Chehab break; 17979a0bf528SMauro Carvalho Chehab case 0x1d: 17989a0bf528SMauro Carvalho Chehab /* get sad sel request */ 17999a0bf528SMauro Carvalho Chehab i = ((dib8000_read_word(state, 921) >> 12)&0x3); 18009a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, 924+i); 18019a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 18029a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 18039a0bf528SMauro Carvalho Chehab return num; 18049a0bf528SMauro Carvalho Chehab case 0x1f: 18059a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 18069a0bf528SMauro Carvalho Chehab word = (u16) ((msg[0].buf[1] << 8) | 18079a0bf528SMauro Carvalho Chehab msg[0].buf[2]); 18089a0bf528SMauro Carvalho Chehab /* in the VGAMODE Sel are located on bit 0/1 */ 18099a0bf528SMauro Carvalho Chehab word &= 0x3; 18109a0bf528SMauro Carvalho Chehab word = (dib8000_read_word(state, 921) & 18119a0bf528SMauro Carvalho Chehab ~(3<<12)) | (word<<12); 18129a0bf528SMauro Carvalho Chehab /* Set the proper input */ 18139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, word); 18149a0bf528SMauro Carvalho Chehab return num; 18159a0bf528SMauro Carvalho Chehab } 18169a0bf528SMauro Carvalho Chehab } 18179a0bf528SMauro Carvalho Chehab 18189a0bf528SMauro Carvalho Chehab if (apb_address != 0) /* R/W acces via APB */ 18199a0bf528SMauro Carvalho Chehab return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address); 18209a0bf528SMauro Carvalho Chehab else /* R/W access via SERPAR */ 18219a0bf528SMauro Carvalho Chehab return dib8096p_tuner_rw_serpar(i2c_adap, msg, num); 18229a0bf528SMauro Carvalho Chehab 18239a0bf528SMauro Carvalho Chehab return 0; 18249a0bf528SMauro Carvalho Chehab } 18259a0bf528SMauro Carvalho Chehab 18269a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter) 18279a0bf528SMauro Carvalho Chehab { 18289a0bf528SMauro Carvalho Chehab return I2C_FUNC_I2C; 18299a0bf528SMauro Carvalho Chehab } 18309a0bf528SMauro Carvalho Chehab 18319a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = { 18329a0bf528SMauro Carvalho Chehab .master_xfer = dib8096p_tuner_xfer, 18339a0bf528SMauro Carvalho Chehab .functionality = dib8096p_i2c_func, 18349a0bf528SMauro Carvalho Chehab }; 18359a0bf528SMauro Carvalho Chehab 18369a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) 18379a0bf528SMauro Carvalho Chehab { 18389a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 18399a0bf528SMauro Carvalho Chehab return &st->dib8096p_tuner_adap; 18409a0bf528SMauro Carvalho Chehab } 18419a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_get_i2c_tuner); 18429a0bf528SMauro Carvalho Chehab 18439a0bf528SMauro Carvalho Chehab int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) 18449a0bf528SMauro Carvalho Chehab { 18459a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 18469a0bf528SMauro Carvalho Chehab u16 en_cur_state; 18479a0bf528SMauro Carvalho Chehab 18489a0bf528SMauro Carvalho Chehab dprintk("sleep dib8096p: %d", onoff); 18499a0bf528SMauro Carvalho Chehab 18509a0bf528SMauro Carvalho Chehab en_cur_state = dib8000_read_word(state, 1922); 18519a0bf528SMauro Carvalho Chehab 18529a0bf528SMauro Carvalho Chehab /* LNAs and MIX are ON and therefore it is a valid configuration */ 18539a0bf528SMauro Carvalho Chehab if (en_cur_state > 0xff) 18549a0bf528SMauro Carvalho Chehab state->tuner_enable = en_cur_state ; 18559a0bf528SMauro Carvalho Chehab 18569a0bf528SMauro Carvalho Chehab if (onoff) 18579a0bf528SMauro Carvalho Chehab en_cur_state &= 0x00ff; 18589a0bf528SMauro Carvalho Chehab else { 18599a0bf528SMauro Carvalho Chehab if (state->tuner_enable != 0) 18609a0bf528SMauro Carvalho Chehab en_cur_state = state->tuner_enable; 18619a0bf528SMauro Carvalho Chehab } 18629a0bf528SMauro Carvalho Chehab 18639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1922, en_cur_state); 18649a0bf528SMauro Carvalho Chehab 18659a0bf528SMauro Carvalho Chehab return 0; 18669a0bf528SMauro Carvalho Chehab } 18679a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_tuner_sleep); 18689a0bf528SMauro Carvalho Chehab 18699a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = 18709a0bf528SMauro Carvalho Chehab { 18719a0bf528SMauro Carvalho Chehab 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 18729a0bf528SMauro Carvalho Chehab }; 18739a0bf528SMauro Carvalho Chehab 18749a0bf528SMauro Carvalho Chehab s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) 18759a0bf528SMauro Carvalho Chehab { 18769a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 18779a0bf528SMauro Carvalho Chehab u32 ix = 0, tmp_val = 0, exp = 0, mant = 0; 18789a0bf528SMauro Carvalho Chehab s32 val; 18799a0bf528SMauro Carvalho Chehab 18809a0bf528SMauro Carvalho Chehab val = dib8000_read32(state, 384); 18819a0bf528SMauro Carvalho Chehab if (mode) { 18829a0bf528SMauro Carvalho Chehab tmp_val = val; 18839a0bf528SMauro Carvalho Chehab while (tmp_val >>= 1) 18849a0bf528SMauro Carvalho Chehab exp++; 18859a0bf528SMauro Carvalho Chehab mant = (val * 1000 / (1<<exp)); 18869a0bf528SMauro Carvalho Chehab ix = (u8)((mant-1000)/100); /* index of the LUT */ 18879a0bf528SMauro Carvalho Chehab val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); 18889a0bf528SMauro Carvalho Chehab val = (val*256)/1000; 18899a0bf528SMauro Carvalho Chehab } 18909a0bf528SMauro Carvalho Chehab return val; 18919a0bf528SMauro Carvalho Chehab } 18929a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_adc_power); 18939a0bf528SMauro Carvalho Chehab 18949a0bf528SMauro Carvalho Chehab int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) 18959a0bf528SMauro Carvalho Chehab { 18969a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 18979a0bf528SMauro Carvalho Chehab int val = 0; 18989a0bf528SMauro Carvalho Chehab 18999a0bf528SMauro Carvalho Chehab switch (IQ) { 19009a0bf528SMauro Carvalho Chehab case 1: 19019a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 403); 19029a0bf528SMauro Carvalho Chehab break; 19039a0bf528SMauro Carvalho Chehab case 0: 19049a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 404); 19059a0bf528SMauro Carvalho Chehab break; 19069a0bf528SMauro Carvalho Chehab } 19079a0bf528SMauro Carvalho Chehab if (val & 0x200) 19089a0bf528SMauro Carvalho Chehab val -= 1024; 19099a0bf528SMauro Carvalho Chehab 19109a0bf528SMauro Carvalho Chehab return val; 19119a0bf528SMauro Carvalho Chehab } 19129a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8090p_get_dc_power); 19139a0bf528SMauro Carvalho Chehab 19149a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state) 19159a0bf528SMauro Carvalho Chehab { 19169a0bf528SMauro Carvalho Chehab u32 timf = state->timf = dib8000_read32(state, 435); 19179a0bf528SMauro Carvalho Chehab 19189a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) (timf >> 16)); 19199a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) (timf & 0xffff)); 19209a0bf528SMauro Carvalho Chehab dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); 19219a0bf528SMauro Carvalho Chehab } 19229a0bf528SMauro Carvalho Chehab 19239a0bf528SMauro Carvalho Chehab u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) 19249a0bf528SMauro Carvalho Chehab { 19259a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 19269a0bf528SMauro Carvalho Chehab 19279a0bf528SMauro Carvalho Chehab switch (op) { 19289a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_SET: 19299a0bf528SMauro Carvalho Chehab state->timf = timf; 19309a0bf528SMauro Carvalho Chehab break; 19319a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_UPDATE: 19329a0bf528SMauro Carvalho Chehab dib8000_update_timf(state); 19339a0bf528SMauro Carvalho Chehab break; 19349a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_GET: 19359a0bf528SMauro Carvalho Chehab break; 19369a0bf528SMauro Carvalho Chehab } 19379a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(state->fe[0], 6000); 19389a0bf528SMauro Carvalho Chehab 19399a0bf528SMauro Carvalho Chehab return state->timf; 19409a0bf528SMauro Carvalho Chehab } 19419a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_ctrl_timf); 19429a0bf528SMauro Carvalho Chehab 19439a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = { 19449a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117, 19459a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117, 19469a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117, 19479a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117, 19489a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117, 19499a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117, 19509a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117, 19519a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117, 19529a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117, 19539a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117, 19549a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117 19559a0bf528SMauro Carvalho Chehab }; 19569a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; 19579a0bf528SMauro Carvalho Chehab 1958173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation) 19599a0bf528SMauro Carvalho Chehab { 1960173a64cbSPatrick Boettcher u8 cr, constellation, time_intlv; 1961c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 19629a0bf528SMauro Carvalho Chehab 1963c82056d0SMauro Carvalho Chehab switch (c->layer[layer_index].modulation) { 19649a0bf528SMauro Carvalho Chehab case DQPSK: 19659a0bf528SMauro Carvalho Chehab constellation = 0; 19669a0bf528SMauro Carvalho Chehab break; 19679a0bf528SMauro Carvalho Chehab case QPSK: 19689a0bf528SMauro Carvalho Chehab constellation = 1; 19699a0bf528SMauro Carvalho Chehab break; 19709a0bf528SMauro Carvalho Chehab case QAM_16: 19719a0bf528SMauro Carvalho Chehab constellation = 2; 19729a0bf528SMauro Carvalho Chehab break; 19739a0bf528SMauro Carvalho Chehab case QAM_64: 19749a0bf528SMauro Carvalho Chehab default: 19759a0bf528SMauro Carvalho Chehab constellation = 3; 19769a0bf528SMauro Carvalho Chehab break; 19779a0bf528SMauro Carvalho Chehab } 19789a0bf528SMauro Carvalho Chehab 1979c82056d0SMauro Carvalho Chehab switch (c->layer[layer_index].fec) { 19809a0bf528SMauro Carvalho Chehab case FEC_1_2: 1981173a64cbSPatrick Boettcher cr = 1; 19829a0bf528SMauro Carvalho Chehab break; 19839a0bf528SMauro Carvalho Chehab case FEC_2_3: 1984173a64cbSPatrick Boettcher cr = 2; 19859a0bf528SMauro Carvalho Chehab break; 19869a0bf528SMauro Carvalho Chehab case FEC_3_4: 1987173a64cbSPatrick Boettcher cr = 3; 19889a0bf528SMauro Carvalho Chehab break; 19899a0bf528SMauro Carvalho Chehab case FEC_5_6: 1990173a64cbSPatrick Boettcher cr = 5; 19919a0bf528SMauro Carvalho Chehab break; 19929a0bf528SMauro Carvalho Chehab case FEC_7_8: 19939a0bf528SMauro Carvalho Chehab default: 1994173a64cbSPatrick Boettcher cr = 7; 19959a0bf528SMauro Carvalho Chehab break; 19969a0bf528SMauro Carvalho Chehab } 19979a0bf528SMauro Carvalho Chehab 1998c82056d0SMauro Carvalho Chehab if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1))) 1999c82056d0SMauro Carvalho Chehab time_intlv = c->layer[layer_index].interleaving; 20009a0bf528SMauro Carvalho Chehab else 2001173a64cbSPatrick Boettcher time_intlv = 0; 2002173a64cbSPatrick Boettcher 2003c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv); 2004c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].segment_count > 0) { 20059a0bf528SMauro Carvalho Chehab switch (max_constellation) { 20069a0bf528SMauro Carvalho Chehab case DQPSK: 20079a0bf528SMauro Carvalho Chehab case QPSK: 2008c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64) 2009c82056d0SMauro Carvalho Chehab max_constellation = c->layer[layer_index].modulation; 20109a0bf528SMauro Carvalho Chehab break; 20119a0bf528SMauro Carvalho Chehab case QAM_16: 2012c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].modulation == QAM_64) 2013c82056d0SMauro Carvalho Chehab max_constellation = c->layer[layer_index].modulation; 20149a0bf528SMauro Carvalho Chehab break; 20159a0bf528SMauro Carvalho Chehab } 20169a0bf528SMauro Carvalho Chehab } 2017173a64cbSPatrick Boettcher 2018173a64cbSPatrick Boettcher return max_constellation; 20199a0bf528SMauro Carvalho Chehab } 20209a0bf528SMauro Carvalho Chehab 2021173a64cbSPatrick 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 */ 2022173a64cbSPatrick 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 */ 2023173a64cbSPatrick 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 */ 2024173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation) 2025173a64cbSPatrick Boettcher { 2026173a64cbSPatrick Boettcher u16 i, ana_gain = 0; 2027173a64cbSPatrick Boettcher const u16 *adp; 20289a0bf528SMauro Carvalho Chehab 2029173a64cbSPatrick Boettcher /* channel estimation fine configuration */ 2030173a64cbSPatrick Boettcher switch (max_constellation) { 2031173a64cbSPatrick Boettcher case QAM_64: 2032173a64cbSPatrick Boettcher ana_gain = 0x7; 2033173a64cbSPatrick Boettcher adp = &adp_Q64[0]; 2034173a64cbSPatrick Boettcher break; 2035173a64cbSPatrick Boettcher case QAM_16: 2036173a64cbSPatrick Boettcher ana_gain = 0x7; 2037173a64cbSPatrick Boettcher adp = &adp_Q16[0]; 2038173a64cbSPatrick Boettcher break; 2039173a64cbSPatrick Boettcher default: 2040173a64cbSPatrick Boettcher ana_gain = 0; 2041173a64cbSPatrick Boettcher adp = &adp_Qdefault[0]; 2042173a64cbSPatrick Boettcher break; 20439a0bf528SMauro Carvalho Chehab } 20449a0bf528SMauro Carvalho Chehab 2045173a64cbSPatrick Boettcher for (i = 0; i < 4; i++) 2046173a64cbSPatrick Boettcher dib8000_write_word(state, 215 + i, adp[i]); 20479a0bf528SMauro Carvalho Chehab 2048173a64cbSPatrick Boettcher return ana_gain; 2049173a64cbSPatrick Boettcher } 20509a0bf528SMauro Carvalho Chehab 2051173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain) 2052173a64cbSPatrick Boettcher { 2053173a64cbSPatrick Boettcher u16 i; 20549a0bf528SMauro Carvalho Chehab 2055173a64cbSPatrick Boettcher dib8000_write_word(state, 116, ana_gain); 20569a0bf528SMauro Carvalho Chehab 2057173a64cbSPatrick Boettcher /* update ADC target depending on ana_gain */ 2058173a64cbSPatrick Boettcher if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */ 2059173a64cbSPatrick Boettcher for (i = 0; i < 10; i++) 2060173a64cbSPatrick Boettcher dib8000_write_word(state, 80 + i, adc_target_16dB[i]); 2061173a64cbSPatrick Boettcher } else { /* set -22dB ADC target for ana_gain=0 */ 2062173a64cbSPatrick Boettcher for (i = 0; i < 10; i++) 2063173a64cbSPatrick Boettcher dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355); 2064173a64cbSPatrick Boettcher } 2065173a64cbSPatrick Boettcher } 20669a0bf528SMauro Carvalho Chehab 2067173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe) 2068173a64cbSPatrick Boettcher { 2069173a64cbSPatrick Boettcher u16 mode = 0; 20709a0bf528SMauro Carvalho Chehab 2071173a64cbSPatrick Boettcher if (state->isdbt_cfg_loaded == 0) 2072173a64cbSPatrick Boettcher for (mode = 0; mode < 24; mode++) 2073173a64cbSPatrick Boettcher dib8000_write_word(state, 117 + mode, ana_fe[mode]); 2074173a64cbSPatrick Boettcher } 20759a0bf528SMauro Carvalho Chehab 2076173a64cbSPatrick Boettcher static const u16 lut_prbs_2k[14] = { 2077173a64cbSPatrick Boettcher 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213 2078173a64cbSPatrick Boettcher }; 2079173a64cbSPatrick Boettcher static const u16 lut_prbs_4k[14] = { 2080173a64cbSPatrick Boettcher 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E 2081173a64cbSPatrick Boettcher }; 2082173a64cbSPatrick Boettcher static const u16 lut_prbs_8k[14] = { 2083173a64cbSPatrick Boettcher 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684 2084173a64cbSPatrick Boettcher }; 2085173a64cbSPatrick Boettcher 2086173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel) 2087173a64cbSPatrick Boettcher { 2088173a64cbSPatrick Boettcher int sub_channel_prbs_group = 0; 2089173a64cbSPatrick Boettcher 2090173a64cbSPatrick Boettcher sub_channel_prbs_group = (subchannel / 3) + 1; 2091173a64cbSPatrick Boettcher dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]); 2092173a64cbSPatrick Boettcher 20939a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) { 20949a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 2095173a64cbSPatrick Boettcher return lut_prbs_2k[sub_channel_prbs_group]; 20969a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 2097173a64cbSPatrick Boettcher return lut_prbs_4k[sub_channel_prbs_group]; 20989a0bf528SMauro Carvalho Chehab default: 2099173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2100173a64cbSPatrick Boettcher return lut_prbs_8k[sub_channel_prbs_group]; 21019a0bf528SMauro Carvalho Chehab } 21029a0bf528SMauro Carvalho Chehab } 21039a0bf528SMauro Carvalho Chehab 2104173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state) 2105173a64cbSPatrick Boettcher { 2106173a64cbSPatrick Boettcher u16 i; 2107173a64cbSPatrick Boettcher u16 coff_pow = 0x2800; 21089a0bf528SMauro Carvalho Chehab 2109173a64cbSPatrick Boettcher state->seg_mask = 0x1fff; /* All 13 segments enabled */ 21109a0bf528SMauro Carvalho Chehab 2111173a64cbSPatrick Boettcher /* ---- COFF ---- Carloff, the most robust --- */ 2112173a64cbSPatrick Boettcher if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */ 21139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 180, (16 << 6) | 9); 21149a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2); 21159a0bf528SMauro Carvalho Chehab coff_pow = 0x2800; 21169a0bf528SMauro Carvalho Chehab for (i = 0; i < 6; i++) 21179a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 181+i, coff_pow); 21189a0bf528SMauro Carvalho Chehab 2119173a64cbSPatrick Boettcher /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */ 2120173a64cbSPatrick 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 */ 21219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1); 21229a0bf528SMauro Carvalho Chehab 2123173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */ 21249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 340, (8 << 6) | (6 << 0)); 2125173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */ 21269a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); 21279a0bf528SMauro Carvalho Chehab 2128173a64cbSPatrick Boettcher dib8000_write_word(state, 228, 0); /* default value */ 2129173a64cbSPatrick Boettcher dib8000_write_word(state, 265, 31); /* default value */ 2130173a64cbSPatrick Boettcher dib8000_write_word(state, 205, 0x200f); /* init value */ 2131173a64cbSPatrick Boettcher } 2132173a64cbSPatrick Boettcher 2133173a64cbSPatrick Boettcher /* 2134173a64cbSPatrick Boettcher * make the cpil_coff_lock more robust but slower p_coff_winlen 21359a0bf528SMauro Carvalho Chehab * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) 21369a0bf528SMauro Carvalho Chehab */ 21379a0bf528SMauro Carvalho Chehab 2138173a64cbSPatrick Boettcher if (state->cfg.pll->ifreq == 0) 2139173a64cbSPatrick Boettcher dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ 21409a0bf528SMauro Carvalho Chehab 2141173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg); 2142173a64cbSPatrick Boettcher } 21439a0bf528SMauro Carvalho Chehab 2144173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs) 2145173a64cbSPatrick Boettcher { 2146173a64cbSPatrick Boettcher u16 reg_1; 21479a0bf528SMauro Carvalho Chehab 2148173a64cbSPatrick Boettcher reg_1 = dib8000_read_word(state, 1); 2149173a64cbSPatrick Boettcher dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */ 2150173a64cbSPatrick Boettcher } 21519a0bf528SMauro Carvalho Chehab 2152173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state) 2153173a64cbSPatrick Boettcher { 2154173a64cbSPatrick Boettcher u16 i; 2155173a64cbSPatrick Boettcher const s16 *ncoeff; 2156c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 21579a0bf528SMauro Carvalho Chehab 2158173a64cbSPatrick Boettcher dib8000_write_word(state, 352, state->seg_diff_mask); 2159173a64cbSPatrick Boettcher dib8000_write_word(state, 353, state->seg_mask); 21609a0bf528SMauro Carvalho Chehab 2161173a64cbSPatrick 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 */ 2162c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5); 2163173a64cbSPatrick Boettcher 2164c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2165173a64cbSPatrick Boettcher /* ---- SMALL ---- */ 2166c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2167173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2168c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */ 2169c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */ 2170173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_1seg_dqpsk; 2171173a64cbSPatrick Boettcher else /* QPSK or QAM */ 2172173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_1seg; 2173173a64cbSPatrick Boettcher } else { /* 3-segments */ 2174c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ 2175c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2176173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; 2177173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2178173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_0dqpsk; 2179173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */ 2180c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2181173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_1dqpsk; 2182173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2183173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg; 2184173a64cbSPatrick Boettcher } 2185173a64cbSPatrick Boettcher } 21869a0bf528SMauro Carvalho Chehab break; 21879a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 2188c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */ 2189c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */ 2190173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_1seg_dqpsk; 2191173a64cbSPatrick Boettcher else /* QPSK or QAM */ 2192173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_1seg; 2193173a64cbSPatrick Boettcher } else { /* 3-segments */ 2194c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ 2195c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2196173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; 2197173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2198173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_0dqpsk; 2199173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */ 2200c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2201173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_1dqpsk; 2202173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2203173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg; 2204173a64cbSPatrick Boettcher } 2205173a64cbSPatrick Boettcher } 22069a0bf528SMauro Carvalho Chehab break; 2207173a64cbSPatrick Boettcher case TRANSMISSION_MODE_AUTO: 2208173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 22099a0bf528SMauro Carvalho Chehab default: 2210c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */ 2211c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */ 2212173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_1seg_dqpsk; 2213173a64cbSPatrick Boettcher else /* QPSK or QAM */ 2214173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_1seg; 2215173a64cbSPatrick Boettcher } else { /* 3-segments */ 2216c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ 2217c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2218173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; 2219173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2220173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_0dqpsk; 2221173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */ 2222c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ 2223173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_1dqpsk; 2224173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */ 2225173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg; 2226173a64cbSPatrick Boettcher } 2227173a64cbSPatrick Boettcher } 22289a0bf528SMauro Carvalho Chehab break; 22299a0bf528SMauro Carvalho Chehab } 2230173a64cbSPatrick Boettcher 2231173a64cbSPatrick Boettcher for (i = 0; i < 8; i++) 2232173a64cbSPatrick Boettcher dib8000_write_word(state, 343 + i, ncoeff[i]); 2233173a64cbSPatrick Boettcher } 2234173a64cbSPatrick Boettcher } 2235173a64cbSPatrick Boettcher 2236173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80}; 2237173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250}; 2238173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state) 2239173a64cbSPatrick Boettcher { 2240c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2241173a64cbSPatrick Boettcher const u16 *coff; 2242173a64cbSPatrick Boettcher u16 i; 2243173a64cbSPatrick Boettcher 2244c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) { 2245173a64cbSPatrick Boettcher dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */ 2246173a64cbSPatrick Boettcher dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */ 2247173a64cbSPatrick Boettcher } else { 2248173a64cbSPatrick Boettcher dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */ 2249173a64cbSPatrick Boettcher dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */ 2250173a64cbSPatrick Boettcher } 2251173a64cbSPatrick Boettcher 2252c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 1) /* 3-segments */ 2253173a64cbSPatrick Boettcher state->seg_mask = 0x00E0; 2254173a64cbSPatrick Boettcher else /* 1-segment */ 2255173a64cbSPatrick Boettcher state->seg_mask = 0x0040; 2256173a64cbSPatrick Boettcher 2257173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); 2258173a64cbSPatrick Boettcher 2259173a64cbSPatrick Boettcher /* ---- COFF ---- Carloff, the most robust --- */ 2260173a64cbSPatrick 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 */ 2261c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3); 2262173a64cbSPatrick Boettcher 2263173a64cbSPatrick Boettcher dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */ 2264173a64cbSPatrick 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 */ 2265173a64cbSPatrick Boettcher 2266173a64cbSPatrick Boettcher /* Sound Broadcasting mode 1 seg */ 2267c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { 2268173a64cbSPatrick 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) */ 2269173a64cbSPatrick Boettcher if (state->mode == 3) 2270173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14)); 22719a0bf528SMauro Carvalho Chehab else 2272173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14)); 2273173a64cbSPatrick Boettcher 2274173a64cbSPatrick 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 */ 2275173a64cbSPatrick Boettcher dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4); 2276173a64cbSPatrick Boettcher coff = &coff_thres_1seg[0]; 2277173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2278173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); 2279173a64cbSPatrick 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 */ 2280173a64cbSPatrick Boettcher dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4); 2281173a64cbSPatrick Boettcher coff = &coff_thres_3seg[0]; 2282173a64cbSPatrick Boettcher } 2283173a64cbSPatrick Boettcher 2284173a64cbSPatrick Boettcher dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */ 2285173a64cbSPatrick Boettcher dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */ 2286173a64cbSPatrick Boettcher 2287c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K) 2288173a64cbSPatrick Boettcher dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */ 2289173a64cbSPatrick Boettcher 2290173a64cbSPatrick Boettcher /* Write COFF thres */ 2291173a64cbSPatrick Boettcher for (i = 0 ; i < 3; i++) { 2292173a64cbSPatrick Boettcher dib8000_write_word(state, 181+i, coff[i]); 2293173a64cbSPatrick Boettcher dib8000_write_word(state, 184+i, coff[i]); 2294173a64cbSPatrick Boettcher } 2295173a64cbSPatrick Boettcher 2296173a64cbSPatrick Boettcher /* 2297173a64cbSPatrick Boettcher * make the cpil_coff_lock more robust but slower p_coff_winlen 2298173a64cbSPatrick Boettcher * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) 2299173a64cbSPatrick Boettcher */ 2300173a64cbSPatrick Boettcher 2301173a64cbSPatrick Boettcher dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */ 2302173a64cbSPatrick Boettcher 2303c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) 2304173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */ 2305173a64cbSPatrick Boettcher else 2306173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ 2307173a64cbSPatrick Boettcher } 2308173a64cbSPatrick Boettcher 2309173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching) 2310173a64cbSPatrick Boettcher { 2311173a64cbSPatrick Boettcher u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0; 2312173a64cbSPatrick Boettcher u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ; 2313173a64cbSPatrick Boettcher u16 max_constellation = DQPSK; 2314173a64cbSPatrick Boettcher int init_prbs; 2315c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2316173a64cbSPatrick Boettcher 2317173a64cbSPatrick Boettcher /* P_mode */ 2318173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (seq << 4)); 2319173a64cbSPatrick Boettcher 2320173a64cbSPatrick Boettcher /* init mode */ 2321173a64cbSPatrick Boettcher state->mode = fft_to_mode(state); 2322173a64cbSPatrick Boettcher 2323173a64cbSPatrick Boettcher /* set guard */ 2324173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 1); 2325c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3)); 2326173a64cbSPatrick Boettcher 2327c82056d0SMauro 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)); 2328173a64cbSPatrick Boettcher 2329173a64cbSPatrick Boettcher /* signal optimization parameter */ 2330c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) { 2331c82056d0SMauro Carvalho Chehab state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0]; 2332173a64cbSPatrick Boettcher for (i = 1; i < 3; i++) 2333c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; 2334173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++) 2335173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i+1]; 2336173a64cbSPatrick Boettcher } else { 2337173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) 2338c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; 2339173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++) 2340173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i]; 2341173a64cbSPatrick Boettcher } 2342173a64cbSPatrick Boettcher 2343173a64cbSPatrick Boettcher if (state->seg_diff_mask) 2344173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); 2345173a64cbSPatrick Boettcher else 2346173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */ 2347173a64cbSPatrick Boettcher 2348173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) 2349173a64cbSPatrick Boettcher max_constellation = dib8000_set_layer(state, i, max_constellation); 2350173a64cbSPatrick Boettcher if (autosearching == 0) { 2351c82056d0SMauro Carvalho Chehab state->layer_b_nb_seg = c->layer[1].segment_count; 2352c82056d0SMauro Carvalho Chehab state->layer_c_nb_seg = c->layer[2].segment_count; 2353173a64cbSPatrick Boettcher } 2354173a64cbSPatrick Boettcher 2355173a64cbSPatrick Boettcher /* WRITE: Mode & Diff mask */ 2356173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask); 2357173a64cbSPatrick Boettcher 2358173a64cbSPatrick Boettcher state->differential_constellation = (state->seg_diff_mask != 0); 23599a0bf528SMauro Carvalho Chehab 23609a0bf528SMauro Carvalho Chehab /* channel estimation fine configuration */ 2361173a64cbSPatrick Boettcher ana_gain = dib8000_adp_fine_tune(state, max_constellation); 23629a0bf528SMauro Carvalho Chehab 2363173a64cbSPatrick Boettcher /* update ana_gain depending on max constellation */ 2364173a64cbSPatrick Boettcher dib8000_update_ana_gain(state, ana_gain); 23659a0bf528SMauro Carvalho Chehab 2366173a64cbSPatrick Boettcher /* ---- ANA_FE ---- */ 2367c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) /* 3-segments */ 2368173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg); 2369173a64cbSPatrick Boettcher else 2370173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */ 2371173a64cbSPatrick Boettcher 2372173a64cbSPatrick Boettcher /* TSB or ISDBT ? apply it now */ 2373c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2374173a64cbSPatrick Boettcher dib8000_set_sb_channel(state); 2375746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_subchannel < 14) 2376c82056d0SMauro Carvalho Chehab init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel); 2377173a64cbSPatrick Boettcher else 2378173a64cbSPatrick Boettcher init_prbs = 0; 2379173a64cbSPatrick Boettcher } else { 2380173a64cbSPatrick Boettcher dib8000_set_13seg_channel(state); 2381173a64cbSPatrick Boettcher init_prbs = 0xfff; 2382173a64cbSPatrick Boettcher } 23839a0bf528SMauro Carvalho Chehab 2384173a64cbSPatrick Boettcher /* SMALL */ 2385173a64cbSPatrick Boettcher dib8000_small_fine_tune(state); 23869a0bf528SMauro Carvalho Chehab 2387173a64cbSPatrick Boettcher dib8000_set_subchannel_prbs(state, init_prbs); 2388173a64cbSPatrick Boettcher 2389173a64cbSPatrick Boettcher /* ---- CHAN_BLK ---- */ 23909a0bf528SMauro Carvalho Chehab for (i = 0; i < 13; i++) { 2391173a64cbSPatrick Boettcher if ((((~state->seg_diff_mask) >> i) & 1) == 1) { 2392173a64cbSPatrick Boettcher p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0)); 2393173a64cbSPatrick Boettcher p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0)); 23949a0bf528SMauro Carvalho Chehab } 23959a0bf528SMauro Carvalho Chehab } 2396173a64cbSPatrick Boettcher dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */ 2397173a64cbSPatrick Boettcher dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */ 2398173a64cbSPatrick Boettcher /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */ 23999a0bf528SMauro Carvalho Chehab 2400173a64cbSPatrick Boettcher dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */ 2401173a64cbSPatrick Boettcher dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */ 2402173a64cbSPatrick Boettcher dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */ 2403173a64cbSPatrick Boettcher 2404173a64cbSPatrick Boettcher if (!autosearching) 2405173a64cbSPatrick Boettcher dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ 2406173a64cbSPatrick Boettcher else 2407173a64cbSPatrick Boettcher dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */ 2408173a64cbSPatrick Boettcher 2409173a64cbSPatrick Boettcher dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */ 2410173a64cbSPatrick Boettcher dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */ 2411173a64cbSPatrick Boettcher 2412173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ 2413173a64cbSPatrick Boettcher 2414173a64cbSPatrick Boettcher /* ---- TMCC ---- */ 24159a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) 2416c82056d0SMauro Carvalho Chehab tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ; 2417173a64cbSPatrick Boettcher 2418173a64cbSPatrick Boettcher /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */ 2419173a64cbSPatrick Boettcher /* Threshold is set at 1/4 of max power. */ 24209a0bf528SMauro Carvalho Chehab tmcc_pow *= (1 << (9-2)); 2421173a64cbSPatrick Boettcher dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */ 2422173a64cbSPatrick Boettcher dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */ 2423173a64cbSPatrick Boettcher dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */ 2424173a64cbSPatrick Boettcher /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */ 24259a0bf528SMauro Carvalho Chehab 2426173a64cbSPatrick Boettcher /* ---- PHA3 ---- */ 24279a0bf528SMauro Carvalho Chehab if (state->isdbt_cfg_loaded == 0) 24289a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */ 24299a0bf528SMauro Carvalho Chehab 24309a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0; 2431173a64cbSPatrick Boettcher } 24329a0bf528SMauro Carvalho Chehab 24336f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, 24346f7ee06fSMauro Carvalho Chehab u32 wait0_ms, u32 wait1_ms, u32 wait2_ms) 2435173a64cbSPatrick Boettcher { 243613122f98SMauro Carvalho Chehab u32 value = 0; /* P_search_end0 wait time */ 2437173a64cbSPatrick Boettcher u16 reg = 11; /* P_search_end0 start addr */ 2438173a64cbSPatrick Boettcher 2439173a64cbSPatrick Boettcher for (reg = 11; reg < 16; reg += 2) { 2440173a64cbSPatrick Boettcher if (reg == 11) { 2441173a64cbSPatrick Boettcher if (state->revision == 0x8090) 244213122f98SMauro Carvalho Chehab value = internal * wait1_ms; 2443173a64cbSPatrick Boettcher else 244413122f98SMauro Carvalho Chehab value = internal * wait0_ms; 2445173a64cbSPatrick Boettcher } else if (reg == 13) 244613122f98SMauro Carvalho Chehab value = internal * wait1_ms; 2447173a64cbSPatrick Boettcher else if (reg == 15) 244813122f98SMauro Carvalho Chehab value = internal * wait2_ms; 2449173a64cbSPatrick Boettcher dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff)); 2450173a64cbSPatrick Boettcher dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff)); 2451173a64cbSPatrick Boettcher } 2452173a64cbSPatrick Boettcher return value; 24539a0bf528SMauro Carvalho Chehab } 24549a0bf528SMauro Carvalho Chehab 24559a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe) 24569a0bf528SMauro Carvalho Chehab { 24579a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 2458c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2459173a64cbSPatrick Boettcher u8 slist = 0; 2460173a64cbSPatrick Boettcher u32 value, internal = state->cfg.pll->internal; 24619a0bf528SMauro Carvalho Chehab 2462173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2463173a64cbSPatrick Boettcher internal = dib8000_read32(state, 23) / 1000; 24649a0bf528SMauro Carvalho Chehab 2465d67350f8SOlivier Grenie if ((state->revision >= 0x8002) && 2466d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) { 2467173a64cbSPatrick Boettcher dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ 2468173a64cbSPatrick Boettcher dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ 2469173a64cbSPatrick Boettcher 2470173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */ 2471173a64cbSPatrick Boettcher dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */ 2472173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */ 2473173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */ 2474173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */ 2475173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */ 2476173a64cbSPatrick Boettcher 2477173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2478173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2479173a64cbSPatrick Boettcher else 2480173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2481173a64cbSPatrick Boettcher 2482173a64cbSPatrick Boettcher dib8000_write_word(state, 17, 0); 2483173a64cbSPatrick Boettcher dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */ 2484173a64cbSPatrick Boettcher dib8000_write_word(state, 19, 0); 2485173a64cbSPatrick Boettcher dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */ 2486173a64cbSPatrick Boettcher dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */ 2487173a64cbSPatrick Boettcher dib8000_write_word(state, 22, value & 0xffff); 2488173a64cbSPatrick Boettcher 2489173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2490173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */ 2491173a64cbSPatrick Boettcher else 2492173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */ 2493173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */ 2494173a64cbSPatrick Boettcher 2495173a64cbSPatrick Boettcher /* P_search_param_select = (1 | 1<<4 | 1 << 8) */ 2496173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0); 2497173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0x111); 2498173a64cbSPatrick Boettcher 2499173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ 2500173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ 2501173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ 2502d67350f8SOlivier Grenie } else if ((state->revision >= 0x8002) && 2503d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_GUARD)) { 2504c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 2505c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 2506c82056d0SMauro Carvalho Chehab c->inversion = 0; 2507c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64; 2508c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3; 2509c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0; 2510c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 25119a0bf528SMauro Carvalho Chehab 2512173a64cbSPatrick Boettcher slist = 16; 2513c82056d0SMauro Carvalho Chehab c->transmission_mode = state->found_nfft; 2514173a64cbSPatrick Boettcher 2515173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1); 2516173a64cbSPatrick Boettcher 2517173a64cbSPatrick Boettcher /* set lock_mask values */ 2518173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0x4); 2519173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2520173a64cbSPatrick Boettcher dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */ 2521173a64cbSPatrick Boettcher else 2522173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0x8); 2523173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0x1000); 2524173a64cbSPatrick Boettcher 2525173a64cbSPatrick Boettcher /* set lock_mask wait time values */ 2526173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2527173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2528173a64cbSPatrick Boettcher else 2529173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2530173a64cbSPatrick Boettcher 2531173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */ 2532173a64cbSPatrick Boettcher 2533173a64cbSPatrick Boettcher /* P_search_param_select = 0xf; look for the 4 different guard intervals */ 2534173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0); 2535173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0xf); 2536173a64cbSPatrick Boettcher 2537173a64cbSPatrick Boettcher value = dib8000_read_word(state, 0); 2538173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)((1 << 15) | value)); 2539173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ 2540173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)value); 2541173a64cbSPatrick Boettcher } else { 2542c82056d0SMauro Carvalho Chehab c->inversion = 0; 2543c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64; 2544c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3; 2545c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0; 2546c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 2547c82056d0SMauro Carvalho Chehab if (!c->isdbt_sb_mode) 2548c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13; 2549173a64cbSPatrick Boettcher 2550173a64cbSPatrick Boettcher /* choose the right list, in sb, always do everything */ 2551c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 25529a0bf528SMauro Carvalho Chehab slist = 7; 25539a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); 25549a0bf528SMauro Carvalho Chehab } else { 2555c82056d0SMauro Carvalho Chehab if (c->guard_interval == GUARD_INTERVAL_AUTO) { 2556c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 2557c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 2558c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 25599a0bf528SMauro Carvalho Chehab slist = 7; 2560173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */ 2561173a64cbSPatrick Boettcher } else { 2562c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 25639a0bf528SMauro Carvalho Chehab slist = 3; 2564173a64cbSPatrick Boettcher } 25659a0bf528SMauro Carvalho Chehab } else { 2566c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { 2567c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 25689a0bf528SMauro Carvalho Chehab slist = 2; 2569173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */ 25709a0bf528SMauro Carvalho Chehab } else 25719a0bf528SMauro Carvalho Chehab slist = 0; 25729a0bf528SMauro Carvalho Chehab } 2573173a64cbSPatrick Boettcher } 2574173a64cbSPatrick Boettcher dprintk("Using list for autosearch : %d", slist); 25759a0bf528SMauro Carvalho Chehab 2576173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1); 25779a0bf528SMauro Carvalho Chehab 2578173a64cbSPatrick Boettcher /* set lock_mask values */ 25799a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 6, 0x4); 2580173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2581173a64cbSPatrick Boettcher dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10)); 2582173a64cbSPatrick Boettcher else 25839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 7, 0x8); 25849a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 8, 0x1000); 25859a0bf528SMauro Carvalho Chehab 2586173a64cbSPatrick Boettcher /* set lock_mask wait time values */ 2587173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2588173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 2589173a64cbSPatrick Boettcher else 2590173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ 25919a0bf528SMauro Carvalho Chehab 25929a0bf528SMauro Carvalho Chehab value = dib8000_read_word(state, 0); 25939a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)((1 << 15) | value)); 2594173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ 25959a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)value); 25969a0bf528SMauro Carvalho Chehab } 25979a0bf528SMauro Carvalho Chehab return 0; 25989a0bf528SMauro Carvalho Chehab } 25999a0bf528SMauro Carvalho Chehab 26009a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe) 26019a0bf528SMauro Carvalho Chehab { 26029a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 26039a0bf528SMauro Carvalho Chehab u16 irq_pending = dib8000_read_word(state, 1284); 26049a0bf528SMauro Carvalho Chehab 2605d67350f8SOlivier Grenie if ((state->revision >= 0x8002) && 2606d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) { 2607173a64cbSPatrick Boettcher if (irq_pending & 0x1) { 2608173a64cbSPatrick Boettcher dprintk("dib8000_autosearch_irq: max correlation result available"); 2609173a64cbSPatrick Boettcher return 3; 2610173a64cbSPatrick Boettcher } 2611173a64cbSPatrick Boettcher } else { 2612173a64cbSPatrick Boettcher if (irq_pending & 0x1) { /* failed */ 26139a0bf528SMauro Carvalho Chehab dprintk("dib8000_autosearch_irq failed"); 26149a0bf528SMauro Carvalho Chehab return 1; 26159a0bf528SMauro Carvalho Chehab } 26169a0bf528SMauro Carvalho Chehab 2617173a64cbSPatrick Boettcher if (irq_pending & 0x2) { /* succeeded */ 26189a0bf528SMauro Carvalho Chehab dprintk("dib8000_autosearch_irq succeeded"); 26199a0bf528SMauro Carvalho Chehab return 2; 26209a0bf528SMauro Carvalho Chehab } 2621173a64cbSPatrick Boettcher } 26229a0bf528SMauro Carvalho Chehab 26239a0bf528SMauro Carvalho Chehab return 0; // still pending 26249a0bf528SMauro Carvalho Chehab } 26259a0bf528SMauro Carvalho Chehab 2626173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff) 2627173a64cbSPatrick Boettcher { 2628173a64cbSPatrick Boettcher u16 tmp; 2629173a64cbSPatrick Boettcher 2630173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 771); 2631173a64cbSPatrick Boettcher if (onoff) /* start P_restart_chd : channel_decoder */ 2632173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp & 0xfffd); 2633173a64cbSPatrick Boettcher else /* stop P_restart_chd : channel_decoder */ 2634173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp | (1<<1)); 2635173a64cbSPatrick Boettcher } 2636173a64cbSPatrick Boettcher 2637173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) 2638173a64cbSPatrick Boettcher { 2639173a64cbSPatrick Boettcher s16 unit_khz_dds_val; 2640173a64cbSPatrick Boettcher u32 abs_offset_khz = ABS(offset_khz); 2641173a64cbSPatrick Boettcher u32 dds = state->cfg.pll->ifreq & 0x1ffffff; 2642173a64cbSPatrick Boettcher u8 invert = !!(state->cfg.pll->ifreq & (1 << 25)); 2643173a64cbSPatrick Boettcher u8 ratio; 2644173a64cbSPatrick Boettcher 2645173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 2646173a64cbSPatrick Boettcher ratio = 4; 2647173a64cbSPatrick Boettcher unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000); 2648173a64cbSPatrick Boettcher if (offset_khz < 0) 2649173a64cbSPatrick Boettcher dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val); 2650173a64cbSPatrick Boettcher else 2651173a64cbSPatrick Boettcher dds = (abs_offset_khz * unit_khz_dds_val); 2652173a64cbSPatrick Boettcher 2653173a64cbSPatrick Boettcher if (invert) 2654173a64cbSPatrick Boettcher dds = (1<<26) - dds; 2655173a64cbSPatrick Boettcher } else { 2656173a64cbSPatrick Boettcher ratio = 2; 2657173a64cbSPatrick Boettcher unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal); 2658173a64cbSPatrick Boettcher 2659173a64cbSPatrick Boettcher if (offset_khz < 0) 2660173a64cbSPatrick Boettcher unit_khz_dds_val *= -1; 2661173a64cbSPatrick Boettcher 2662173a64cbSPatrick Boettcher /* IF tuner */ 2663173a64cbSPatrick Boettcher if (invert) 2664173a64cbSPatrick Boettcher dds -= abs_offset_khz * unit_khz_dds_val; 2665173a64cbSPatrick Boettcher else 2666173a64cbSPatrick Boettcher dds += abs_offset_khz * unit_khz_dds_val; 2667173a64cbSPatrick Boettcher } 2668173a64cbSPatrick Boettcher 2669173a64cbSPatrick Boettcher dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val); 2670173a64cbSPatrick Boettcher 2671173a64cbSPatrick Boettcher if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) { 2672173a64cbSPatrick Boettcher /* Max dds offset is the half of the demod freq */ 2673173a64cbSPatrick Boettcher dib8000_write_word(state, 26, invert); 2674173a64cbSPatrick Boettcher dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff); 2675173a64cbSPatrick Boettcher dib8000_write_word(state, 28, (u16)(dds & 0xffff)); 2676173a64cbSPatrick Boettcher } 2677173a64cbSPatrick Boettcher } 2678173a64cbSPatrick Boettcher 2679173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state) 2680173a64cbSPatrick Boettcher { 2681c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2682173a64cbSPatrick Boettcher int i; 2683173a64cbSPatrick Boettcher u32 current_rf; 2684173a64cbSPatrick Boettcher int total_dds_offset_khz; 2685173a64cbSPatrick Boettcher 2686173a64cbSPatrick Boettcher if (state->fe[0]->ops.tuner_ops.get_frequency) 2687173a64cbSPatrick Boettcher state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], ¤t_rf); 2688173a64cbSPatrick Boettcher else 2689c82056d0SMauro Carvalho Chehab current_rf = c->frequency; 2690173a64cbSPatrick Boettcher current_rf /= 1000; 2691c82056d0SMauro Carvalho Chehab total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000; 2692173a64cbSPatrick Boettcher 2693c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2694c82056d0SMauro Carvalho Chehab state->subchannel = c->isdbt_sb_subchannel; 2695173a64cbSPatrick Boettcher 2696173a64cbSPatrick Boettcher i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */ 2697c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 26, c->inversion ^ i); 2698173a64cbSPatrick Boettcher 2699173a64cbSPatrick Boettcher if (state->cfg.pll->ifreq == 0) { /* low if tuner */ 2700c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0) 2701173a64cbSPatrick Boettcher dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); 2702173a64cbSPatrick Boettcher } else { 2703c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0) 2704173a64cbSPatrick Boettcher total_dds_offset_khz *= -1; 2705173a64cbSPatrick Boettcher } 2706173a64cbSPatrick Boettcher } 2707173a64cbSPatrick Boettcher 2708c82056d0SMauro 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); 2709173a64cbSPatrick Boettcher 2710173a64cbSPatrick Boettcher /* apply dds offset now */ 2711173a64cbSPatrick Boettcher dib8000_set_dds(state, total_dds_offset_khz); 2712173a64cbSPatrick Boettcher } 2713173a64cbSPatrick Boettcher 2714173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 }; 27156f7ee06fSMauro Carvalho Chehab 27166f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state) 2717173a64cbSPatrick Boettcher { 2718c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2719173a64cbSPatrick Boettcher u16 i; 2720173a64cbSPatrick Boettcher 2721c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2722173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2723173a64cbSPatrick Boettcher i = 0; 2724173a64cbSPatrick Boettcher break; 2725173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K: 2726173a64cbSPatrick Boettcher i = 2; 2727173a64cbSPatrick Boettcher break; 2728173a64cbSPatrick Boettcher default: 2729173a64cbSPatrick Boettcher case TRANSMISSION_MODE_AUTO: 2730173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2731173a64cbSPatrick Boettcher i = 1; 2732173a64cbSPatrick Boettcher break; 2733173a64cbSPatrick Boettcher } 2734173a64cbSPatrick Boettcher 2735c82056d0SMauro Carvalho Chehab return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1; 2736173a64cbSPatrick Boettcher } 2737173a64cbSPatrick Boettcher 2738173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step) 2739173a64cbSPatrick Boettcher { 2740c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2741173a64cbSPatrick Boettcher u16 reg_32 = 0, reg_37 = 0; 2742173a64cbSPatrick Boettcher 2743173a64cbSPatrick Boettcher switch (loop_step) { 2744173a64cbSPatrick Boettcher case LOOP_TUNE_1: 2745c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2746c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { 2747173a64cbSPatrick Boettcher reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */ 2748173a64cbSPatrick 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) */ 2749173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2750173a64cbSPatrick Boettcher reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */ 2751173a64cbSPatrick 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) */ 2752173a64cbSPatrick Boettcher } 2753173a64cbSPatrick Boettcher } else { /* 13-seg start conf offset loop parameters */ 2754173a64cbSPatrick Boettcher reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ 2755173a64cbSPatrick 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 */ 2756173a64cbSPatrick Boettcher } 2757173a64cbSPatrick Boettcher break; 2758173a64cbSPatrick Boettcher case LOOP_TUNE_2: 2759c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) { 2760c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */ 2761173a64cbSPatrick Boettcher reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/ 2762173a64cbSPatrick Boettcher reg_37 = (12-state->mode) | ((5 + state->mode) << 5); 2763173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */ 2764173a64cbSPatrick Boettcher reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */ 2765173a64cbSPatrick Boettcher reg_37 = (11-state->mode) | ((5 + state->mode) << 5); 2766173a64cbSPatrick Boettcher } 2767173a64cbSPatrick Boettcher } else { /* 13 seg */ 2768173a64cbSPatrick Boettcher reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */ 2769173a64cbSPatrick Boettcher reg_37 = ((5+state->mode) << 5) | (10 - state->mode); 2770173a64cbSPatrick Boettcher } 2771173a64cbSPatrick Boettcher break; 2772173a64cbSPatrick Boettcher } 2773173a64cbSPatrick Boettcher dib8000_write_word(state, 32, reg_32); 2774173a64cbSPatrick Boettcher dib8000_write_word(state, 37, reg_37); 2775173a64cbSPatrick Boettcher } 2776173a64cbSPatrick Boettcher 2777173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state) 2778173a64cbSPatrick Boettcher { 2779173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x4000); 2780173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x0000); 2781173a64cbSPatrick Boettcher return; 2782173a64cbSPatrick Boettcher } 2783173a64cbSPatrick Boettcher 2784173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state) 2785173a64cbSPatrick Boettcher { 2786c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2787173a64cbSPatrick Boettcher u16 sync_wait = 64; 2788173a64cbSPatrick Boettcher 2789173a64cbSPatrick Boettcher /* P_dvsy_sync_wait - reuse mode */ 2790c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) { 2791173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K: 2792173a64cbSPatrick Boettcher sync_wait = 256; 2793173a64cbSPatrick Boettcher break; 2794173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K: 2795173a64cbSPatrick Boettcher sync_wait = 128; 2796173a64cbSPatrick Boettcher break; 2797173a64cbSPatrick Boettcher default: 2798173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K: 2799173a64cbSPatrick Boettcher sync_wait = 64; 2800173a64cbSPatrick Boettcher break; 2801173a64cbSPatrick Boettcher } 2802173a64cbSPatrick Boettcher 2803173a64cbSPatrick Boettcher if (state->cfg.diversity_delay == 0) 2804c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */ 2805173a64cbSPatrick Boettcher else 2806c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */ 2807173a64cbSPatrick Boettcher 2808173a64cbSPatrick Boettcher dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4)); 2809173a64cbSPatrick Boettcher } 2810173a64cbSPatrick Boettcher 2811173a64cbSPatrick Boettcher static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode) 2812173a64cbSPatrick Boettcher { 2813173a64cbSPatrick Boettcher if (mode == SYMBOL_DEPENDENT_ON) 2814173a64cbSPatrick Boettcher return systime() + (delay * state->symbol_duration); 2815173a64cbSPatrick Boettcher else 2816173a64cbSPatrick Boettcher return systime() + delay; 2817173a64cbSPatrick Boettcher } 2818173a64cbSPatrick Boettcher 2819173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe) 2820173a64cbSPatrick Boettcher { 2821173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2822173a64cbSPatrick Boettcher return state->status; 2823173a64cbSPatrick Boettcher } 2824173a64cbSPatrick Boettcher 2825173a64cbSPatrick Boettcher enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) 2826173a64cbSPatrick Boettcher { 2827173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2828173a64cbSPatrick Boettcher return state->tune_state; 2829173a64cbSPatrick Boettcher } 2830173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_get_tune_state); 2831173a64cbSPatrick Boettcher 2832173a64cbSPatrick Boettcher int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) 2833173a64cbSPatrick Boettcher { 2834173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2835173a64cbSPatrick Boettcher 2836173a64cbSPatrick Boettcher state->tune_state = tune_state; 2837173a64cbSPatrick Boettcher return 0; 2838173a64cbSPatrick Boettcher } 2839173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_set_tune_state); 2840173a64cbSPatrick Boettcher 2841173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe) 2842173a64cbSPatrick Boettcher { 2843173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2844173a64cbSPatrick Boettcher 2845173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING; 2846173a64cbSPatrick Boettcher state->tune_state = CT_DEMOD_START; 2847173a64cbSPatrick Boettcher return 0; 2848173a64cbSPatrick Boettcher } 2849173a64cbSPatrick Boettcher 2850173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe) 2851173a64cbSPatrick Boettcher { 2852173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv; 2853173a64cbSPatrick Boettcher 2854173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2855173a64cbSPatrick Boettcher return dib8000_read_word(state, 570); 2856173a64cbSPatrick Boettcher return dib8000_read_word(state, 568); 2857173a64cbSPatrick Boettcher } 2858173a64cbSPatrick Boettcher 2859173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state) 2860173a64cbSPatrick Boettcher { 2861173a64cbSPatrick Boettcher u16 reg = 0; 2862173a64cbSPatrick Boettcher dprintk("init sdram"); 2863173a64cbSPatrick Boettcher 2864173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 274) & 0xfff0; 2865173a64cbSPatrick Boettcher dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */ 2866173a64cbSPatrick Boettcher 2867173a64cbSPatrick Boettcher dib8000_write_word(state, 1803, (7 << 2)); 2868173a64cbSPatrick Boettcher 2869173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 1280); 2870173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */ 2871173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */ 2872173a64cbSPatrick Boettcher 2873173a64cbSPatrick Boettcher return 0; 2874173a64cbSPatrick Boettcher } 2875173a64cbSPatrick Boettcher 28769a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe) 28779a0bf528SMauro Carvalho Chehab { 28789a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 2879c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 2880173a64cbSPatrick Boettcher enum frontend_tune_state *tune_state = &state->tune_state; 28819a0bf528SMauro Carvalho Chehab 2882173a64cbSPatrick Boettcher u16 locks, deeper_interleaver = 0, i; 2883173a64cbSPatrick Boettcher int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */ 28849a0bf528SMauro Carvalho Chehab 2885173a64cbSPatrick Boettcher u32 *timeout = &state->timeout; 2886173a64cbSPatrick Boettcher u32 now = systime(); 2887173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 2888173a64cbSPatrick Boettcher u16 agc1, agc2; 2889173a64cbSPatrick Boettcher #endif 28909a0bf528SMauro Carvalho Chehab 2891173a64cbSPatrick Boettcher u32 corm[4] = {0, 0, 0, 0}; 2892173a64cbSPatrick Boettcher u8 find_index, max_value; 28939a0bf528SMauro Carvalho Chehab 2894173a64cbSPatrick Boettcher #if 0 2895173a64cbSPatrick Boettcher if (*tune_state < CT_DEMOD_STOP) 2896173a64cbSPatrick Boettcher dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now); 2897173a64cbSPatrick Boettcher #endif 28989a0bf528SMauro Carvalho Chehab 2899173a64cbSPatrick Boettcher switch (*tune_state) { 2900173a64cbSPatrick Boettcher case CT_DEMOD_START: /* 30 */ 2901173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2902173a64cbSPatrick Boettcher dib8090p_init_sdram(state); 2903173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING; 2904c82056d0SMauro Carvalho Chehab if ((c->delivery_system != SYS_ISDBT) || 2905c82056d0SMauro Carvalho Chehab (c->inversion == INVERSION_AUTO) || 2906c82056d0SMauro Carvalho Chehab (c->transmission_mode == TRANSMISSION_MODE_AUTO) || 2907c82056d0SMauro Carvalho Chehab (c->guard_interval == GUARD_INTERVAL_AUTO) || 2908c82056d0SMauro Carvalho Chehab (((c->isdbt_layer_enabled & (1 << 0)) != 0) && 2909c82056d0SMauro Carvalho Chehab (c->layer[0].segment_count != 0xff) && 2910c82056d0SMauro Carvalho Chehab (c->layer[0].segment_count != 0) && 2911c82056d0SMauro Carvalho Chehab ((c->layer[0].modulation == QAM_AUTO) || 2912c82056d0SMauro Carvalho Chehab (c->layer[0].fec == FEC_AUTO))) || 2913c82056d0SMauro Carvalho Chehab (((c->isdbt_layer_enabled & (1 << 1)) != 0) && 2914c82056d0SMauro Carvalho Chehab (c->layer[1].segment_count != 0xff) && 2915c82056d0SMauro Carvalho Chehab (c->layer[1].segment_count != 0) && 2916c82056d0SMauro Carvalho Chehab ((c->layer[1].modulation == QAM_AUTO) || 2917c82056d0SMauro Carvalho Chehab (c->layer[1].fec == FEC_AUTO))) || 2918c82056d0SMauro Carvalho Chehab (((c->isdbt_layer_enabled & (1 << 2)) != 0) && 2919c82056d0SMauro Carvalho Chehab (c->layer[2].segment_count != 0xff) && 2920c82056d0SMauro Carvalho Chehab (c->layer[2].segment_count != 0) && 2921c82056d0SMauro Carvalho Chehab ((c->layer[2].modulation == QAM_AUTO) || 2922c82056d0SMauro Carvalho Chehab (c->layer[2].fec == FEC_AUTO))) || 2923c82056d0SMauro Carvalho Chehab (((c->layer[0].segment_count == 0) || 2924c82056d0SMauro Carvalho Chehab ((c->isdbt_layer_enabled & (1 << 0)) == 0)) && 2925c82056d0SMauro Carvalho Chehab ((c->layer[1].segment_count == 0) || 2926c82056d0SMauro Carvalho Chehab ((c->isdbt_layer_enabled & (2 << 0)) == 0)) && 2927c82056d0SMauro Carvalho Chehab ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0)))) 2928173a64cbSPatrick Boettcher state->channel_parameters_set = 0; /* auto search */ 29299a0bf528SMauro Carvalho Chehab else 2930173a64cbSPatrick Boettcher state->channel_parameters_set = 1; /* channel parameters are known */ 29319a0bf528SMauro Carvalho Chehab 2932173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 0); /* force chan dec in restart */ 29339a0bf528SMauro Carvalho Chehab 2934173a64cbSPatrick Boettcher /* Layer monit */ 2935173a64cbSPatrick Boettcher dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); 2936173a64cbSPatrick Boettcher 2937173a64cbSPatrick Boettcher dib8000_set_frequency_offset(state); 2938c82056d0SMauro Carvalho Chehab dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000); 2939173a64cbSPatrick Boettcher 2940173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */ 2941173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 2942173a64cbSPatrick Boettcher if (state->revision != 0x8090) { 2943173a64cbSPatrick Boettcher state->agc1_max = dib8000_read_word(state, 108); 2944173a64cbSPatrick Boettcher state->agc1_min = dib8000_read_word(state, 109); 2945173a64cbSPatrick Boettcher state->agc2_max = dib8000_read_word(state, 110); 2946173a64cbSPatrick Boettcher state->agc2_min = dib8000_read_word(state, 111); 2947173a64cbSPatrick Boettcher agc1 = dib8000_read_word(state, 388); 2948173a64cbSPatrick Boettcher agc2 = dib8000_read_word(state, 389); 2949173a64cbSPatrick Boettcher dib8000_write_word(state, 108, agc1); 2950173a64cbSPatrick Boettcher dib8000_write_word(state, 109, agc1); 2951173a64cbSPatrick Boettcher dib8000_write_word(state, 110, agc2); 2952173a64cbSPatrick Boettcher dib8000_write_word(state, 111, agc2); 2953173a64cbSPatrick Boettcher } 2954173a64cbSPatrick Boettcher #endif 2955173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_FFT; 2956173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_AUTO; 2957173a64cbSPatrick Boettcher state->found_guard = GUARD_INTERVAL_AUTO; 2958173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT; 2959173a64cbSPatrick Boettcher } else { /* we already know the channel struct so TUNE only ! */ 2960173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 2961173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 2962173a64cbSPatrick Boettcher } 2963173a64cbSPatrick Boettcher state->symbol_duration = dib8000_get_symbol_duration(state); 2964173a64cbSPatrick Boettcher break; 2965173a64cbSPatrick Boettcher 2966173a64cbSPatrick Boettcher case CT_DEMOD_SEARCH_NEXT: /* 51 */ 2967173a64cbSPatrick Boettcher dib8000_autosearch_start(fe); 2968173a64cbSPatrick Boettcher if (state->revision == 0x8090) 2969173a64cbSPatrick Boettcher ret = 50; 2970173a64cbSPatrick Boettcher else 2971173a64cbSPatrick Boettcher ret = 15; 2972173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_1; 2973173a64cbSPatrick Boettcher break; 2974173a64cbSPatrick Boettcher 2975173a64cbSPatrick Boettcher case CT_DEMOD_STEP_1: /* 31 */ 2976173a64cbSPatrick Boettcher switch (dib8000_autosearch_irq(fe)) { 2977173a64cbSPatrick Boettcher case 1: /* fail */ 2978173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 2979173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 2980173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */ 2981173a64cbSPatrick Boettcher break; 2982173a64cbSPatrick Boettcher case 2: /* Succes */ 2983173a64cbSPatrick Boettcher state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */ 2984173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 2985173a64cbSPatrick Boettcher if (state->autosearch_state == AS_SEARCHING_GUARD) 2986173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2; 2987173a64cbSPatrick Boettcher else 2988173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 2989173a64cbSPatrick Boettcher break; 2990173a64cbSPatrick Boettcher case 3: /* Autosearch FFT max correlation endded */ 2991173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2; 2992173a64cbSPatrick Boettcher break; 2993173a64cbSPatrick Boettcher } 2994173a64cbSPatrick Boettcher break; 2995173a64cbSPatrick Boettcher 2996173a64cbSPatrick Boettcher case CT_DEMOD_STEP_2: 2997173a64cbSPatrick Boettcher switch (state->autosearch_state) { 2998173a64cbSPatrick Boettcher case AS_SEARCHING_FFT: 2999173a64cbSPatrick Boettcher /* searching for the correct FFT */ 3000173a64cbSPatrick Boettcher if (state->revision == 0x8090) { 3001173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); 3002173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); 3003173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601)); 3004173a64cbSPatrick Boettcher } else { 3005173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595)); 3006173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); 3007173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); 3008173a64cbSPatrick Boettcher } 3009173a64cbSPatrick Boettcher /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */ 3010173a64cbSPatrick Boettcher 3011173a64cbSPatrick Boettcher max_value = 0; 3012173a64cbSPatrick Boettcher for (find_index = 1 ; find_index < 3 ; find_index++) { 3013173a64cbSPatrick Boettcher if (corm[max_value] < corm[find_index]) 3014173a64cbSPatrick Boettcher max_value = find_index ; 30159a0bf528SMauro Carvalho Chehab } 30169a0bf528SMauro Carvalho Chehab 3017173a64cbSPatrick Boettcher switch (max_value) { 3018173a64cbSPatrick Boettcher case 0: 3019173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_2K; 3020173a64cbSPatrick Boettcher break; 3021173a64cbSPatrick Boettcher case 1: 3022173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_4K; 3023173a64cbSPatrick Boettcher break; 3024173a64cbSPatrick Boettcher case 2: 3025173a64cbSPatrick Boettcher default: 3026173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_8K; 3027173a64cbSPatrick Boettcher break; 3028173a64cbSPatrick Boettcher } 3029173a64cbSPatrick Boettcher /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */ 3030173a64cbSPatrick Boettcher 3031173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT; 3032173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_GUARD; 3033173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3034173a64cbSPatrick Boettcher ret = 50; 3035173a64cbSPatrick Boettcher else 3036173a64cbSPatrick Boettcher ret = 10; 3037173a64cbSPatrick Boettcher break; 3038173a64cbSPatrick Boettcher case AS_SEARCHING_GUARD: 3039173a64cbSPatrick Boettcher /* searching for the correct guard interval */ 3040173a64cbSPatrick Boettcher if (state->revision == 0x8090) 3041173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 572) & 0x3; 3042173a64cbSPatrick Boettcher else 3043173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 570) & 0x3; 3044173a64cbSPatrick Boettcher /* dprintk("guard interval found=%i", state->found_guard); */ 3045173a64cbSPatrick Boettcher 3046173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3; 3047173a64cbSPatrick Boettcher break; 3048173a64cbSPatrick Boettcher default: 3049173a64cbSPatrick Boettcher /* the demod should never be in this state */ 3050173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3051173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE; 3052173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */ 3053173a64cbSPatrick Boettcher break; 3054173a64cbSPatrick Boettcher } 3055173a64cbSPatrick Boettcher break; 3056173a64cbSPatrick Boettcher 3057173a64cbSPatrick Boettcher case CT_DEMOD_STEP_3: /* 33 */ 3058173a64cbSPatrick Boettcher state->symbol_duration = dib8000_get_symbol_duration(state); 3059173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1); 3060173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */ 3061173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_4; 3062173a64cbSPatrick Boettcher break; 3063173a64cbSPatrick Boettcher 3064173a64cbSPatrick Boettcher case CT_DEMOD_STEP_4: /* (34) */ 3065173a64cbSPatrick Boettcher dib8000_demod_restart(state); 3066173a64cbSPatrick Boettcher 3067173a64cbSPatrick Boettcher dib8000_set_sync_wait(state); 3068173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); 3069173a64cbSPatrick Boettcher 3070173a64cbSPatrick Boettcher locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */ 307139c1cb2bSJonathan McCrohan /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */ 3072173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON); 3073173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_5; 3074173a64cbSPatrick Boettcher break; 3075173a64cbSPatrick Boettcher 3076173a64cbSPatrick Boettcher case CT_DEMOD_STEP_5: /* (35) */ 3077173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3078173a64cbSPatrick Boettcher if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */ 3079173a64cbSPatrick Boettcher dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */ 3080173a64cbSPatrick Boettcher if (!state->differential_constellation) { 3081173a64cbSPatrick Boettcher /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */ 3082173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON); 3083173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_7; 3084173a64cbSPatrick Boettcher } else { 3085173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; 3086173a64cbSPatrick Boettcher } 3087173a64cbSPatrick Boettcher } else if (now > *timeout) { 3088173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ 3089173a64cbSPatrick Boettcher } 3090173a64cbSPatrick Boettcher break; 3091173a64cbSPatrick Boettcher 3092173a64cbSPatrick Boettcher case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */ 3093173a64cbSPatrick Boettcher if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { 3094173a64cbSPatrick 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 */ 3095173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ 3096173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ 3097173a64cbSPatrick Boettcher else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */ 3098173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ 3099173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3100173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3101173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3102173a64cbSPatrick Boettcher } 3103173a64cbSPatrick Boettcher } else { 3104173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3105173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3106173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ 3107173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3108173a64cbSPatrick Boettcher } 3109173a64cbSPatrick Boettcher break; 3110173a64cbSPatrick Boettcher 3111173a64cbSPatrick Boettcher case CT_DEMOD_STEP_7: /* 37 */ 3112173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3113173a64cbSPatrick Boettcher if (locks & (1<<10)) { /* lmod4_lock */ 3114173a64cbSPatrick Boettcher ret = 14; /* wait for 14 symbols */ 3115173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; 3116173a64cbSPatrick Boettcher } else if (now > *timeout) 3117173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ 3118173a64cbSPatrick Boettcher break; 3119173a64cbSPatrick Boettcher 3120173a64cbSPatrick Boettcher case CT_DEMOD_STEP_8: /* 38 */ 3121173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */ 3122173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); 3123173a64cbSPatrick Boettcher 3124173a64cbSPatrick Boettcher /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ 3125746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3126746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3127746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) { 3128173a64cbSPatrick Boettcher state->subchannel = 0; 3129173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11; 3130173a64cbSPatrick Boettcher } else { 3131173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9; 3132173a64cbSPatrick Boettcher state->status = FE_STATUS_LOCKED; 3133173a64cbSPatrick Boettcher } 3134173a64cbSPatrick Boettcher break; 3135173a64cbSPatrick Boettcher 3136173a64cbSPatrick Boettcher case CT_DEMOD_STEP_9: /* 39 */ 3137173a64cbSPatrick Boettcher if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */ 313839c1cb2bSJonathan McCrohan /* defines timeout for mpeg lock depending on interleaver length of longest layer */ 3139173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) { 3140c82056d0SMauro Carvalho Chehab if (c->layer[i].interleaving >= deeper_interleaver) { 3141c82056d0SMauro Carvalho Chehab dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving); 3142c82056d0SMauro Carvalho Chehab if (c->layer[i].segment_count > 0) { /* valid layer */ 3143c82056d0SMauro Carvalho Chehab deeper_interleaver = c->layer[0].interleaving; 3144173a64cbSPatrick Boettcher state->longest_intlv_layer = i; 3145173a64cbSPatrick Boettcher } 3146173a64cbSPatrick Boettcher } 3147173a64cbSPatrick Boettcher } 3148173a64cbSPatrick Boettcher 3149173a64cbSPatrick Boettcher if (deeper_interleaver == 0) 3150173a64cbSPatrick Boettcher locks = 2; /* locks is the tmp local variable name */ 3151173a64cbSPatrick Boettcher else if (deeper_interleaver == 3) 3152173a64cbSPatrick Boettcher locks = 8; 3153173a64cbSPatrick Boettcher else 3154173a64cbSPatrick Boettcher locks = 2 * deeper_interleaver; 3155173a64cbSPatrick Boettcher 3156173a64cbSPatrick Boettcher if (state->diversity_onoff != 0) /* because of diversity sync */ 3157173a64cbSPatrick Boettcher locks *= 2; 3158173a64cbSPatrick Boettcher 3159173a64cbSPatrick Boettcher *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */ 3160173a64cbSPatrick 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); 3161173a64cbSPatrick Boettcher 3162173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_10; 3163173a64cbSPatrick Boettcher } else 3164173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3165173a64cbSPatrick Boettcher break; 3166173a64cbSPatrick Boettcher 3167173a64cbSPatrick Boettcher case CT_DEMOD_STEP_10: /* 40 */ 3168173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe); 3169173a64cbSPatrick Boettcher if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ 3170173a64cbSPatrick Boettcher dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); 3171746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3172746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3173746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) 3174173a64cbSPatrick Boettcher /* signal to the upper layer, that there was a channel found and the parameters can be read */ 3175173a64cbSPatrick Boettcher state->status = FE_STATUS_DEMOD_SUCCESS; 3176173a64cbSPatrick Boettcher else 3177173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED; 3178173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3179173a64cbSPatrick Boettcher } else if (now > *timeout) { 3180746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode 3181746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14 3182746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) { /* continue to try init prbs autosearch */ 3183173a64cbSPatrick Boettcher state->subchannel += 3; 3184173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11; 3185173a64cbSPatrick 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 */ 3186173a64cbSPatrick Boettcher if (locks & (0x7<<5)) { 3187173a64cbSPatrick Boettcher dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); 3188173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED; 3189173a64cbSPatrick Boettcher } else 3190173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3191173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3192173a64cbSPatrick Boettcher } 3193173a64cbSPatrick Boettcher } 3194173a64cbSPatrick Boettcher break; 3195173a64cbSPatrick Boettcher 3196173a64cbSPatrick Boettcher case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */ 3197173a64cbSPatrick Boettcher if (state->subchannel <= 41) { 3198173a64cbSPatrick Boettcher dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); 3199173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9; 3200173a64cbSPatrick Boettcher } else { 3201173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; 3202173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED; 3203173a64cbSPatrick Boettcher } 3204173a64cbSPatrick Boettcher break; 3205173a64cbSPatrick Boettcher 3206173a64cbSPatrick Boettcher default: 3207173a64cbSPatrick Boettcher break; 3208173a64cbSPatrick Boettcher } 3209173a64cbSPatrick Boettcher 3210173a64cbSPatrick Boettcher /* tuning is finished - cleanup the demod */ 3211173a64cbSPatrick Boettcher switch (*tune_state) { 3212173a64cbSPatrick Boettcher case CT_DEMOD_STOP: /* (42) */ 3213173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE 3214173a64cbSPatrick Boettcher if ((state->revision != 0x8090) && (state->agc1_max != 0)) { 3215173a64cbSPatrick Boettcher dib8000_write_word(state, 108, state->agc1_max); 3216173a64cbSPatrick Boettcher dib8000_write_word(state, 109, state->agc1_min); 3217173a64cbSPatrick Boettcher dib8000_write_word(state, 110, state->agc2_max); 3218173a64cbSPatrick Boettcher dib8000_write_word(state, 111, state->agc2_min); 3219173a64cbSPatrick Boettcher state->agc1_max = 0; 3220173a64cbSPatrick Boettcher state->agc1_min = 0; 3221173a64cbSPatrick Boettcher state->agc2_max = 0; 3222173a64cbSPatrick Boettcher state->agc2_min = 0; 3223173a64cbSPatrick Boettcher } 3224173a64cbSPatrick Boettcher #endif 3225173a64cbSPatrick Boettcher ret = FE_CALLBACK_TIME_NEVER; 3226173a64cbSPatrick Boettcher break; 3227173a64cbSPatrick Boettcher default: 3228173a64cbSPatrick Boettcher break; 3229173a64cbSPatrick Boettcher } 3230173a64cbSPatrick Boettcher 3231173a64cbSPatrick Boettcher if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3)) 3232173a64cbSPatrick Boettcher return ret * state->symbol_duration; 3233173a64cbSPatrick Boettcher if ((ret > 0) && (ret < state->symbol_duration)) 3234173a64cbSPatrick Boettcher return state->symbol_duration; /* at least one symbol */ 32359a0bf528SMauro Carvalho Chehab return ret; 32369a0bf528SMauro Carvalho Chehab } 32379a0bf528SMauro Carvalho Chehab 32389a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe) 32399a0bf528SMauro Carvalho Chehab { 32409a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 32419a0bf528SMauro Carvalho Chehab u8 index_frontend; 32429a0bf528SMauro Carvalho Chehab int ret; 32439a0bf528SMauro Carvalho Chehab 32449a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL); 32459a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON); 32469a0bf528SMauro Carvalho Chehab if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) 32479a0bf528SMauro Carvalho Chehab dprintk("could not start Slow ADC"); 32489a0bf528SMauro Carvalho Chehab 3249173a64cbSPatrick Boettcher if (state->revision == 0x8090) 32509a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state); 32519a0bf528SMauro Carvalho Chehab 32529a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 32539a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); 32549a0bf528SMauro Carvalho Chehab if (ret < 0) 32559a0bf528SMauro Carvalho Chehab return ret; 32569a0bf528SMauro Carvalho Chehab } 32579a0bf528SMauro Carvalho Chehab 32589a0bf528SMauro Carvalho Chehab return 0; 32599a0bf528SMauro Carvalho Chehab } 32609a0bf528SMauro Carvalho Chehab 32619a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe) 32629a0bf528SMauro Carvalho Chehab { 32639a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 32649a0bf528SMauro Carvalho Chehab u8 index_frontend; 32659a0bf528SMauro Carvalho Chehab int ret; 32669a0bf528SMauro Carvalho Chehab 32679a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 32689a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); 32699a0bf528SMauro Carvalho Chehab if (ret < 0) 32709a0bf528SMauro Carvalho Chehab return ret; 32719a0bf528SMauro Carvalho Chehab } 32729a0bf528SMauro Carvalho Chehab 32739a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 32749a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); 32759a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); 32769a0bf528SMauro Carvalho Chehab return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); 32779a0bf528SMauro Carvalho Chehab } 32789a0bf528SMauro Carvalho Chehab 327970315b3eSMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat); 328070315b3eSMauro Carvalho Chehab 32819a0bf528SMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe) 32829a0bf528SMauro Carvalho Chehab { 32839a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 32849a0bf528SMauro Carvalho Chehab u16 i, val = 0; 328570315b3eSMauro Carvalho Chehab fe_status_t stat = 0; 32869a0bf528SMauro Carvalho Chehab u8 index_frontend, sub_index_frontend; 32879a0bf528SMauro Carvalho Chehab 32889a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.bandwidth_hz = 6000000; 32899a0bf528SMauro Carvalho Chehab 329070315b3eSMauro Carvalho Chehab /* 329170315b3eSMauro Carvalho Chehab * If called to early, get_frontend makes dib8000_tune to either 329270315b3eSMauro Carvalho Chehab * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail. 329370315b3eSMauro Carvalho Chehab * So, let's just return if frontend 0 has not locked. 329470315b3eSMauro Carvalho Chehab */ 329570315b3eSMauro Carvalho Chehab dib8000_read_status(fe, &stat); 329670315b3eSMauro Carvalho Chehab if (!(stat & FE_HAS_SYNC)) 329770315b3eSMauro Carvalho Chehab return 0; 329870315b3eSMauro Carvalho Chehab 329970315b3eSMauro Carvalho Chehab dprintk("TMCC lock"); 33009a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 33019a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); 33029a0bf528SMauro Carvalho Chehab if (stat&FE_HAS_SYNC) { 33039a0bf528SMauro Carvalho Chehab dprintk("TMCC lock on the slave%i", index_frontend); 33049a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 33059a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]); 33069a0bf528SMauro Carvalho Chehab for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { 33079a0bf528SMauro Carvalho Chehab if (sub_index_frontend != index_frontend) { 33089a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; 33099a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; 33109a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; 33119a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; 33129a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; 33139a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 33149a0bf528SMauro 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; 33159a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; 33169a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; 33179a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; 33189a0bf528SMauro Carvalho Chehab } 33199a0bf528SMauro Carvalho Chehab } 33209a0bf528SMauro Carvalho Chehab } 33219a0bf528SMauro Carvalho Chehab return 0; 33229a0bf528SMauro Carvalho Chehab } 33239a0bf528SMauro Carvalho Chehab } 33249a0bf528SMauro Carvalho Chehab 33259a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; 33269a0bf528SMauro Carvalho Chehab 33279a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 33289a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 572); 33299a0bf528SMauro Carvalho Chehab else 33309a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 570); 33319a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.inversion = (val & 0x40) >> 6; 33329a0bf528SMauro Carvalho Chehab switch ((val & 0x30) >> 4) { 33339a0bf528SMauro Carvalho Chehab case 1: 33349a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; 33359a0bf528SMauro Carvalho Chehab break; 33369a0bf528SMauro Carvalho Chehab case 3: 33379a0bf528SMauro Carvalho Chehab default: 33389a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; 33399a0bf528SMauro Carvalho Chehab break; 33409a0bf528SMauro Carvalho Chehab } 33419a0bf528SMauro Carvalho Chehab 33429a0bf528SMauro Carvalho Chehab switch (val & 0x3) { 33439a0bf528SMauro Carvalho Chehab case 0: 33449a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; 33459a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/32 "); 33469a0bf528SMauro Carvalho Chehab break; 33479a0bf528SMauro Carvalho Chehab case 1: 33489a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; 33499a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/16 "); 33509a0bf528SMauro Carvalho Chehab break; 33519a0bf528SMauro Carvalho Chehab case 2: 33529a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/8 "); 33539a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; 33549a0bf528SMauro Carvalho Chehab break; 33559a0bf528SMauro Carvalho Chehab case 3: 33569a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend GI = 1/4 "); 33579a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; 33589a0bf528SMauro Carvalho Chehab break; 33599a0bf528SMauro Carvalho Chehab } 33609a0bf528SMauro Carvalho Chehab 33619a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 505); 33629a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.isdbt_partial_reception = val & 1; 33639a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception); 33649a0bf528SMauro Carvalho Chehab 33659a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 33669a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 493 + i); 33679a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; 33689a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); 33699a0bf528SMauro Carvalho Chehab 33709a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 499 + i); 33719a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].interleaving = val & 0x3; 33729a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving); 33739a0bf528SMauro Carvalho Chehab 33749a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 481 + i); 33759a0bf528SMauro Carvalho Chehab switch (val & 0x7) { 33769a0bf528SMauro Carvalho Chehab case 1: 33779a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_1_2; 33789a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i); 33799a0bf528SMauro Carvalho Chehab break; 33809a0bf528SMauro Carvalho Chehab case 2: 33819a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_2_3; 33829a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i); 33839a0bf528SMauro Carvalho Chehab break; 33849a0bf528SMauro Carvalho Chehab case 3: 33859a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_3_4; 33869a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i); 33879a0bf528SMauro Carvalho Chehab break; 33889a0bf528SMauro Carvalho Chehab case 5: 33899a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_5_6; 33909a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i); 33919a0bf528SMauro Carvalho Chehab break; 33929a0bf528SMauro Carvalho Chehab default: 33939a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].fec = FEC_7_8; 33949a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i); 33959a0bf528SMauro Carvalho Chehab break; 33969a0bf528SMauro Carvalho Chehab } 33979a0bf528SMauro Carvalho Chehab 33989a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 487 + i); 33999a0bf528SMauro Carvalho Chehab switch (val & 0x3) { 34009a0bf528SMauro Carvalho Chehab case 0: 34019a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d DQPSK ", i); 34029a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = DQPSK; 34039a0bf528SMauro Carvalho Chehab break; 34049a0bf528SMauro Carvalho Chehab case 1: 34059a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = QPSK; 34069a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d QPSK ", i); 34079a0bf528SMauro Carvalho Chehab break; 34089a0bf528SMauro Carvalho Chehab case 2: 34099a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = QAM_16; 34109a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d QAM16 ", i); 34119a0bf528SMauro Carvalho Chehab break; 34129a0bf528SMauro Carvalho Chehab case 3: 34139a0bf528SMauro Carvalho Chehab default: 34149a0bf528SMauro Carvalho Chehab dprintk("dib8000_get_frontend : Layer %d QAM64 ", i); 34159a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.layer[i].modulation = QAM_64; 34169a0bf528SMauro Carvalho Chehab break; 34179a0bf528SMauro Carvalho Chehab } 34189a0bf528SMauro Carvalho Chehab } 34199a0bf528SMauro Carvalho Chehab 34209a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 34219a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 34229a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode; 34239a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; 34249a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; 34259a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; 34269a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception; 34279a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) { 34289a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count; 34299a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving; 34309a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec; 34319a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation; 34329a0bf528SMauro Carvalho Chehab } 34339a0bf528SMauro Carvalho Chehab } 34349a0bf528SMauro Carvalho Chehab return 0; 34359a0bf528SMauro Carvalho Chehab } 34369a0bf528SMauro Carvalho Chehab 34379a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe) 34389a0bf528SMauro Carvalho Chehab { 34399a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 3440c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; 34414d8d5d92SGeert Uytterhoeven int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER; 3442173a64cbSPatrick Boettcher u8 exit_condition, index_frontend; 3443173a64cbSPatrick Boettcher u32 delay, callback_time; 34449a0bf528SMauro Carvalho Chehab 3445c82056d0SMauro Carvalho Chehab if (c->frequency == 0) { 34469a0bf528SMauro Carvalho Chehab dprintk("dib8000: must at least specify frequency "); 34479a0bf528SMauro Carvalho Chehab return 0; 34489a0bf528SMauro Carvalho Chehab } 34499a0bf528SMauro Carvalho Chehab 3450c82056d0SMauro Carvalho Chehab if (c->bandwidth_hz == 0) { 34519a0bf528SMauro Carvalho Chehab dprintk("dib8000: no bandwidth specified, set to default "); 3452c82056d0SMauro Carvalho Chehab c->bandwidth_hz = 6000000; 34539a0bf528SMauro Carvalho Chehab } 34549a0bf528SMauro Carvalho Chehab 34559a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 34569a0bf528SMauro Carvalho Chehab /* synchronization of the cache */ 34579a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; 34589a0bf528SMauro Carvalho Chehab memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); 34599a0bf528SMauro Carvalho Chehab 3460173a64cbSPatrick Boettcher /* set output mode and diversity input */ 3461173a64cbSPatrick Boettcher if (state->revision != 0x8090) { 3462173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend], 1); 3463173a64cbSPatrick Boettcher if (index_frontend != 0) 34649a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[index_frontend], 3465173a64cbSPatrick Boettcher OUTMODE_DIVERSITY); 34669a0bf528SMauro Carvalho Chehab else 3467173a64cbSPatrick Boettcher dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); 3468173a64cbSPatrick Boettcher } else { 3469173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend], 1); 3470173a64cbSPatrick Boettcher if (index_frontend != 0) 34719a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[index_frontend], 3472173a64cbSPatrick Boettcher OUTMODE_DIVERSITY); 3473173a64cbSPatrick Boettcher else 3474173a64cbSPatrick Boettcher dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); 3475173a64cbSPatrick Boettcher } 3476173a64cbSPatrick Boettcher 3477173a64cbSPatrick Boettcher /* tune the tuner */ 34789a0bf528SMauro Carvalho Chehab if (state->fe[index_frontend]->ops.tuner_ops.set_params) 34799a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]); 34809a0bf528SMauro Carvalho Chehab 34819a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); 34829a0bf528SMauro Carvalho Chehab } 34839a0bf528SMauro Carvalho Chehab 3484173a64cbSPatrick Boettcher /* turn off the diversity of the last chip */ 3485173a64cbSPatrick Boettcher if (state->revision != 0x8090) 3486173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend - 1], 0); 3487173a64cbSPatrick Boettcher else 3488173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0); 3489173a64cbSPatrick Boettcher 34909a0bf528SMauro Carvalho Chehab /* start up the AGC */ 34919a0bf528SMauro Carvalho Chehab do { 34929a0bf528SMauro Carvalho Chehab time = dib8000_agc_startup(state->fe[0]); 34939a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 34949a0bf528SMauro Carvalho Chehab time_slave = dib8000_agc_startup(state->fe[index_frontend]); 34959a0bf528SMauro Carvalho Chehab if (time == FE_CALLBACK_TIME_NEVER) 34969a0bf528SMauro Carvalho Chehab time = time_slave; 34979a0bf528SMauro Carvalho Chehab else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time)) 34989a0bf528SMauro Carvalho Chehab time = time_slave; 34999a0bf528SMauro Carvalho Chehab } 35009a0bf528SMauro Carvalho Chehab if (time != FE_CALLBACK_TIME_NEVER) 35019a0bf528SMauro Carvalho Chehab msleep(time / 10); 35029a0bf528SMauro Carvalho Chehab else 35039a0bf528SMauro Carvalho Chehab break; 35049a0bf528SMauro Carvalho Chehab exit_condition = 1; 35059a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 35069a0bf528SMauro Carvalho Chehab if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { 35079a0bf528SMauro Carvalho Chehab exit_condition = 0; 35089a0bf528SMauro Carvalho Chehab break; 35099a0bf528SMauro Carvalho Chehab } 35109a0bf528SMauro Carvalho Chehab } 35119a0bf528SMauro Carvalho Chehab } while (exit_condition == 0); 35129a0bf528SMauro Carvalho Chehab 35139a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 35149a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); 35159a0bf528SMauro Carvalho Chehab 3516173a64cbSPatrick Boettcher active = 1; 35179a0bf528SMauro Carvalho Chehab do { 3518173a64cbSPatrick Boettcher callback_time = FE_CALLBACK_TIME_NEVER; 35199a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 3520173a64cbSPatrick Boettcher delay = dib8000_tune(state->fe[index_frontend]); 3521173a64cbSPatrick Boettcher if (delay != FE_CALLBACK_TIME_NEVER) 3522173a64cbSPatrick Boettcher delay += systime(); 3523173a64cbSPatrick Boettcher 3524173a64cbSPatrick Boettcher /* we are in autosearch */ 3525173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* searching */ 3526173a64cbSPatrick Boettcher if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) { 3527173a64cbSPatrick Boettcher dprintk("autosearch succeeded on fe%i", index_frontend); 3528173a64cbSPatrick Boettcher dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */ 3529173a64cbSPatrick Boettcher state->channel_parameters_set = 1; 3530173a64cbSPatrick Boettcher 3531173a64cbSPatrick Boettcher for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) { 3532173a64cbSPatrick Boettcher if (l != index_frontend) { /* and for all frontend except the successful one */ 3533173a64cbSPatrick Boettcher dib8000_tune_restart_from_demod(state->fe[l]); 3534173a64cbSPatrick Boettcher 3535173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; 3536173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; 3537173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; 3538173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; 3539173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; 3540173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) { 3541173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; 3542173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; 3543173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; 3544173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; 3545173a64cbSPatrick Boettcher } 3546173a64cbSPatrick Boettcher 35479a0bf528SMauro Carvalho Chehab } 35489a0bf528SMauro Carvalho Chehab } 35499a0bf528SMauro Carvalho Chehab } 3550173a64cbSPatrick Boettcher } 3551173a64cbSPatrick Boettcher if (delay < callback_time) 3552173a64cbSPatrick Boettcher callback_time = delay; 3553173a64cbSPatrick Boettcher } 3554173a64cbSPatrick Boettcher /* tuning is done when the master frontend is done (failed or success) */ 3555173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED || 3556173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED || 3557173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) { 3558173a64cbSPatrick Boettcher active = 0; 3559173a64cbSPatrick Boettcher /* we need to wait for all frontends to be finished */ 3560173a64cbSPatrick Boettcher for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 3561173a64cbSPatrick Boettcher if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP) 3562173a64cbSPatrick Boettcher active = 1; 3563173a64cbSPatrick Boettcher } 3564173a64cbSPatrick Boettcher if (active == 0) 3565173a64cbSPatrick Boettcher dprintk("tuning done with status %d", dib8000_get_status(state->fe[0])); 35669a0bf528SMauro Carvalho Chehab } 35679a0bf528SMauro Carvalho Chehab 3568173a64cbSPatrick Boettcher if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) { 3569173a64cbSPatrick Boettcher dprintk("strange callback time something went wrong"); 3570173a64cbSPatrick Boettcher active = 0; 35719a0bf528SMauro Carvalho Chehab } 35729a0bf528SMauro Carvalho Chehab 3573173a64cbSPatrick Boettcher while ((active == 1) && (systime() < callback_time)) 3574173a64cbSPatrick Boettcher msleep(100); 3575173a64cbSPatrick Boettcher } while (active); 35769a0bf528SMauro Carvalho Chehab 3577173a64cbSPatrick Boettcher /* set output mode */ 3578173a64cbSPatrick Boettcher if (state->revision != 0x8090) 35799a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); 3580173a64cbSPatrick Boettcher else { 35819a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode); 35829a0bf528SMauro Carvalho Chehab if (state->cfg.enMpegOutput == 0) { 35839a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, MPEG_ON_DIBTX); 35849a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); 35859a0bf528SMauro Carvalho Chehab } 35869a0bf528SMauro Carvalho Chehab } 35879a0bf528SMauro Carvalho Chehab 35884d8d5d92SGeert Uytterhoeven return 0; 35899a0bf528SMauro Carvalho Chehab } 35909a0bf528SMauro Carvalho Chehab 35919a0bf528SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) 35929a0bf528SMauro Carvalho Chehab { 35939a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 35949a0bf528SMauro Carvalho Chehab u16 lock_slave = 0, lock; 35959a0bf528SMauro Carvalho Chehab u8 index_frontend; 35969a0bf528SMauro Carvalho Chehab 3597173a64cbSPatrick Boettcher lock = dib8000_read_lock(fe); 35989a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 35999a0bf528SMauro Carvalho Chehab lock_slave |= dib8000_read_lock(state->fe[index_frontend]); 36009a0bf528SMauro Carvalho Chehab 36019a0bf528SMauro Carvalho Chehab *stat = 0; 36029a0bf528SMauro Carvalho Chehab 36039a0bf528SMauro Carvalho Chehab if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1)) 36049a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SIGNAL; 36059a0bf528SMauro Carvalho Chehab 36069a0bf528SMauro Carvalho Chehab if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */ 36079a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_CARRIER; 36089a0bf528SMauro Carvalho Chehab 36099a0bf528SMauro Carvalho Chehab if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */ 36109a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SYNC; 36119a0bf528SMauro Carvalho Chehab 36129a0bf528SMauro Carvalho Chehab if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */ 36139a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_LOCK; 36149a0bf528SMauro Carvalho Chehab 36159a0bf528SMauro Carvalho Chehab if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) { 36169a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ 36179a0bf528SMauro Carvalho Chehab if (lock & 0x01) 36189a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 36199a0bf528SMauro Carvalho Chehab 36209a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ 36219a0bf528SMauro Carvalho Chehab if (lock & 0x01) 36229a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 36239a0bf528SMauro Carvalho Chehab 36249a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ 36259a0bf528SMauro Carvalho Chehab if (lock & 0x01) 36269a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 36279a0bf528SMauro Carvalho Chehab } 36289a0bf528SMauro Carvalho Chehab 36299a0bf528SMauro Carvalho Chehab return 0; 36309a0bf528SMauro Carvalho Chehab } 36319a0bf528SMauro Carvalho Chehab 36329a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) 36339a0bf528SMauro Carvalho Chehab { 36349a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 36359a0bf528SMauro Carvalho Chehab 36369a0bf528SMauro Carvalho Chehab /* 13 segments */ 36379a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 36389a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 562) << 16) | 36399a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 563); 36409a0bf528SMauro Carvalho Chehab else 36419a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 560) << 16) | 36429a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 561); 36439a0bf528SMauro Carvalho Chehab return 0; 36449a0bf528SMauro Carvalho Chehab } 36459a0bf528SMauro Carvalho Chehab 36469a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) 36479a0bf528SMauro Carvalho Chehab { 36489a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 36499a0bf528SMauro Carvalho Chehab 36509a0bf528SMauro Carvalho Chehab /* packet error on 13 seg */ 36519a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) 36529a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 567); 36539a0bf528SMauro Carvalho Chehab else 36549a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 565); 36559a0bf528SMauro Carvalho Chehab return 0; 36569a0bf528SMauro Carvalho Chehab } 36579a0bf528SMauro Carvalho Chehab 36589a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 36599a0bf528SMauro Carvalho Chehab { 36609a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 36619a0bf528SMauro Carvalho Chehab u8 index_frontend; 36629a0bf528SMauro Carvalho Chehab u16 val; 36639a0bf528SMauro Carvalho Chehab 36649a0bf528SMauro Carvalho Chehab *strength = 0; 36659a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 36669a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); 36679a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 36689a0bf528SMauro Carvalho Chehab *strength = 65535; 36699a0bf528SMauro Carvalho Chehab else 36709a0bf528SMauro Carvalho Chehab *strength += val; 36719a0bf528SMauro Carvalho Chehab } 36729a0bf528SMauro Carvalho Chehab 36739a0bf528SMauro Carvalho Chehab val = 65535 - dib8000_read_word(state, 390); 36749a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 36759a0bf528SMauro Carvalho Chehab *strength = 65535; 36769a0bf528SMauro Carvalho Chehab else 36779a0bf528SMauro Carvalho Chehab *strength += val; 36789a0bf528SMauro Carvalho Chehab return 0; 36799a0bf528SMauro Carvalho Chehab } 36809a0bf528SMauro Carvalho Chehab 36819a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe) 36829a0bf528SMauro Carvalho Chehab { 36839a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 36849a0bf528SMauro Carvalho Chehab u32 n, s, exp; 36859a0bf528SMauro Carvalho Chehab u16 val; 36869a0bf528SMauro Carvalho Chehab 36879a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 36889a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 542); 36899a0bf528SMauro Carvalho Chehab else 36909a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 544); 36919a0bf528SMauro Carvalho Chehab n = (val >> 6) & 0xff; 36929a0bf528SMauro Carvalho Chehab exp = (val & 0x3f); 36939a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 36949a0bf528SMauro Carvalho Chehab exp -= 0x40; 36959a0bf528SMauro Carvalho Chehab n <<= exp+16; 36969a0bf528SMauro Carvalho Chehab 36979a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) 36989a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 543); 36999a0bf528SMauro Carvalho Chehab else 37009a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 545); 37019a0bf528SMauro Carvalho Chehab s = (val >> 6) & 0xff; 37029a0bf528SMauro Carvalho Chehab exp = (val & 0x3f); 37039a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 37049a0bf528SMauro Carvalho Chehab exp -= 0x40; 37059a0bf528SMauro Carvalho Chehab s <<= exp+16; 37069a0bf528SMauro Carvalho Chehab 37079a0bf528SMauro Carvalho Chehab if (n > 0) { 37089a0bf528SMauro Carvalho Chehab u32 t = (s/n) << 16; 37099a0bf528SMauro Carvalho Chehab return t + ((s << 16) - n*t) / n; 37109a0bf528SMauro Carvalho Chehab } 37119a0bf528SMauro Carvalho Chehab return 0xffffffff; 37129a0bf528SMauro Carvalho Chehab } 37139a0bf528SMauro Carvalho Chehab 37149a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) 37159a0bf528SMauro Carvalho Chehab { 37169a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37179a0bf528SMauro Carvalho Chehab u8 index_frontend; 37189a0bf528SMauro Carvalho Chehab u32 snr_master; 37199a0bf528SMauro Carvalho Chehab 37209a0bf528SMauro Carvalho Chehab snr_master = dib8000_get_snr(fe); 37219a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 37229a0bf528SMauro Carvalho Chehab snr_master += dib8000_get_snr(state->fe[index_frontend]); 37239a0bf528SMauro Carvalho Chehab 37249a0bf528SMauro Carvalho Chehab if ((snr_master >> 16) != 0) { 37259a0bf528SMauro Carvalho Chehab snr_master = 10*intlog10(snr_master>>16); 37269a0bf528SMauro Carvalho Chehab *snr = snr_master / ((1 << 24) / 10); 37279a0bf528SMauro Carvalho Chehab } 37289a0bf528SMauro Carvalho Chehab else 37299a0bf528SMauro Carvalho Chehab *snr = 0; 37309a0bf528SMauro Carvalho Chehab 37319a0bf528SMauro Carvalho Chehab return 0; 37329a0bf528SMauro Carvalho Chehab } 37339a0bf528SMauro Carvalho Chehab 37349a0bf528SMauro Carvalho Chehab int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) 37359a0bf528SMauro Carvalho Chehab { 37369a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37379a0bf528SMauro Carvalho Chehab u8 index_frontend = 1; 37389a0bf528SMauro Carvalho Chehab 37399a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 37409a0bf528SMauro Carvalho Chehab index_frontend++; 37419a0bf528SMauro Carvalho Chehab if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { 37429a0bf528SMauro Carvalho Chehab dprintk("set slave fe %p to index %i", fe_slave, index_frontend); 37439a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = fe_slave; 37449a0bf528SMauro Carvalho Chehab return 0; 37459a0bf528SMauro Carvalho Chehab } 37469a0bf528SMauro Carvalho Chehab 37479a0bf528SMauro Carvalho Chehab dprintk("too many slave frontend"); 37489a0bf528SMauro Carvalho Chehab return -ENOMEM; 37499a0bf528SMauro Carvalho Chehab } 37509a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_slave_frontend); 37519a0bf528SMauro Carvalho Chehab 37529a0bf528SMauro Carvalho Chehab int dib8000_remove_slave_frontend(struct dvb_frontend *fe) 37539a0bf528SMauro Carvalho Chehab { 37549a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37559a0bf528SMauro Carvalho Chehab u8 index_frontend = 1; 37569a0bf528SMauro Carvalho Chehab 37579a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 37589a0bf528SMauro Carvalho Chehab index_frontend++; 37599a0bf528SMauro Carvalho Chehab if (index_frontend != 1) { 37609a0bf528SMauro Carvalho Chehab dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); 37619a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = NULL; 37629a0bf528SMauro Carvalho Chehab return 0; 37639a0bf528SMauro Carvalho Chehab } 37649a0bf528SMauro Carvalho Chehab 37659a0bf528SMauro Carvalho Chehab dprintk("no frontend to be removed"); 37669a0bf528SMauro Carvalho Chehab return -ENODEV; 37679a0bf528SMauro Carvalho Chehab } 37689a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_remove_slave_frontend); 37699a0bf528SMauro Carvalho Chehab 37709a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) 37719a0bf528SMauro Carvalho Chehab { 37729a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv; 37739a0bf528SMauro Carvalho Chehab 37749a0bf528SMauro Carvalho Chehab if (slave_index >= MAX_NUMBER_OF_FRONTENDS) 37759a0bf528SMauro Carvalho Chehab return NULL; 37769a0bf528SMauro Carvalho Chehab return state->fe[slave_index]; 37779a0bf528SMauro Carvalho Chehab } 37789a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_slave_frontend); 37799a0bf528SMauro Carvalho Chehab 37809a0bf528SMauro Carvalho Chehab 37819a0bf528SMauro Carvalho Chehab int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, 37829a0bf528SMauro Carvalho Chehab u8 default_addr, u8 first_addr, u8 is_dib8096p) 37839a0bf528SMauro Carvalho Chehab { 37849a0bf528SMauro Carvalho Chehab int k = 0, ret = 0; 37859a0bf528SMauro Carvalho Chehab u8 new_addr = 0; 37869a0bf528SMauro Carvalho Chehab struct i2c_device client = {.adap = host }; 37879a0bf528SMauro Carvalho Chehab 37889a0bf528SMauro Carvalho Chehab client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); 37899a0bf528SMauro Carvalho Chehab if (!client.i2c_write_buffer) { 37909a0bf528SMauro Carvalho Chehab dprintk("%s: not enough memory", __func__); 37919a0bf528SMauro Carvalho Chehab return -ENOMEM; 37929a0bf528SMauro Carvalho Chehab } 37939a0bf528SMauro Carvalho Chehab client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); 37949a0bf528SMauro Carvalho Chehab if (!client.i2c_read_buffer) { 37959a0bf528SMauro Carvalho Chehab dprintk("%s: not enough memory", __func__); 37969a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 37979a0bf528SMauro Carvalho Chehab goto error_memory_read; 37989a0bf528SMauro Carvalho Chehab } 37999a0bf528SMauro Carvalho Chehab client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); 38009a0bf528SMauro Carvalho Chehab if (!client.i2c_buffer_lock) { 38019a0bf528SMauro Carvalho Chehab dprintk("%s: not enough memory", __func__); 38029a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 38039a0bf528SMauro Carvalho Chehab goto error_memory_lock; 38049a0bf528SMauro Carvalho Chehab } 38059a0bf528SMauro Carvalho Chehab mutex_init(client.i2c_buffer_lock); 38069a0bf528SMauro Carvalho Chehab 38079a0bf528SMauro Carvalho Chehab for (k = no_of_demods - 1; k >= 0; k--) { 38089a0bf528SMauro Carvalho Chehab /* designated i2c address */ 38099a0bf528SMauro Carvalho Chehab new_addr = first_addr + (k << 1); 38109a0bf528SMauro Carvalho Chehab 38119a0bf528SMauro Carvalho Chehab client.addr = new_addr; 38129a0bf528SMauro Carvalho Chehab if (!is_dib8096p) 38139a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ 38149a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) { 38159a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */ 38169a0bf528SMauro Carvalho Chehab if (!is_dib8096p) 38179a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003); 38189a0bf528SMauro Carvalho Chehab client.addr = default_addr; 38199a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) { 38209a0bf528SMauro Carvalho Chehab dprintk("#%d: not identified", k); 38219a0bf528SMauro Carvalho Chehab ret = -EINVAL; 38229a0bf528SMauro Carvalho Chehab goto error; 38239a0bf528SMauro Carvalho Chehab } 38249a0bf528SMauro Carvalho Chehab } 38259a0bf528SMauro Carvalho Chehab 38269a0bf528SMauro Carvalho Chehab /* start diversity to pull_down div_str - just for i2c-enumeration */ 38279a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6)); 38289a0bf528SMauro Carvalho Chehab 38299a0bf528SMauro Carvalho Chehab /* set new i2c address and force divstart */ 38309a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2); 38319a0bf528SMauro Carvalho Chehab client.addr = new_addr; 38329a0bf528SMauro Carvalho Chehab dib8000_identify(&client); 38339a0bf528SMauro Carvalho Chehab 38349a0bf528SMauro Carvalho Chehab dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); 38359a0bf528SMauro Carvalho Chehab } 38369a0bf528SMauro Carvalho Chehab 38379a0bf528SMauro Carvalho Chehab for (k = 0; k < no_of_demods; k++) { 38389a0bf528SMauro Carvalho Chehab new_addr = first_addr | (k << 1); 38399a0bf528SMauro Carvalho Chehab client.addr = new_addr; 38409a0bf528SMauro Carvalho Chehab 38419a0bf528SMauro Carvalho Chehab // unforce divstr 38429a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, new_addr << 2); 38439a0bf528SMauro Carvalho Chehab 38449a0bf528SMauro Carvalho Chehab /* deactivate div - it was just for i2c-enumeration */ 38459a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, 0); 38469a0bf528SMauro Carvalho Chehab } 38479a0bf528SMauro Carvalho Chehab 38489a0bf528SMauro Carvalho Chehab error: 38499a0bf528SMauro Carvalho Chehab kfree(client.i2c_buffer_lock); 38509a0bf528SMauro Carvalho Chehab error_memory_lock: 38519a0bf528SMauro Carvalho Chehab kfree(client.i2c_read_buffer); 38529a0bf528SMauro Carvalho Chehab error_memory_read: 38539a0bf528SMauro Carvalho Chehab kfree(client.i2c_write_buffer); 38549a0bf528SMauro Carvalho Chehab 38559a0bf528SMauro Carvalho Chehab return ret; 38569a0bf528SMauro Carvalho Chehab } 38579a0bf528SMauro Carvalho Chehab 38589a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_i2c_enumeration); 38599a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) 38609a0bf528SMauro Carvalho Chehab { 38619a0bf528SMauro Carvalho Chehab tune->min_delay_ms = 1000; 38629a0bf528SMauro Carvalho Chehab tune->step_size = 0; 38639a0bf528SMauro Carvalho Chehab tune->max_drift = 0; 38649a0bf528SMauro Carvalho Chehab return 0; 38659a0bf528SMauro Carvalho Chehab } 38669a0bf528SMauro Carvalho Chehab 38679a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe) 38689a0bf528SMauro Carvalho Chehab { 38699a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 38709a0bf528SMauro Carvalho Chehab u8 index_frontend; 38719a0bf528SMauro Carvalho Chehab 38729a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) 38739a0bf528SMauro Carvalho Chehab dvb_frontend_detach(st->fe[index_frontend]); 38749a0bf528SMauro Carvalho Chehab 38759a0bf528SMauro Carvalho Chehab dibx000_exit_i2c_master(&st->i2c_master); 38769a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->dib8096p_tuner_adap); 38779a0bf528SMauro Carvalho Chehab kfree(st->fe[0]); 38789a0bf528SMauro Carvalho Chehab kfree(st); 38799a0bf528SMauro Carvalho Chehab } 38809a0bf528SMauro Carvalho Chehab 38819a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) 38829a0bf528SMauro Carvalho Chehab { 38839a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 38849a0bf528SMauro Carvalho Chehab return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); 38859a0bf528SMauro Carvalho Chehab } 38869a0bf528SMauro Carvalho Chehab 38879a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_i2c_master); 38889a0bf528SMauro Carvalho Chehab 38899a0bf528SMauro Carvalho Chehab int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) 38909a0bf528SMauro Carvalho Chehab { 38919a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 38929a0bf528SMauro Carvalho Chehab u16 val = dib8000_read_word(st, 299) & 0xffef; 38939a0bf528SMauro Carvalho Chehab val |= (onoff & 0x1) << 4; 38949a0bf528SMauro Carvalho Chehab 38959a0bf528SMauro Carvalho Chehab dprintk("pid filter enabled %d", onoff); 38969a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 299, val); 38979a0bf528SMauro Carvalho Chehab } 38989a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter_ctrl); 38999a0bf528SMauro Carvalho Chehab 39009a0bf528SMauro Carvalho Chehab int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) 39019a0bf528SMauro Carvalho Chehab { 39029a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv; 39039a0bf528SMauro Carvalho Chehab dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); 39049a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); 39059a0bf528SMauro Carvalho Chehab } 39069a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter); 39079a0bf528SMauro Carvalho Chehab 39089a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = { 39099a0bf528SMauro Carvalho Chehab .delsys = { SYS_ISDBT }, 39109a0bf528SMauro Carvalho Chehab .info = { 39119a0bf528SMauro Carvalho Chehab .name = "DiBcom 8000 ISDB-T", 39129a0bf528SMauro Carvalho Chehab .frequency_min = 44250000, 39139a0bf528SMauro Carvalho Chehab .frequency_max = 867250000, 39149a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 39159a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | 39169a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 39179a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 39189a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 39199a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, 39209a0bf528SMauro Carvalho Chehab }, 39219a0bf528SMauro Carvalho Chehab 39229a0bf528SMauro Carvalho Chehab .release = dib8000_release, 39239a0bf528SMauro Carvalho Chehab 39249a0bf528SMauro Carvalho Chehab .init = dib8000_wakeup, 39259a0bf528SMauro Carvalho Chehab .sleep = dib8000_sleep, 39269a0bf528SMauro Carvalho Chehab 39279a0bf528SMauro Carvalho Chehab .set_frontend = dib8000_set_frontend, 39289a0bf528SMauro Carvalho Chehab .get_tune_settings = dib8000_fe_get_tune_settings, 39299a0bf528SMauro Carvalho Chehab .get_frontend = dib8000_get_frontend, 39309a0bf528SMauro Carvalho Chehab 39319a0bf528SMauro Carvalho Chehab .read_status = dib8000_read_status, 39329a0bf528SMauro Carvalho Chehab .read_ber = dib8000_read_ber, 39339a0bf528SMauro Carvalho Chehab .read_signal_strength = dib8000_read_signal_strength, 39349a0bf528SMauro Carvalho Chehab .read_snr = dib8000_read_snr, 39359a0bf528SMauro Carvalho Chehab .read_ucblocks = dib8000_read_unc_blocks, 39369a0bf528SMauro Carvalho Chehab }; 39379a0bf528SMauro Carvalho Chehab 39389a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) 39399a0bf528SMauro Carvalho Chehab { 39409a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe; 39419a0bf528SMauro Carvalho Chehab struct dib8000_state *state; 39429a0bf528SMauro Carvalho Chehab 39439a0bf528SMauro Carvalho Chehab dprintk("dib8000_attach"); 39449a0bf528SMauro Carvalho Chehab 39459a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); 39469a0bf528SMauro Carvalho Chehab if (state == NULL) 39479a0bf528SMauro Carvalho Chehab return NULL; 39489a0bf528SMauro Carvalho Chehab fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); 39499a0bf528SMauro Carvalho Chehab if (fe == NULL) 39509a0bf528SMauro Carvalho Chehab goto error; 39519a0bf528SMauro Carvalho Chehab 39529a0bf528SMauro Carvalho Chehab memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); 39539a0bf528SMauro Carvalho Chehab state->i2c.adap = i2c_adap; 39549a0bf528SMauro Carvalho Chehab state->i2c.addr = i2c_addr; 39559a0bf528SMauro Carvalho Chehab state->i2c.i2c_write_buffer = state->i2c_write_buffer; 39569a0bf528SMauro Carvalho Chehab state->i2c.i2c_read_buffer = state->i2c_read_buffer; 39579a0bf528SMauro Carvalho Chehab mutex_init(&state->i2c_buffer_lock); 39589a0bf528SMauro Carvalho Chehab state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock; 39599a0bf528SMauro Carvalho Chehab state->gpio_val = cfg->gpio_val; 39609a0bf528SMauro Carvalho Chehab state->gpio_dir = cfg->gpio_dir; 39619a0bf528SMauro Carvalho Chehab 39629a0bf528SMauro Carvalho Chehab /* Ensure the output mode remains at the previous default if it's 39639a0bf528SMauro Carvalho Chehab * not specifically set by the caller. 39649a0bf528SMauro Carvalho Chehab */ 39659a0bf528SMauro Carvalho Chehab if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) 39669a0bf528SMauro Carvalho Chehab state->cfg.output_mode = OUTMODE_MPEG2_FIFO; 39679a0bf528SMauro Carvalho Chehab 39689a0bf528SMauro Carvalho Chehab state->fe[0] = fe; 39699a0bf528SMauro Carvalho Chehab fe->demodulator_priv = state; 39709a0bf528SMauro Carvalho Chehab memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); 39719a0bf528SMauro Carvalho Chehab 39729a0bf528SMauro Carvalho Chehab state->timf_default = cfg->pll->timf; 39739a0bf528SMauro Carvalho Chehab 39749a0bf528SMauro Carvalho Chehab if (dib8000_identify(&state->i2c) == 0) 39759a0bf528SMauro Carvalho Chehab goto error; 39769a0bf528SMauro Carvalho Chehab 39779a0bf528SMauro Carvalho Chehab dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); 39789a0bf528SMauro Carvalho Chehab 39799a0bf528SMauro Carvalho Chehab /* init 8096p tuner adapter */ 39809a0bf528SMauro Carvalho Chehab strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", 39819a0bf528SMauro Carvalho Chehab sizeof(state->dib8096p_tuner_adap.name)); 39829a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo; 39839a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo_data = NULL; 39849a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent; 39859a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&state->dib8096p_tuner_adap, state); 39869a0bf528SMauro Carvalho Chehab i2c_add_adapter(&state->dib8096p_tuner_adap); 39879a0bf528SMauro Carvalho Chehab 39889a0bf528SMauro Carvalho Chehab dib8000_reset(fe); 39899a0bf528SMauro Carvalho Chehab 39909a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ 3991173a64cbSPatrick Boettcher state->current_demod_bw = 6000; 39929a0bf528SMauro Carvalho Chehab 39939a0bf528SMauro Carvalho Chehab return fe; 39949a0bf528SMauro Carvalho Chehab 39959a0bf528SMauro Carvalho Chehab error: 39969a0bf528SMauro Carvalho Chehab kfree(state); 39979a0bf528SMauro Carvalho Chehab return NULL; 39989a0bf528SMauro Carvalho Chehab } 39999a0bf528SMauro Carvalho Chehab 40009a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_attach); 40019a0bf528SMauro Carvalho Chehab 40029a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>"); 40039a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator"); 40049a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 4005