19a0bf528SMauro Carvalho Chehab /* 29a0bf528SMauro Carvalho Chehab * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). 39a0bf528SMauro Carvalho Chehab * 49a0bf528SMauro Carvalho Chehab * Copyright (C) 2005-7 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 #include "dvb_frontend.h" 179a0bf528SMauro Carvalho Chehab 189a0bf528SMauro Carvalho Chehab #include "dib7000p.h" 199a0bf528SMauro Carvalho Chehab 209a0bf528SMauro Carvalho Chehab static int debug; 219a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 229a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 239a0bf528SMauro Carvalho Chehab 249a0bf528SMauro Carvalho Chehab static int buggy_sfn_workaround; 259a0bf528SMauro Carvalho Chehab module_param(buggy_sfn_workaround, int, 0644); 269a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); 279a0bf528SMauro Carvalho Chehab 289a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) 299a0bf528SMauro Carvalho Chehab 309a0bf528SMauro Carvalho Chehab struct i2c_device { 319a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c_adap; 329a0bf528SMauro Carvalho Chehab u8 i2c_addr; 339a0bf528SMauro Carvalho Chehab }; 349a0bf528SMauro Carvalho Chehab 359a0bf528SMauro Carvalho Chehab struct dib7000p_state { 369a0bf528SMauro Carvalho Chehab struct dvb_frontend demod; 379a0bf528SMauro Carvalho Chehab struct dib7000p_config cfg; 389a0bf528SMauro Carvalho Chehab 399a0bf528SMauro Carvalho Chehab u8 i2c_addr; 409a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c_adap; 419a0bf528SMauro Carvalho Chehab 429a0bf528SMauro Carvalho Chehab struct dibx000_i2c_master i2c_master; 439a0bf528SMauro Carvalho Chehab 449a0bf528SMauro Carvalho Chehab u16 wbd_ref; 459a0bf528SMauro Carvalho Chehab 469a0bf528SMauro Carvalho Chehab u8 current_band; 479a0bf528SMauro Carvalho Chehab u32 current_bandwidth; 489a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *current_agc; 499a0bf528SMauro Carvalho Chehab u32 timf; 509a0bf528SMauro Carvalho Chehab 519a0bf528SMauro Carvalho Chehab u8 div_force_off:1; 529a0bf528SMauro Carvalho Chehab u8 div_state:1; 539a0bf528SMauro Carvalho Chehab u16 div_sync_wait; 549a0bf528SMauro Carvalho Chehab 559a0bf528SMauro Carvalho Chehab u8 agc_state; 569a0bf528SMauro Carvalho Chehab 579a0bf528SMauro Carvalho Chehab u16 gpio_dir; 589a0bf528SMauro Carvalho Chehab u16 gpio_val; 599a0bf528SMauro Carvalho Chehab 609a0bf528SMauro Carvalho Chehab u8 sfn_workaround_active:1; 619a0bf528SMauro Carvalho Chehab 629a0bf528SMauro Carvalho Chehab #define SOC7090 0x7090 639a0bf528SMauro Carvalho Chehab u16 version; 649a0bf528SMauro Carvalho Chehab 659a0bf528SMauro Carvalho Chehab u16 tuner_enable; 669a0bf528SMauro Carvalho Chehab struct i2c_adapter dib7090_tuner_adap; 679a0bf528SMauro Carvalho Chehab 689a0bf528SMauro Carvalho Chehab /* for the I2C transfer */ 699a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2]; 709a0bf528SMauro Carvalho Chehab u8 i2c_write_buffer[4]; 719a0bf528SMauro Carvalho Chehab u8 i2c_read_buffer[2]; 729a0bf528SMauro Carvalho Chehab struct mutex i2c_buffer_lock; 739a0bf528SMauro Carvalho Chehab 749a0bf528SMauro Carvalho Chehab u8 input_mode_mpeg; 759a0bf528SMauro Carvalho Chehab }; 769a0bf528SMauro Carvalho Chehab 779a0bf528SMauro Carvalho Chehab enum dib7000p_power_mode { 789a0bf528SMauro Carvalho Chehab DIB7000P_POWER_ALL = 0, 799a0bf528SMauro Carvalho Chehab DIB7000P_POWER_ANALOG_ADC, 809a0bf528SMauro Carvalho Chehab DIB7000P_POWER_INTERFACE_ONLY, 819a0bf528SMauro Carvalho Chehab }; 829a0bf528SMauro Carvalho Chehab 839a0bf528SMauro Carvalho Chehab /* dib7090 specific fonctions */ 849a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode); 859a0bf528SMauro Carvalho Chehab static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); 869a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode); 879a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode); 889a0bf528SMauro Carvalho Chehab 899a0bf528SMauro Carvalho Chehab static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) 909a0bf528SMauro Carvalho Chehab { 919a0bf528SMauro Carvalho Chehab u16 ret; 929a0bf528SMauro Carvalho Chehab 939a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 949a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 959a0bf528SMauro Carvalho Chehab return 0; 969a0bf528SMauro Carvalho Chehab } 979a0bf528SMauro Carvalho Chehab 989a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = reg >> 8; 999a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 1009a0bf528SMauro Carvalho Chehab 1019a0bf528SMauro Carvalho Chehab memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 1029a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c_addr >> 1; 1039a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 1049a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 1059a0bf528SMauro Carvalho Chehab state->msg[0].len = 2; 1069a0bf528SMauro Carvalho Chehab state->msg[1].addr = state->i2c_addr >> 1; 1079a0bf528SMauro Carvalho Chehab state->msg[1].flags = I2C_M_RD; 1089a0bf528SMauro Carvalho Chehab state->msg[1].buf = state->i2c_read_buffer; 1099a0bf528SMauro Carvalho Chehab state->msg[1].len = 2; 1109a0bf528SMauro Carvalho Chehab 1119a0bf528SMauro Carvalho Chehab if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) 1129a0bf528SMauro Carvalho Chehab dprintk("i2c read error on %d", reg); 1139a0bf528SMauro Carvalho Chehab 1149a0bf528SMauro Carvalho Chehab ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 1159a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 1169a0bf528SMauro Carvalho Chehab return ret; 1179a0bf528SMauro Carvalho Chehab } 1189a0bf528SMauro Carvalho Chehab 1199a0bf528SMauro Carvalho Chehab static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) 1209a0bf528SMauro Carvalho Chehab { 1219a0bf528SMauro Carvalho Chehab int ret; 1229a0bf528SMauro Carvalho Chehab 1239a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { 1249a0bf528SMauro Carvalho Chehab dprintk("could not acquire lock"); 1259a0bf528SMauro Carvalho Chehab return -EINVAL; 1269a0bf528SMauro Carvalho Chehab } 1279a0bf528SMauro Carvalho Chehab 1289a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = (reg >> 8) & 0xff; 1299a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 1309a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[2] = (val >> 8) & 0xff; 1319a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[3] = val & 0xff; 1329a0bf528SMauro Carvalho Chehab 1339a0bf528SMauro Carvalho Chehab memset(&state->msg[0], 0, sizeof(struct i2c_msg)); 1349a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c_addr >> 1; 1359a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 1369a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 1379a0bf528SMauro Carvalho Chehab state->msg[0].len = 4; 1389a0bf528SMauro Carvalho Chehab 1399a0bf528SMauro Carvalho Chehab ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? 1409a0bf528SMauro Carvalho Chehab -EREMOTEIO : 0); 1419a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock); 1429a0bf528SMauro Carvalho Chehab return ret; 1439a0bf528SMauro Carvalho Chehab } 1449a0bf528SMauro Carvalho Chehab 1459a0bf528SMauro Carvalho Chehab static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) 1469a0bf528SMauro Carvalho Chehab { 1479a0bf528SMauro Carvalho Chehab u16 l = 0, r, *n; 1489a0bf528SMauro Carvalho Chehab n = buf; 1499a0bf528SMauro Carvalho Chehab l = *n++; 1509a0bf528SMauro Carvalho Chehab while (l) { 1519a0bf528SMauro Carvalho Chehab r = *n++; 1529a0bf528SMauro Carvalho Chehab 1539a0bf528SMauro Carvalho Chehab do { 1549a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, r, *n++); 1559a0bf528SMauro Carvalho Chehab r++; 1569a0bf528SMauro Carvalho Chehab } while (--l); 1579a0bf528SMauro Carvalho Chehab l = *n++; 1589a0bf528SMauro Carvalho Chehab } 1599a0bf528SMauro Carvalho Chehab } 1609a0bf528SMauro Carvalho Chehab 1619a0bf528SMauro Carvalho Chehab static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) 1629a0bf528SMauro Carvalho Chehab { 1639a0bf528SMauro Carvalho Chehab int ret = 0; 1649a0bf528SMauro Carvalho Chehab u16 outreg, fifo_threshold, smo_mode; 1659a0bf528SMauro Carvalho Chehab 1669a0bf528SMauro Carvalho Chehab outreg = 0; 1679a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 1689a0bf528SMauro Carvalho Chehab smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); 1699a0bf528SMauro Carvalho Chehab 1709a0bf528SMauro Carvalho Chehab dprintk("setting output mode for demod %p to %d", &state->demod, mode); 1719a0bf528SMauro Carvalho Chehab 1729a0bf528SMauro Carvalho Chehab switch (mode) { 1739a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 1749a0bf528SMauro Carvalho Chehab outreg = (1 << 10); /* 0x0400 */ 1759a0bf528SMauro Carvalho Chehab break; 1769a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: 1779a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (1 << 6); /* 0x0440 */ 1789a0bf528SMauro Carvalho Chehab break; 1799a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 1809a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */ 1819a0bf528SMauro Carvalho Chehab break; 1829a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 1839a0bf528SMauro Carvalho Chehab if (state->cfg.hostbus_diversity) 1849a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (4 << 6); /* 0x0500 */ 1859a0bf528SMauro Carvalho Chehab else 1869a0bf528SMauro Carvalho Chehab outreg = (1 << 11); 1879a0bf528SMauro Carvalho Chehab break; 1889a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: 1899a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 1909a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 1919a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (5 << 6); 1929a0bf528SMauro Carvalho Chehab break; 1939a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 1949a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (3 << 6); 1959a0bf528SMauro Carvalho Chehab break; 1969a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: 1979a0bf528SMauro Carvalho Chehab outreg = 0; 1989a0bf528SMauro Carvalho Chehab break; 1999a0bf528SMauro Carvalho Chehab default: 2009a0bf528SMauro Carvalho Chehab dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod); 2019a0bf528SMauro Carvalho Chehab break; 2029a0bf528SMauro Carvalho Chehab } 2039a0bf528SMauro Carvalho Chehab 2049a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 2059a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 2069a0bf528SMauro Carvalho Chehab 2079a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 235, smo_mode); 2089a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ 2099a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) 2109a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */ 2119a0bf528SMauro Carvalho Chehab 2129a0bf528SMauro Carvalho Chehab return ret; 2139a0bf528SMauro Carvalho Chehab } 2149a0bf528SMauro Carvalho Chehab 2159a0bf528SMauro Carvalho Chehab static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) 2169a0bf528SMauro Carvalho Chehab { 2179a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 2189a0bf528SMauro Carvalho Chehab 2199a0bf528SMauro Carvalho Chehab if (state->div_force_off) { 2209a0bf528SMauro Carvalho Chehab dprintk("diversity combination deactivated - forced by COFDM parameters"); 2219a0bf528SMauro Carvalho Chehab onoff = 0; 2229a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 207, 0); 2239a0bf528SMauro Carvalho Chehab } else 2249a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); 2259a0bf528SMauro Carvalho Chehab 2269a0bf528SMauro Carvalho Chehab state->div_state = (u8) onoff; 2279a0bf528SMauro Carvalho Chehab 2289a0bf528SMauro Carvalho Chehab if (onoff) { 2299a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 204, 6); 2309a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 205, 16); 2319a0bf528SMauro Carvalho Chehab /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ 2329a0bf528SMauro Carvalho Chehab } else { 2339a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 204, 1); 2349a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 205, 0); 2359a0bf528SMauro Carvalho Chehab } 2369a0bf528SMauro Carvalho Chehab 2379a0bf528SMauro Carvalho Chehab return 0; 2389a0bf528SMauro Carvalho Chehab } 2399a0bf528SMauro Carvalho Chehab 2409a0bf528SMauro Carvalho Chehab static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) 2419a0bf528SMauro Carvalho Chehab { 2429a0bf528SMauro Carvalho Chehab /* by default everything is powered off */ 2439a0bf528SMauro Carvalho Chehab u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff); 2449a0bf528SMauro Carvalho Chehab 2459a0bf528SMauro Carvalho Chehab /* now, depending on the requested mode, we power on */ 2469a0bf528SMauro Carvalho Chehab switch (mode) { 2479a0bf528SMauro Carvalho Chehab /* power up everything in the demod */ 2489a0bf528SMauro Carvalho Chehab case DIB7000P_POWER_ALL: 2499a0bf528SMauro Carvalho Chehab reg_774 = 0x0000; 2509a0bf528SMauro Carvalho Chehab reg_775 = 0x0000; 2519a0bf528SMauro Carvalho Chehab reg_776 = 0x0; 2529a0bf528SMauro Carvalho Chehab reg_899 = 0x0; 2539a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 2549a0bf528SMauro Carvalho Chehab reg_1280 &= 0x001f; 2559a0bf528SMauro Carvalho Chehab else 2569a0bf528SMauro Carvalho Chehab reg_1280 &= 0x01ff; 2579a0bf528SMauro Carvalho Chehab break; 2589a0bf528SMauro Carvalho Chehab 2599a0bf528SMauro Carvalho Chehab case DIB7000P_POWER_ANALOG_ADC: 2609a0bf528SMauro Carvalho Chehab /* dem, cfg, iqc, sad, agc */ 2619a0bf528SMauro Carvalho Chehab reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); 2629a0bf528SMauro Carvalho Chehab /* nud */ 2639a0bf528SMauro Carvalho Chehab reg_776 &= ~((1 << 0)); 2649a0bf528SMauro Carvalho Chehab /* Dout */ 2659a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) 2669a0bf528SMauro Carvalho Chehab reg_1280 &= ~((1 << 11)); 2679a0bf528SMauro Carvalho Chehab reg_1280 &= ~(1 << 6); 2689a0bf528SMauro Carvalho Chehab /* fall through wanted to enable the interfaces */ 2699a0bf528SMauro Carvalho Chehab 2709a0bf528SMauro Carvalho Chehab /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ 2719a0bf528SMauro Carvalho Chehab case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ 2729a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 2739a0bf528SMauro Carvalho Chehab reg_1280 &= ~((1 << 7) | (1 << 5)); 2749a0bf528SMauro Carvalho Chehab else 2759a0bf528SMauro Carvalho Chehab reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); 2769a0bf528SMauro Carvalho Chehab break; 2779a0bf528SMauro Carvalho Chehab 2789a0bf528SMauro Carvalho Chehab /* TODO following stuff is just converted from the dib7000-driver - check when is used what */ 2799a0bf528SMauro Carvalho Chehab } 2809a0bf528SMauro Carvalho Chehab 2819a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 774, reg_774); 2829a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 775, reg_775); 2839a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 776, reg_776); 2849a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1280, reg_1280); 2859a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) 2869a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 899, reg_899); 2879a0bf528SMauro Carvalho Chehab 2889a0bf528SMauro Carvalho Chehab return 0; 2899a0bf528SMauro Carvalho Chehab } 2909a0bf528SMauro Carvalho Chehab 2919a0bf528SMauro Carvalho Chehab static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no) 2929a0bf528SMauro Carvalho Chehab { 2939a0bf528SMauro Carvalho Chehab u16 reg_908 = 0, reg_909 = 0; 2949a0bf528SMauro Carvalho Chehab u16 reg; 2959a0bf528SMauro Carvalho Chehab 2969a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) { 2979a0bf528SMauro Carvalho Chehab reg_908 = dib7000p_read_word(state, 908); 2989a0bf528SMauro Carvalho Chehab reg_909 = dib7000p_read_word(state, 909); 2999a0bf528SMauro Carvalho Chehab } 3009a0bf528SMauro Carvalho Chehab 3019a0bf528SMauro Carvalho Chehab switch (no) { 3029a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_ON: 3039a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) { 3049a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1925); 3059a0bf528SMauro Carvalho Chehab 3069a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */ 3079a0bf528SMauro Carvalho Chehab 3089a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */ 3099a0bf528SMauro Carvalho Chehab msleep(200); 3109a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */ 3119a0bf528SMauro Carvalho Chehab 3129a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12)); 3139a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */ 3149a0bf528SMauro Carvalho Chehab } else { 3159a0bf528SMauro Carvalho Chehab reg_909 |= (1 << 1) | (1 << 0); 3169a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 909, reg_909); 3179a0bf528SMauro Carvalho Chehab reg_909 &= ~(1 << 1); 3189a0bf528SMauro Carvalho Chehab } 3199a0bf528SMauro Carvalho Chehab break; 3209a0bf528SMauro Carvalho Chehab 3219a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_OFF: 3229a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) { 3239a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1925); 3249a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */ 3259a0bf528SMauro Carvalho Chehab } else 3269a0bf528SMauro Carvalho Chehab reg_909 |= (1 << 1) | (1 << 0); 3279a0bf528SMauro Carvalho Chehab break; 3289a0bf528SMauro Carvalho Chehab 3299a0bf528SMauro Carvalho Chehab case DIBX000_ADC_ON: 3309a0bf528SMauro Carvalho Chehab reg_908 &= 0x0fff; 3319a0bf528SMauro Carvalho Chehab reg_909 &= 0x0003; 3329a0bf528SMauro Carvalho Chehab break; 3339a0bf528SMauro Carvalho Chehab 3349a0bf528SMauro Carvalho Chehab case DIBX000_ADC_OFF: 3359a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 14) | (1 << 13) | (1 << 12); 3369a0bf528SMauro Carvalho Chehab reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); 3379a0bf528SMauro Carvalho Chehab break; 3389a0bf528SMauro Carvalho Chehab 3399a0bf528SMauro Carvalho Chehab case DIBX000_VBG_ENABLE: 3409a0bf528SMauro Carvalho Chehab reg_908 &= ~(1 << 15); 3419a0bf528SMauro Carvalho Chehab break; 3429a0bf528SMauro Carvalho Chehab 3439a0bf528SMauro Carvalho Chehab case DIBX000_VBG_DISABLE: 3449a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 15); 3459a0bf528SMauro Carvalho Chehab break; 3469a0bf528SMauro Carvalho Chehab 3479a0bf528SMauro Carvalho Chehab default: 3489a0bf528SMauro Carvalho Chehab break; 3499a0bf528SMauro Carvalho Chehab } 3509a0bf528SMauro Carvalho Chehab 3519a0bf528SMauro Carvalho Chehab // dprintk( "908: %x, 909: %x\n", reg_908, reg_909); 3529a0bf528SMauro Carvalho Chehab 3539a0bf528SMauro Carvalho Chehab reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4; 3549a0bf528SMauro Carvalho Chehab reg_908 |= (state->cfg.enable_current_mirror & 1) << 7; 3559a0bf528SMauro Carvalho Chehab 3569a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) { 3579a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 908, reg_908); 3589a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 909, reg_909); 3599a0bf528SMauro Carvalho Chehab } 3609a0bf528SMauro Carvalho Chehab } 3619a0bf528SMauro Carvalho Chehab 3629a0bf528SMauro Carvalho Chehab static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) 3639a0bf528SMauro Carvalho Chehab { 3649a0bf528SMauro Carvalho Chehab u32 timf; 3659a0bf528SMauro Carvalho Chehab 3669a0bf528SMauro Carvalho Chehab // store the current bandwidth for later use 3679a0bf528SMauro Carvalho Chehab state->current_bandwidth = bw; 3689a0bf528SMauro Carvalho Chehab 3699a0bf528SMauro Carvalho Chehab if (state->timf == 0) { 3709a0bf528SMauro Carvalho Chehab dprintk("using default timf"); 3719a0bf528SMauro Carvalho Chehab timf = state->cfg.bw->timf; 3729a0bf528SMauro Carvalho Chehab } else { 3739a0bf528SMauro Carvalho Chehab dprintk("using updated timf"); 3749a0bf528SMauro Carvalho Chehab timf = state->timf; 3759a0bf528SMauro Carvalho Chehab } 3769a0bf528SMauro Carvalho Chehab 3779a0bf528SMauro Carvalho Chehab timf = timf * (bw / 50) / 160; 3789a0bf528SMauro Carvalho Chehab 3799a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); 3809a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff)); 3819a0bf528SMauro Carvalho Chehab 3829a0bf528SMauro Carvalho Chehab return 0; 3839a0bf528SMauro Carvalho Chehab } 3849a0bf528SMauro Carvalho Chehab 3859a0bf528SMauro Carvalho Chehab static int dib7000p_sad_calib(struct dib7000p_state *state) 3869a0bf528SMauro Carvalho Chehab { 3879a0bf528SMauro Carvalho Chehab /* internal */ 3889a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); 3899a0bf528SMauro Carvalho Chehab 3909a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 3919a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 74, 2048); 3929a0bf528SMauro Carvalho Chehab else 3939a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 74, 776); 3949a0bf528SMauro Carvalho Chehab 3959a0bf528SMauro Carvalho Chehab /* do the calibration */ 3969a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 73, (1 << 0)); 3979a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 73, (0 << 0)); 3989a0bf528SMauro Carvalho Chehab 3999a0bf528SMauro Carvalho Chehab msleep(1); 4009a0bf528SMauro Carvalho Chehab 4019a0bf528SMauro Carvalho Chehab return 0; 4029a0bf528SMauro Carvalho Chehab } 4039a0bf528SMauro Carvalho Chehab 404*8abe4a0aSMauro Carvalho Chehab static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) 4059a0bf528SMauro Carvalho Chehab { 4069a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 4079a0bf528SMauro Carvalho Chehab if (value > 4095) 4089a0bf528SMauro Carvalho Chehab value = 4095; 4099a0bf528SMauro Carvalho Chehab state->wbd_ref = value; 4109a0bf528SMauro Carvalho Chehab return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); 4119a0bf528SMauro Carvalho Chehab } 4129a0bf528SMauro Carvalho Chehab 413*8abe4a0aSMauro Carvalho Chehab static int dib7000p_get_agc_values(struct dvb_frontend *fe, 4149a0bf528SMauro Carvalho Chehab u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd) 4159a0bf528SMauro Carvalho Chehab { 4169a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 4179a0bf528SMauro Carvalho Chehab 4189a0bf528SMauro Carvalho Chehab if (agc_global != NULL) 4199a0bf528SMauro Carvalho Chehab *agc_global = dib7000p_read_word(state, 394); 4209a0bf528SMauro Carvalho Chehab if (agc1 != NULL) 4219a0bf528SMauro Carvalho Chehab *agc1 = dib7000p_read_word(state, 392); 4229a0bf528SMauro Carvalho Chehab if (agc2 != NULL) 4239a0bf528SMauro Carvalho Chehab *agc2 = dib7000p_read_word(state, 393); 4249a0bf528SMauro Carvalho Chehab if (wbd != NULL) 4259a0bf528SMauro Carvalho Chehab *wbd = dib7000p_read_word(state, 397); 4269a0bf528SMauro Carvalho Chehab 4279a0bf528SMauro Carvalho Chehab return 0; 4289a0bf528SMauro Carvalho Chehab } 4299a0bf528SMauro Carvalho Chehab 430*8abe4a0aSMauro Carvalho Chehab static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v) 4316fe1099cSOlivier Grenie { 4326fe1099cSOlivier Grenie struct dib7000p_state *state = fe->demodulator_priv; 4336fe1099cSOlivier Grenie return dib7000p_write_word(state, 108, v); 4346fe1099cSOlivier Grenie } 4356fe1099cSOlivier Grenie 4369a0bf528SMauro Carvalho Chehab static void dib7000p_reset_pll(struct dib7000p_state *state) 4379a0bf528SMauro Carvalho Chehab { 4389a0bf528SMauro Carvalho Chehab struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; 4399a0bf528SMauro Carvalho Chehab u16 clk_cfg0; 4409a0bf528SMauro Carvalho Chehab 4419a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) { 4429a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv)); 4439a0bf528SMauro Carvalho Chehab 4449a0bf528SMauro Carvalho Chehab while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) 4459a0bf528SMauro Carvalho Chehab ; 4469a0bf528SMauro Carvalho Chehab 4479a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15)); 4489a0bf528SMauro Carvalho Chehab } else { 4499a0bf528SMauro Carvalho Chehab /* force PLL bypass */ 4509a0bf528SMauro Carvalho Chehab clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | 4519a0bf528SMauro Carvalho Chehab (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); 4529a0bf528SMauro Carvalho Chehab 4539a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 900, clk_cfg0); 4549a0bf528SMauro Carvalho Chehab 4559a0bf528SMauro Carvalho Chehab /* P_pll_cfg */ 4569a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); 4579a0bf528SMauro Carvalho Chehab clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); 4589a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 900, clk_cfg0); 4599a0bf528SMauro Carvalho Chehab } 4609a0bf528SMauro Carvalho Chehab 4619a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); 4629a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff)); 4639a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff)); 4649a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff)); 4659a0bf528SMauro Carvalho Chehab 4669a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 72, bw->sad_cfg); 4679a0bf528SMauro Carvalho Chehab } 4689a0bf528SMauro Carvalho Chehab 4699a0bf528SMauro Carvalho Chehab static u32 dib7000p_get_internal_freq(struct dib7000p_state *state) 4709a0bf528SMauro Carvalho Chehab { 4719a0bf528SMauro Carvalho Chehab u32 internal = (u32) dib7000p_read_word(state, 18) << 16; 4729a0bf528SMauro Carvalho Chehab internal |= (u32) dib7000p_read_word(state, 19); 4739a0bf528SMauro Carvalho Chehab internal /= 1000; 4749a0bf528SMauro Carvalho Chehab 4759a0bf528SMauro Carvalho Chehab return internal; 4769a0bf528SMauro Carvalho Chehab } 4779a0bf528SMauro Carvalho Chehab 478*8abe4a0aSMauro Carvalho Chehab static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw) 4799a0bf528SMauro Carvalho Chehab { 4809a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 4819a0bf528SMauro Carvalho Chehab u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856); 4829a0bf528SMauro Carvalho Chehab u8 loopdiv, prediv; 4839a0bf528SMauro Carvalho Chehab u32 internal, xtal; 4849a0bf528SMauro Carvalho Chehab 4859a0bf528SMauro Carvalho Chehab /* get back old values */ 4869a0bf528SMauro Carvalho Chehab prediv = reg_1856 & 0x3f; 4879a0bf528SMauro Carvalho Chehab loopdiv = (reg_1856 >> 6) & 0x3f; 4889a0bf528SMauro Carvalho Chehab 4899a0bf528SMauro Carvalho Chehab if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) { 4909a0bf528SMauro Carvalho Chehab dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); 4919a0bf528SMauro Carvalho Chehab reg_1856 &= 0xf000; 4929a0bf528SMauro Carvalho Chehab reg_1857 = dib7000p_read_word(state, 1857); 4939a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); 4949a0bf528SMauro Carvalho Chehab 4959a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f)); 4969a0bf528SMauro Carvalho Chehab 4979a0bf528SMauro Carvalho Chehab /* write new system clk into P_sec_len */ 4989a0bf528SMauro Carvalho Chehab internal = dib7000p_get_internal_freq(state); 4999a0bf528SMauro Carvalho Chehab xtal = (internal / loopdiv) * prediv; 5009a0bf528SMauro Carvalho Chehab internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */ 5019a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff)); 5029a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 19, (u16) (internal & 0xffff)); 5039a0bf528SMauro Carvalho Chehab 5049a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); 5059a0bf528SMauro Carvalho Chehab 5069a0bf528SMauro Carvalho Chehab while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) 5079a0bf528SMauro Carvalho Chehab dprintk("Waiting for PLL to lock"); 5089a0bf528SMauro Carvalho Chehab 5099a0bf528SMauro Carvalho Chehab return 0; 5109a0bf528SMauro Carvalho Chehab } 5119a0bf528SMauro Carvalho Chehab return -EIO; 5129a0bf528SMauro Carvalho Chehab } 5139a0bf528SMauro Carvalho Chehab 5149a0bf528SMauro Carvalho Chehab static int dib7000p_reset_gpio(struct dib7000p_state *st) 5159a0bf528SMauro Carvalho Chehab { 5169a0bf528SMauro Carvalho Chehab /* reset the GPIOs */ 5179a0bf528SMauro Carvalho Chehab dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos); 5189a0bf528SMauro Carvalho Chehab 5199a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1029, st->gpio_dir); 5209a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1030, st->gpio_val); 5219a0bf528SMauro Carvalho Chehab 5229a0bf528SMauro Carvalho Chehab /* TODO 1031 is P_gpio_od */ 5239a0bf528SMauro Carvalho Chehab 5249a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos); 5259a0bf528SMauro Carvalho Chehab 5269a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div); 5279a0bf528SMauro Carvalho Chehab return 0; 5289a0bf528SMauro Carvalho Chehab } 5299a0bf528SMauro Carvalho Chehab 5309a0bf528SMauro Carvalho Chehab static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) 5319a0bf528SMauro Carvalho Chehab { 5329a0bf528SMauro Carvalho Chehab st->gpio_dir = dib7000p_read_word(st, 1029); 5339a0bf528SMauro Carvalho Chehab st->gpio_dir &= ~(1 << num); /* reset the direction bit */ 5349a0bf528SMauro Carvalho Chehab st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ 5359a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1029, st->gpio_dir); 5369a0bf528SMauro Carvalho Chehab 5379a0bf528SMauro Carvalho Chehab st->gpio_val = dib7000p_read_word(st, 1030); 5389a0bf528SMauro Carvalho Chehab st->gpio_val &= ~(1 << num); /* reset the direction bit */ 5399a0bf528SMauro Carvalho Chehab st->gpio_val |= (val & 0x01) << num; /* set the new value */ 5409a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1030, st->gpio_val); 5419a0bf528SMauro Carvalho Chehab 5429a0bf528SMauro Carvalho Chehab return 0; 5439a0bf528SMauro Carvalho Chehab } 5449a0bf528SMauro Carvalho Chehab 545*8abe4a0aSMauro Carvalho Chehab static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) 5469a0bf528SMauro Carvalho Chehab { 5479a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 5489a0bf528SMauro Carvalho Chehab return dib7000p_cfg_gpio(state, num, dir, val); 5499a0bf528SMauro Carvalho Chehab } 5509a0bf528SMauro Carvalho Chehab 5519a0bf528SMauro Carvalho Chehab static u16 dib7000p_defaults[] = { 5529a0bf528SMauro Carvalho Chehab // auto search configuration 5539a0bf528SMauro Carvalho Chehab 3, 2, 5549a0bf528SMauro Carvalho Chehab 0x0004, 5559a0bf528SMauro Carvalho Chehab (1<<3)|(1<<11)|(1<<12)|(1<<13), 5569a0bf528SMauro Carvalho Chehab 0x0814, /* Equal Lock */ 5579a0bf528SMauro Carvalho Chehab 5589a0bf528SMauro Carvalho Chehab 12, 6, 5599a0bf528SMauro Carvalho Chehab 0x001b, 5609a0bf528SMauro Carvalho Chehab 0x7740, 5619a0bf528SMauro Carvalho Chehab 0x005b, 5629a0bf528SMauro Carvalho Chehab 0x8d80, 5639a0bf528SMauro Carvalho Chehab 0x01c9, 5649a0bf528SMauro Carvalho Chehab 0xc380, 5659a0bf528SMauro Carvalho Chehab 0x0000, 5669a0bf528SMauro Carvalho Chehab 0x0080, 5679a0bf528SMauro Carvalho Chehab 0x0000, 5689a0bf528SMauro Carvalho Chehab 0x0090, 5699a0bf528SMauro Carvalho Chehab 0x0001, 5709a0bf528SMauro Carvalho Chehab 0xd4c0, 5719a0bf528SMauro Carvalho Chehab 5729a0bf528SMauro Carvalho Chehab 1, 26, 5739a0bf528SMauro Carvalho Chehab 0x6680, 5749a0bf528SMauro Carvalho Chehab 5759a0bf528SMauro Carvalho Chehab /* set ADC level to -16 */ 5769a0bf528SMauro Carvalho Chehab 11, 79, 5779a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117, 5789a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117, 5799a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117, 5809a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117, 5819a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117, 5829a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117, 5839a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117, 5849a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117, 5859a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117, 5869a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117, 5879a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117, 5889a0bf528SMauro Carvalho Chehab 5899a0bf528SMauro Carvalho Chehab 1, 142, 5909a0bf528SMauro Carvalho Chehab 0x0410, 5919a0bf528SMauro Carvalho Chehab 5929a0bf528SMauro Carvalho Chehab /* disable power smoothing */ 5939a0bf528SMauro Carvalho Chehab 8, 145, 5949a0bf528SMauro Carvalho Chehab 0, 5959a0bf528SMauro Carvalho Chehab 0, 5969a0bf528SMauro Carvalho Chehab 0, 5979a0bf528SMauro Carvalho Chehab 0, 5989a0bf528SMauro Carvalho Chehab 0, 5999a0bf528SMauro Carvalho Chehab 0, 6009a0bf528SMauro Carvalho Chehab 0, 6019a0bf528SMauro Carvalho Chehab 0, 6029a0bf528SMauro Carvalho Chehab 6039a0bf528SMauro Carvalho Chehab 1, 154, 6049a0bf528SMauro Carvalho Chehab 1 << 13, 6059a0bf528SMauro Carvalho Chehab 6069a0bf528SMauro Carvalho Chehab 1, 168, 6079a0bf528SMauro Carvalho Chehab 0x0ccd, 6089a0bf528SMauro Carvalho Chehab 6099a0bf528SMauro Carvalho Chehab 1, 183, 6109a0bf528SMauro Carvalho Chehab 0x200f, 6119a0bf528SMauro Carvalho Chehab 6129a0bf528SMauro Carvalho Chehab 1, 212, 6139a0bf528SMauro Carvalho Chehab 0x169, 6149a0bf528SMauro Carvalho Chehab 6159a0bf528SMauro Carvalho Chehab 5, 187, 6169a0bf528SMauro Carvalho Chehab 0x023d, 6179a0bf528SMauro Carvalho Chehab 0x00a4, 6189a0bf528SMauro Carvalho Chehab 0x00a4, 6199a0bf528SMauro Carvalho Chehab 0x7ff0, 6209a0bf528SMauro Carvalho Chehab 0x3ccc, 6219a0bf528SMauro Carvalho Chehab 6229a0bf528SMauro Carvalho Chehab 1, 198, 6239a0bf528SMauro Carvalho Chehab 0x800, 6249a0bf528SMauro Carvalho Chehab 6259a0bf528SMauro Carvalho Chehab 1, 222, 6269a0bf528SMauro Carvalho Chehab 0x0010, 6279a0bf528SMauro Carvalho Chehab 6289a0bf528SMauro Carvalho Chehab 1, 235, 6299a0bf528SMauro Carvalho Chehab 0x0062, 6309a0bf528SMauro Carvalho Chehab 6319a0bf528SMauro Carvalho Chehab 0, 6329a0bf528SMauro Carvalho Chehab }; 6339a0bf528SMauro Carvalho Chehab 6349a0bf528SMauro Carvalho Chehab static int dib7000p_demod_reset(struct dib7000p_state *state) 6359a0bf528SMauro Carvalho Chehab { 6369a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); 6379a0bf528SMauro Carvalho Chehab 6389a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 6399a0bf528SMauro Carvalho Chehab dibx000_reset_i2c_master(&state->i2c_master); 6409a0bf528SMauro Carvalho Chehab 6419a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE); 6429a0bf528SMauro Carvalho Chehab 6439a0bf528SMauro Carvalho Chehab /* restart all parts */ 6449a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0xffff); 6459a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, 0xffff); 6469a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 772, 0x001f); 6479a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3))); 6489a0bf528SMauro Carvalho Chehab 6499a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0); 6509a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, 0); 6519a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 772, 0); 6529a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1280, 0); 6539a0bf528SMauro Carvalho Chehab 6549a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) { 6559a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 898, 0x0003); 6569a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 898, 0); 6579a0bf528SMauro Carvalho Chehab } 6589a0bf528SMauro Carvalho Chehab 6599a0bf528SMauro Carvalho Chehab /* default */ 6609a0bf528SMauro Carvalho Chehab dib7000p_reset_pll(state); 6619a0bf528SMauro Carvalho Chehab 6629a0bf528SMauro Carvalho Chehab if (dib7000p_reset_gpio(state) != 0) 6639a0bf528SMauro Carvalho Chehab dprintk("GPIO reset was not successful."); 6649a0bf528SMauro Carvalho Chehab 6659a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) { 6669a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 899, 0); 6679a0bf528SMauro Carvalho Chehab 6689a0bf528SMauro Carvalho Chehab /* impulse noise */ 6699a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */ 6709a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */ 6719a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */ 6729a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 273, (0<<6) | 30); 6739a0bf528SMauro Carvalho Chehab } 6749a0bf528SMauro Carvalho Chehab if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) 6759a0bf528SMauro Carvalho Chehab dprintk("OUTPUT_MODE could not be reset."); 6769a0bf528SMauro Carvalho Chehab 6779a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); 6789a0bf528SMauro Carvalho Chehab dib7000p_sad_calib(state); 6799a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); 6809a0bf528SMauro Carvalho Chehab 6819a0bf528SMauro Carvalho Chehab /* unforce divstr regardless whether i2c enumeration was done or not */ 6829a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1)); 6839a0bf528SMauro Carvalho Chehab 6849a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, 8000); 6859a0bf528SMauro Carvalho Chehab 6869a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) { 6879a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ 6889a0bf528SMauro Carvalho Chehab } else { 6899a0bf528SMauro Carvalho Chehab if (state->cfg.tuner_is_baseband) 6909a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 36, 0x0755); 6919a0bf528SMauro Carvalho Chehab else 6929a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 36, 0x1f55); 6939a0bf528SMauro Carvalho Chehab } 6949a0bf528SMauro Carvalho Chehab 6959a0bf528SMauro Carvalho Chehab dib7000p_write_tab(state, dib7000p_defaults); 6969a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) { 6979a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 901, 0x0006); 6989a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); 6999a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 905, 0x2c8e); 7009a0bf528SMauro Carvalho Chehab } 7019a0bf528SMauro Carvalho Chehab 7029a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); 7039a0bf528SMauro Carvalho Chehab 7049a0bf528SMauro Carvalho Chehab return 0; 7059a0bf528SMauro Carvalho Chehab } 7069a0bf528SMauro Carvalho Chehab 7079a0bf528SMauro Carvalho Chehab static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) 7089a0bf528SMauro Carvalho Chehab { 7099a0bf528SMauro Carvalho Chehab u16 tmp = 0; 7109a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 903); 7119a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 903, (tmp | 0x1)); 7129a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 900); 7139a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); 7149a0bf528SMauro Carvalho Chehab } 7159a0bf528SMauro Carvalho Chehab 7169a0bf528SMauro Carvalho Chehab static void dib7000p_restart_agc(struct dib7000p_state *state) 7179a0bf528SMauro Carvalho Chehab { 7189a0bf528SMauro Carvalho Chehab // P_restart_iqc & P_restart_agc 7199a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); 7209a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0x0000); 7219a0bf528SMauro Carvalho Chehab } 7229a0bf528SMauro Carvalho Chehab 7239a0bf528SMauro Carvalho Chehab static int dib7000p_update_lna(struct dib7000p_state *state) 7249a0bf528SMauro Carvalho Chehab { 7259a0bf528SMauro Carvalho Chehab u16 dyn_gain; 7269a0bf528SMauro Carvalho Chehab 7279a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna) { 7289a0bf528SMauro Carvalho Chehab dyn_gain = dib7000p_read_word(state, 394); 7299a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna(&state->demod, dyn_gain)) { 7309a0bf528SMauro Carvalho Chehab dib7000p_restart_agc(state); 7319a0bf528SMauro Carvalho Chehab return 1; 7329a0bf528SMauro Carvalho Chehab } 7339a0bf528SMauro Carvalho Chehab } 7349a0bf528SMauro Carvalho Chehab 7359a0bf528SMauro Carvalho Chehab return 0; 7369a0bf528SMauro Carvalho Chehab } 7379a0bf528SMauro Carvalho Chehab 7389a0bf528SMauro Carvalho Chehab static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) 7399a0bf528SMauro Carvalho Chehab { 7409a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *agc = NULL; 7419a0bf528SMauro Carvalho Chehab int i; 7429a0bf528SMauro Carvalho Chehab if (state->current_band == band && state->current_agc != NULL) 7439a0bf528SMauro Carvalho Chehab return 0; 7449a0bf528SMauro Carvalho Chehab state->current_band = band; 7459a0bf528SMauro Carvalho Chehab 7469a0bf528SMauro Carvalho Chehab for (i = 0; i < state->cfg.agc_config_count; i++) 7479a0bf528SMauro Carvalho Chehab if (state->cfg.agc[i].band_caps & band) { 7489a0bf528SMauro Carvalho Chehab agc = &state->cfg.agc[i]; 7499a0bf528SMauro Carvalho Chehab break; 7509a0bf528SMauro Carvalho Chehab } 7519a0bf528SMauro Carvalho Chehab 7529a0bf528SMauro Carvalho Chehab if (agc == NULL) { 7539a0bf528SMauro Carvalho Chehab dprintk("no valid AGC configuration found for band 0x%02x", band); 7549a0bf528SMauro Carvalho Chehab return -EINVAL; 7559a0bf528SMauro Carvalho Chehab } 7569a0bf528SMauro Carvalho Chehab 7579a0bf528SMauro Carvalho Chehab state->current_agc = agc; 7589a0bf528SMauro Carvalho Chehab 7599a0bf528SMauro Carvalho Chehab /* AGC */ 7609a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 75, agc->setup); 7619a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 76, agc->inv_gain); 7629a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 77, agc->time_stabiliz); 7639a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); 7649a0bf528SMauro Carvalho Chehab 7659a0bf528SMauro Carvalho Chehab // Demod AGC loop configuration 7669a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); 7679a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); 7689a0bf528SMauro Carvalho Chehab 7699a0bf528SMauro Carvalho Chehab /* AGC continued */ 7709a0bf528SMauro Carvalho Chehab dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", 7719a0bf528SMauro Carvalho Chehab state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); 7729a0bf528SMauro Carvalho Chehab 7739a0bf528SMauro Carvalho Chehab if (state->wbd_ref != 0) 7749a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); 7759a0bf528SMauro Carvalho Chehab else 7769a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); 7779a0bf528SMauro Carvalho Chehab 7789a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); 7799a0bf528SMauro Carvalho Chehab 7809a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 107, agc->agc1_max); 7819a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 108, agc->agc1_min); 7829a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 109, agc->agc2_max); 7839a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 110, agc->agc2_min); 7849a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); 7859a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 112, agc->agc1_pt3); 7869a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); 7879a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); 7889a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); 7899a0bf528SMauro Carvalho Chehab return 0; 7909a0bf528SMauro Carvalho Chehab } 7919a0bf528SMauro Carvalho Chehab 7929a0bf528SMauro Carvalho Chehab static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) 7939a0bf528SMauro Carvalho Chehab { 7949a0bf528SMauro Carvalho Chehab u32 internal = dib7000p_get_internal_freq(state); 7959a0bf528SMauro Carvalho Chehab s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */ 7969a0bf528SMauro Carvalho Chehab u32 abs_offset_khz = ABS(offset_khz); 7979a0bf528SMauro Carvalho Chehab u32 dds = state->cfg.bw->ifreq & 0x1ffffff; 7989a0bf528SMauro Carvalho Chehab u8 invert = !!(state->cfg.bw->ifreq & (1 << 25)); 7999a0bf528SMauro Carvalho Chehab 8009a0bf528SMauro Carvalho Chehab dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert); 8019a0bf528SMauro Carvalho Chehab 8029a0bf528SMauro Carvalho Chehab if (offset_khz < 0) 8039a0bf528SMauro Carvalho Chehab unit_khz_dds_val *= -1; 8049a0bf528SMauro Carvalho Chehab 8059a0bf528SMauro Carvalho Chehab /* IF tuner */ 8069a0bf528SMauro Carvalho Chehab if (invert) 8079a0bf528SMauro Carvalho Chehab dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */ 8089a0bf528SMauro Carvalho Chehab else 8099a0bf528SMauro Carvalho Chehab dds += (abs_offset_khz * unit_khz_dds_val); 8109a0bf528SMauro Carvalho Chehab 8119a0bf528SMauro Carvalho Chehab if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */ 8129a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9))); 8139a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 22, (u16) (dds & 0xffff)); 8149a0bf528SMauro Carvalho Chehab } 8159a0bf528SMauro Carvalho Chehab } 8169a0bf528SMauro Carvalho Chehab 8179a0bf528SMauro Carvalho Chehab static int dib7000p_agc_startup(struct dvb_frontend *demod) 8189a0bf528SMauro Carvalho Chehab { 8199a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch = &demod->dtv_property_cache; 8209a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 8219a0bf528SMauro Carvalho Chehab int ret = -1; 8229a0bf528SMauro Carvalho Chehab u8 *agc_state = &state->agc_state; 8239a0bf528SMauro Carvalho Chehab u8 agc_split; 8249a0bf528SMauro Carvalho Chehab u16 reg; 8259a0bf528SMauro Carvalho Chehab u32 upd_demod_gain_period = 0x1000; 8266fe1099cSOlivier Grenie s32 frequency_offset = 0; 8279a0bf528SMauro Carvalho Chehab 8289a0bf528SMauro Carvalho Chehab switch (state->agc_state) { 8299a0bf528SMauro Carvalho Chehab case 0: 8309a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); 8319a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) { 8329a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 0x79b) & 0xff00; 8339a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */ 8349a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF)); 8359a0bf528SMauro Carvalho Chehab 8369a0bf528SMauro Carvalho Chehab /* enable adc i & q */ 8379a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 0x780); 8389a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7))); 8399a0bf528SMauro Carvalho Chehab } else { 8409a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_ADC_ON); 8419a0bf528SMauro Carvalho Chehab dib7000p_pll_clk_cfg(state); 8429a0bf528SMauro Carvalho Chehab } 8439a0bf528SMauro Carvalho Chehab 8449a0bf528SMauro Carvalho Chehab if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0) 8459a0bf528SMauro Carvalho Chehab return -1; 8469a0bf528SMauro Carvalho Chehab 8476fe1099cSOlivier Grenie if (demod->ops.tuner_ops.get_frequency) { 8486fe1099cSOlivier Grenie u32 frequency_tuner; 8496fe1099cSOlivier Grenie 8506fe1099cSOlivier Grenie demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner); 8516fe1099cSOlivier Grenie frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000; 8526fe1099cSOlivier Grenie } 8536fe1099cSOlivier Grenie 8546fe1099cSOlivier Grenie dib7000p_set_dds(state, frequency_offset); 8559a0bf528SMauro Carvalho Chehab ret = 7; 8569a0bf528SMauro Carvalho Chehab (*agc_state)++; 8579a0bf528SMauro Carvalho Chehab break; 8589a0bf528SMauro Carvalho Chehab 8599a0bf528SMauro Carvalho Chehab case 1: 8609a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 8619a0bf528SMauro Carvalho Chehab state->cfg.agc_control(&state->demod, 1); 8629a0bf528SMauro Carvalho Chehab 8639a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 78, 32768); 8649a0bf528SMauro Carvalho Chehab if (!state->current_agc->perform_agc_softsplit) { 8659a0bf528SMauro Carvalho Chehab /* we are using the wbd - so slow AGC startup */ 8669a0bf528SMauro Carvalho Chehab /* force 0 split on WBD and restart AGC */ 8679a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); 8689a0bf528SMauro Carvalho Chehab (*agc_state)++; 8699a0bf528SMauro Carvalho Chehab ret = 5; 8709a0bf528SMauro Carvalho Chehab } else { 8719a0bf528SMauro Carvalho Chehab /* default AGC startup */ 8729a0bf528SMauro Carvalho Chehab (*agc_state) = 4; 8739a0bf528SMauro Carvalho Chehab /* wait AGC rough lock time */ 8749a0bf528SMauro Carvalho Chehab ret = 7; 8759a0bf528SMauro Carvalho Chehab } 8769a0bf528SMauro Carvalho Chehab 8779a0bf528SMauro Carvalho Chehab dib7000p_restart_agc(state); 8789a0bf528SMauro Carvalho Chehab break; 8799a0bf528SMauro Carvalho Chehab 8809a0bf528SMauro Carvalho Chehab case 2: /* fast split search path after 5sec */ 8819a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ 8829a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ 8839a0bf528SMauro Carvalho Chehab (*agc_state)++; 8849a0bf528SMauro Carvalho Chehab ret = 14; 8859a0bf528SMauro Carvalho Chehab break; 8869a0bf528SMauro Carvalho Chehab 8879a0bf528SMauro Carvalho Chehab case 3: /* split search ended */ 8889a0bf528SMauro Carvalho Chehab agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */ 8899a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ 8909a0bf528SMauro Carvalho Chehab 8919a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ 8929a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ 8939a0bf528SMauro Carvalho Chehab 8949a0bf528SMauro Carvalho Chehab dib7000p_restart_agc(state); 8959a0bf528SMauro Carvalho Chehab 8969a0bf528SMauro Carvalho Chehab dprintk("SPLIT %p: %hd", demod, agc_split); 8979a0bf528SMauro Carvalho Chehab 8989a0bf528SMauro Carvalho Chehab (*agc_state)++; 8999a0bf528SMauro Carvalho Chehab ret = 5; 9009a0bf528SMauro Carvalho Chehab break; 9019a0bf528SMauro Carvalho Chehab 9029a0bf528SMauro Carvalho Chehab case 4: /* LNA startup */ 9039a0bf528SMauro Carvalho Chehab ret = 7; 9049a0bf528SMauro Carvalho Chehab 9059a0bf528SMauro Carvalho Chehab if (dib7000p_update_lna(state)) 9069a0bf528SMauro Carvalho Chehab ret = 5; 9079a0bf528SMauro Carvalho Chehab else 9089a0bf528SMauro Carvalho Chehab (*agc_state)++; 9099a0bf528SMauro Carvalho Chehab break; 9109a0bf528SMauro Carvalho Chehab 9119a0bf528SMauro Carvalho Chehab case 5: 9129a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control) 9139a0bf528SMauro Carvalho Chehab state->cfg.agc_control(&state->demod, 0); 9149a0bf528SMauro Carvalho Chehab (*agc_state)++; 9159a0bf528SMauro Carvalho Chehab break; 9169a0bf528SMauro Carvalho Chehab default: 9179a0bf528SMauro Carvalho Chehab break; 9189a0bf528SMauro Carvalho Chehab } 9199a0bf528SMauro Carvalho Chehab return ret; 9209a0bf528SMauro Carvalho Chehab } 9219a0bf528SMauro Carvalho Chehab 9229a0bf528SMauro Carvalho Chehab static void dib7000p_update_timf(struct dib7000p_state *state) 9239a0bf528SMauro Carvalho Chehab { 9249a0bf528SMauro Carvalho Chehab u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); 9259a0bf528SMauro Carvalho Chehab state->timf = timf * 160 / (state->current_bandwidth / 50); 9269a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 23, (u16) (timf >> 16)); 9279a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); 9289a0bf528SMauro Carvalho Chehab dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf); 9299a0bf528SMauro Carvalho Chehab 9309a0bf528SMauro Carvalho Chehab } 9319a0bf528SMauro Carvalho Chehab 932*8abe4a0aSMauro Carvalho Chehab static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) 9339a0bf528SMauro Carvalho Chehab { 9349a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 9359a0bf528SMauro Carvalho Chehab switch (op) { 9369a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_SET: 9379a0bf528SMauro Carvalho Chehab state->timf = timf; 9389a0bf528SMauro Carvalho Chehab break; 9399a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_UPDATE: 9409a0bf528SMauro Carvalho Chehab dib7000p_update_timf(state); 9419a0bf528SMauro Carvalho Chehab break; 9429a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_GET: 9439a0bf528SMauro Carvalho Chehab break; 9449a0bf528SMauro Carvalho Chehab } 9459a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, state->current_bandwidth); 9469a0bf528SMauro Carvalho Chehab return state->timf; 9479a0bf528SMauro Carvalho Chehab } 9489a0bf528SMauro Carvalho Chehab 9499a0bf528SMauro Carvalho Chehab static void dib7000p_set_channel(struct dib7000p_state *state, 9509a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch, u8 seq) 9519a0bf528SMauro Carvalho Chehab { 9529a0bf528SMauro Carvalho Chehab u16 value, est[4]; 9539a0bf528SMauro Carvalho Chehab 9549a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); 9559a0bf528SMauro Carvalho Chehab 9569a0bf528SMauro Carvalho Chehab /* nfft, guard, qam, alpha */ 9579a0bf528SMauro Carvalho Chehab value = 0; 9589a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) { 9599a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 9609a0bf528SMauro Carvalho Chehab value |= (0 << 7); 9619a0bf528SMauro Carvalho Chehab break; 9629a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 9639a0bf528SMauro Carvalho Chehab value |= (2 << 7); 9649a0bf528SMauro Carvalho Chehab break; 9659a0bf528SMauro Carvalho Chehab default: 9669a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 9679a0bf528SMauro Carvalho Chehab value |= (1 << 7); 9689a0bf528SMauro Carvalho Chehab break; 9699a0bf528SMauro Carvalho Chehab } 9709a0bf528SMauro Carvalho Chehab switch (ch->guard_interval) { 9719a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 9729a0bf528SMauro Carvalho Chehab value |= (0 << 5); 9739a0bf528SMauro Carvalho Chehab break; 9749a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 9759a0bf528SMauro Carvalho Chehab value |= (1 << 5); 9769a0bf528SMauro Carvalho Chehab break; 9779a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 9789a0bf528SMauro Carvalho Chehab value |= (3 << 5); 9799a0bf528SMauro Carvalho Chehab break; 9809a0bf528SMauro Carvalho Chehab default: 9819a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 9829a0bf528SMauro Carvalho Chehab value |= (2 << 5); 9839a0bf528SMauro Carvalho Chehab break; 9849a0bf528SMauro Carvalho Chehab } 9859a0bf528SMauro Carvalho Chehab switch (ch->modulation) { 9869a0bf528SMauro Carvalho Chehab case QPSK: 9879a0bf528SMauro Carvalho Chehab value |= (0 << 3); 9889a0bf528SMauro Carvalho Chehab break; 9899a0bf528SMauro Carvalho Chehab case QAM_16: 9909a0bf528SMauro Carvalho Chehab value |= (1 << 3); 9919a0bf528SMauro Carvalho Chehab break; 9929a0bf528SMauro Carvalho Chehab default: 9939a0bf528SMauro Carvalho Chehab case QAM_64: 9949a0bf528SMauro Carvalho Chehab value |= (2 << 3); 9959a0bf528SMauro Carvalho Chehab break; 9969a0bf528SMauro Carvalho Chehab } 9979a0bf528SMauro Carvalho Chehab switch (HIERARCHY_1) { 9989a0bf528SMauro Carvalho Chehab case HIERARCHY_2: 9999a0bf528SMauro Carvalho Chehab value |= 2; 10009a0bf528SMauro Carvalho Chehab break; 10019a0bf528SMauro Carvalho Chehab case HIERARCHY_4: 10029a0bf528SMauro Carvalho Chehab value |= 4; 10039a0bf528SMauro Carvalho Chehab break; 10049a0bf528SMauro Carvalho Chehab default: 10059a0bf528SMauro Carvalho Chehab case HIERARCHY_1: 10069a0bf528SMauro Carvalho Chehab value |= 1; 10079a0bf528SMauro Carvalho Chehab break; 10089a0bf528SMauro Carvalho Chehab } 10099a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0, value); 10109a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ 10119a0bf528SMauro Carvalho Chehab 10129a0bf528SMauro Carvalho Chehab /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ 10139a0bf528SMauro Carvalho Chehab value = 0; 10149a0bf528SMauro Carvalho Chehab if (1 != 0) 10159a0bf528SMauro Carvalho Chehab value |= (1 << 6); 10169a0bf528SMauro Carvalho Chehab if (ch->hierarchy == 1) 10179a0bf528SMauro Carvalho Chehab value |= (1 << 4); 10189a0bf528SMauro Carvalho Chehab if (1 == 1) 10199a0bf528SMauro Carvalho Chehab value |= 1; 10209a0bf528SMauro Carvalho Chehab switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { 10219a0bf528SMauro Carvalho Chehab case FEC_2_3: 10229a0bf528SMauro Carvalho Chehab value |= (2 << 1); 10239a0bf528SMauro Carvalho Chehab break; 10249a0bf528SMauro Carvalho Chehab case FEC_3_4: 10259a0bf528SMauro Carvalho Chehab value |= (3 << 1); 10269a0bf528SMauro Carvalho Chehab break; 10279a0bf528SMauro Carvalho Chehab case FEC_5_6: 10289a0bf528SMauro Carvalho Chehab value |= (5 << 1); 10299a0bf528SMauro Carvalho Chehab break; 10309a0bf528SMauro Carvalho Chehab case FEC_7_8: 10319a0bf528SMauro Carvalho Chehab value |= (7 << 1); 10329a0bf528SMauro Carvalho Chehab break; 10339a0bf528SMauro Carvalho Chehab default: 10349a0bf528SMauro Carvalho Chehab case FEC_1_2: 10359a0bf528SMauro Carvalho Chehab value |= (1 << 1); 10369a0bf528SMauro Carvalho Chehab break; 10379a0bf528SMauro Carvalho Chehab } 10389a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 208, value); 10399a0bf528SMauro Carvalho Chehab 10409a0bf528SMauro Carvalho Chehab /* offset loop parameters */ 10419a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 26, 0x6680); 10429a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 32, 0x0003); 10439a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 29, 0x1273); 10449a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 33, 0x0005); 10459a0bf528SMauro Carvalho Chehab 10469a0bf528SMauro Carvalho Chehab /* P_dvsy_sync_wait */ 10479a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) { 10489a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 10499a0bf528SMauro Carvalho Chehab value = 256; 10509a0bf528SMauro Carvalho Chehab break; 10519a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 10529a0bf528SMauro Carvalho Chehab value = 128; 10539a0bf528SMauro Carvalho Chehab break; 10549a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 10559a0bf528SMauro Carvalho Chehab default: 10569a0bf528SMauro Carvalho Chehab value = 64; 10579a0bf528SMauro Carvalho Chehab break; 10589a0bf528SMauro Carvalho Chehab } 10599a0bf528SMauro Carvalho Chehab switch (ch->guard_interval) { 10609a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 10619a0bf528SMauro Carvalho Chehab value *= 2; 10629a0bf528SMauro Carvalho Chehab break; 10639a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 10649a0bf528SMauro Carvalho Chehab value *= 4; 10659a0bf528SMauro Carvalho Chehab break; 10669a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 10679a0bf528SMauro Carvalho Chehab value *= 8; 10689a0bf528SMauro Carvalho Chehab break; 10699a0bf528SMauro Carvalho Chehab default: 10709a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 10719a0bf528SMauro Carvalho Chehab value *= 1; 10729a0bf528SMauro Carvalho Chehab break; 10739a0bf528SMauro Carvalho Chehab } 10749a0bf528SMauro Carvalho Chehab if (state->cfg.diversity_delay == 0) 10759a0bf528SMauro Carvalho Chehab state->div_sync_wait = (value * 3) / 2 + 48; 10769a0bf528SMauro Carvalho Chehab else 10779a0bf528SMauro Carvalho Chehab state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; 10789a0bf528SMauro Carvalho Chehab 10799a0bf528SMauro Carvalho Chehab /* deactive the possibility of diversity reception if extended interleaver */ 10809a0bf528SMauro Carvalho Chehab state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K; 10819a0bf528SMauro Carvalho Chehab dib7000p_set_diversity_in(&state->demod, state->div_state); 10829a0bf528SMauro Carvalho Chehab 10839a0bf528SMauro Carvalho Chehab /* channel estimation fine configuration */ 10849a0bf528SMauro Carvalho Chehab switch (ch->modulation) { 10859a0bf528SMauro Carvalho Chehab case QAM_64: 10869a0bf528SMauro Carvalho Chehab est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ 10879a0bf528SMauro Carvalho Chehab est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ 10889a0bf528SMauro Carvalho Chehab est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ 10899a0bf528SMauro Carvalho Chehab est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ 10909a0bf528SMauro Carvalho Chehab break; 10919a0bf528SMauro Carvalho Chehab case QAM_16: 10929a0bf528SMauro Carvalho Chehab est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ 10939a0bf528SMauro Carvalho Chehab est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ 10949a0bf528SMauro Carvalho Chehab est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ 10959a0bf528SMauro Carvalho Chehab est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ 10969a0bf528SMauro Carvalho Chehab break; 10979a0bf528SMauro Carvalho Chehab default: 10989a0bf528SMauro Carvalho Chehab est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ 10999a0bf528SMauro Carvalho Chehab est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ 11009a0bf528SMauro Carvalho Chehab est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ 11019a0bf528SMauro Carvalho Chehab est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ 11029a0bf528SMauro Carvalho Chehab break; 11039a0bf528SMauro Carvalho Chehab } 11049a0bf528SMauro Carvalho Chehab for (value = 0; value < 4; value++) 11059a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 187 + value, est[value]); 11069a0bf528SMauro Carvalho Chehab } 11079a0bf528SMauro Carvalho Chehab 11089a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_start(struct dvb_frontend *demod) 11099a0bf528SMauro Carvalho Chehab { 11109a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch = &demod->dtv_property_cache; 11119a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 11129a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties schan; 11139a0bf528SMauro Carvalho Chehab u32 value, factor; 11149a0bf528SMauro Carvalho Chehab u32 internal = dib7000p_get_internal_freq(state); 11159a0bf528SMauro Carvalho Chehab 11169a0bf528SMauro Carvalho Chehab schan = *ch; 11179a0bf528SMauro Carvalho Chehab schan.modulation = QAM_64; 11189a0bf528SMauro Carvalho Chehab schan.guard_interval = GUARD_INTERVAL_1_32; 11199a0bf528SMauro Carvalho Chehab schan.transmission_mode = TRANSMISSION_MODE_8K; 11209a0bf528SMauro Carvalho Chehab schan.code_rate_HP = FEC_2_3; 11219a0bf528SMauro Carvalho Chehab schan.code_rate_LP = FEC_3_4; 11229a0bf528SMauro Carvalho Chehab schan.hierarchy = 0; 11239a0bf528SMauro Carvalho Chehab 11249a0bf528SMauro Carvalho Chehab dib7000p_set_channel(state, &schan, 7); 11259a0bf528SMauro Carvalho Chehab 11269a0bf528SMauro Carvalho Chehab factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz); 11279a0bf528SMauro Carvalho Chehab if (factor >= 5000) { 11289a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 11299a0bf528SMauro Carvalho Chehab factor = 2; 11309a0bf528SMauro Carvalho Chehab else 11319a0bf528SMauro Carvalho Chehab factor = 1; 11329a0bf528SMauro Carvalho Chehab } else 11339a0bf528SMauro Carvalho Chehab factor = 6; 11349a0bf528SMauro Carvalho Chehab 11359a0bf528SMauro Carvalho Chehab value = 30 * internal * factor; 11369a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); 11379a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 7, (u16) (value & 0xffff)); 11389a0bf528SMauro Carvalho Chehab value = 100 * internal * factor; 11399a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); 11409a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 9, (u16) (value & 0xffff)); 11419a0bf528SMauro Carvalho Chehab value = 500 * internal * factor; 11429a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); 11439a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 11, (u16) (value & 0xffff)); 11449a0bf528SMauro Carvalho Chehab 11459a0bf528SMauro Carvalho Chehab value = dib7000p_read_word(state, 0); 11469a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); 11479a0bf528SMauro Carvalho Chehab dib7000p_read_word(state, 1284); 11489a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0, (u16) value); 11499a0bf528SMauro Carvalho Chehab 11509a0bf528SMauro Carvalho Chehab return 0; 11519a0bf528SMauro Carvalho Chehab } 11529a0bf528SMauro Carvalho Chehab 11539a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) 11549a0bf528SMauro Carvalho Chehab { 11559a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 11569a0bf528SMauro Carvalho Chehab u16 irq_pending = dib7000p_read_word(state, 1284); 11579a0bf528SMauro Carvalho Chehab 11589a0bf528SMauro Carvalho Chehab if (irq_pending & 0x1) 11599a0bf528SMauro Carvalho Chehab return 1; 11609a0bf528SMauro Carvalho Chehab 11619a0bf528SMauro Carvalho Chehab if (irq_pending & 0x2) 11629a0bf528SMauro Carvalho Chehab return 2; 11639a0bf528SMauro Carvalho Chehab 11649a0bf528SMauro Carvalho Chehab return 0; 11659a0bf528SMauro Carvalho Chehab } 11669a0bf528SMauro Carvalho Chehab 11679a0bf528SMauro Carvalho Chehab static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) 11689a0bf528SMauro Carvalho Chehab { 11699a0bf528SMauro Carvalho Chehab static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 }; 11709a0bf528SMauro Carvalho Chehab static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, 11719a0bf528SMauro Carvalho Chehab 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, 11729a0bf528SMauro Carvalho Chehab 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, 11739a0bf528SMauro Carvalho Chehab 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, 11749a0bf528SMauro Carvalho Chehab 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, 11759a0bf528SMauro Carvalho Chehab 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, 11769a0bf528SMauro Carvalho Chehab 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, 11779a0bf528SMauro Carvalho Chehab 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, 11789a0bf528SMauro Carvalho Chehab 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 11799a0bf528SMauro Carvalho Chehab 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, 11809a0bf528SMauro Carvalho Chehab 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, 11819a0bf528SMauro Carvalho Chehab 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, 11829a0bf528SMauro Carvalho Chehab 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, 11839a0bf528SMauro Carvalho Chehab 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, 11849a0bf528SMauro Carvalho Chehab 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 11859a0bf528SMauro Carvalho Chehab 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11869a0bf528SMauro Carvalho Chehab 255, 255, 255, 255, 255, 255 11879a0bf528SMauro Carvalho Chehab }; 11889a0bf528SMauro Carvalho Chehab 11899a0bf528SMauro Carvalho Chehab u32 xtal = state->cfg.bw->xtal_hz / 1000; 11909a0bf528SMauro Carvalho Chehab int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz; 11919a0bf528SMauro Carvalho Chehab int k; 11929a0bf528SMauro Carvalho Chehab int coef_re[8], coef_im[8]; 11939a0bf528SMauro Carvalho Chehab int bw_khz = bw; 11949a0bf528SMauro Carvalho Chehab u32 pha; 11959a0bf528SMauro Carvalho Chehab 11969a0bf528SMauro Carvalho Chehab dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); 11979a0bf528SMauro Carvalho Chehab 11989a0bf528SMauro Carvalho Chehab if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2) 11999a0bf528SMauro Carvalho Chehab return; 12009a0bf528SMauro Carvalho Chehab 12019a0bf528SMauro Carvalho Chehab bw_khz /= 100; 12029a0bf528SMauro Carvalho Chehab 12039a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 142, 0x0610); 12049a0bf528SMauro Carvalho Chehab 12059a0bf528SMauro Carvalho Chehab for (k = 0; k < 8; k++) { 12069a0bf528SMauro Carvalho Chehab pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff; 12079a0bf528SMauro Carvalho Chehab 12089a0bf528SMauro Carvalho Chehab if (pha == 0) { 12099a0bf528SMauro Carvalho Chehab coef_re[k] = 256; 12109a0bf528SMauro Carvalho Chehab coef_im[k] = 0; 12119a0bf528SMauro Carvalho Chehab } else if (pha < 256) { 12129a0bf528SMauro Carvalho Chehab coef_re[k] = sine[256 - (pha & 0xff)]; 12139a0bf528SMauro Carvalho Chehab coef_im[k] = sine[pha & 0xff]; 12149a0bf528SMauro Carvalho Chehab } else if (pha == 256) { 12159a0bf528SMauro Carvalho Chehab coef_re[k] = 0; 12169a0bf528SMauro Carvalho Chehab coef_im[k] = 256; 12179a0bf528SMauro Carvalho Chehab } else if (pha < 512) { 12189a0bf528SMauro Carvalho Chehab coef_re[k] = -sine[pha & 0xff]; 12199a0bf528SMauro Carvalho Chehab coef_im[k] = sine[256 - (pha & 0xff)]; 12209a0bf528SMauro Carvalho Chehab } else if (pha == 512) { 12219a0bf528SMauro Carvalho Chehab coef_re[k] = -256; 12229a0bf528SMauro Carvalho Chehab coef_im[k] = 0; 12239a0bf528SMauro Carvalho Chehab } else if (pha < 768) { 12249a0bf528SMauro Carvalho Chehab coef_re[k] = -sine[256 - (pha & 0xff)]; 12259a0bf528SMauro Carvalho Chehab coef_im[k] = -sine[pha & 0xff]; 12269a0bf528SMauro Carvalho Chehab } else if (pha == 768) { 12279a0bf528SMauro Carvalho Chehab coef_re[k] = 0; 12289a0bf528SMauro Carvalho Chehab coef_im[k] = -256; 12299a0bf528SMauro Carvalho Chehab } else { 12309a0bf528SMauro Carvalho Chehab coef_re[k] = sine[pha & 0xff]; 12319a0bf528SMauro Carvalho Chehab coef_im[k] = -sine[256 - (pha & 0xff)]; 12329a0bf528SMauro Carvalho Chehab } 12339a0bf528SMauro Carvalho Chehab 12349a0bf528SMauro Carvalho Chehab coef_re[k] *= notch[k]; 12359a0bf528SMauro Carvalho Chehab coef_re[k] += (1 << 14); 12369a0bf528SMauro Carvalho Chehab if (coef_re[k] >= (1 << 24)) 12379a0bf528SMauro Carvalho Chehab coef_re[k] = (1 << 24) - 1; 12389a0bf528SMauro Carvalho Chehab coef_re[k] /= (1 << 15); 12399a0bf528SMauro Carvalho Chehab 12409a0bf528SMauro Carvalho Chehab coef_im[k] *= notch[k]; 12419a0bf528SMauro Carvalho Chehab coef_im[k] += (1 << 14); 12429a0bf528SMauro Carvalho Chehab if (coef_im[k] >= (1 << 24)) 12439a0bf528SMauro Carvalho Chehab coef_im[k] = (1 << 24) - 1; 12449a0bf528SMauro Carvalho Chehab coef_im[k] /= (1 << 15); 12459a0bf528SMauro Carvalho Chehab 12469a0bf528SMauro Carvalho Chehab dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); 12479a0bf528SMauro Carvalho Chehab 12489a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); 12499a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); 12509a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); 12519a0bf528SMauro Carvalho Chehab } 12529a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 143, 0); 12539a0bf528SMauro Carvalho Chehab } 12549a0bf528SMauro Carvalho Chehab 12559a0bf528SMauro Carvalho Chehab static int dib7000p_tune(struct dvb_frontend *demod) 12569a0bf528SMauro Carvalho Chehab { 12579a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch = &demod->dtv_property_cache; 12589a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 12599a0bf528SMauro Carvalho Chehab u16 tmp = 0; 12609a0bf528SMauro Carvalho Chehab 12619a0bf528SMauro Carvalho Chehab if (ch != NULL) 12629a0bf528SMauro Carvalho Chehab dib7000p_set_channel(state, ch, 0); 12639a0bf528SMauro Carvalho Chehab else 12649a0bf528SMauro Carvalho Chehab return -EINVAL; 12659a0bf528SMauro Carvalho Chehab 12669a0bf528SMauro Carvalho Chehab // restart demod 12679a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0x4000); 12689a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0x0000); 12699a0bf528SMauro Carvalho Chehab msleep(45); 12709a0bf528SMauro Carvalho Chehab 12719a0bf528SMauro Carvalho Chehab /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ 12729a0bf528SMauro Carvalho Chehab tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); 12739a0bf528SMauro Carvalho Chehab if (state->sfn_workaround_active) { 12749a0bf528SMauro Carvalho Chehab dprintk("SFN workaround is active"); 12759a0bf528SMauro Carvalho Chehab tmp |= (1 << 9); 12769a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 166, 0x4000); 12779a0bf528SMauro Carvalho Chehab } else { 12789a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 166, 0x0000); 12799a0bf528SMauro Carvalho Chehab } 12809a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 29, tmp); 12819a0bf528SMauro Carvalho Chehab 12829a0bf528SMauro Carvalho Chehab // never achieved a lock with that bandwidth so far - wait for osc-freq to update 12839a0bf528SMauro Carvalho Chehab if (state->timf == 0) 12849a0bf528SMauro Carvalho Chehab msleep(200); 12859a0bf528SMauro Carvalho Chehab 12869a0bf528SMauro Carvalho Chehab /* offset loop parameters */ 12879a0bf528SMauro Carvalho Chehab 12889a0bf528SMauro Carvalho Chehab /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ 12899a0bf528SMauro Carvalho Chehab tmp = (6 << 8) | 0x80; 12909a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) { 12919a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 12929a0bf528SMauro Carvalho Chehab tmp |= (2 << 12); 12939a0bf528SMauro Carvalho Chehab break; 12949a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 12959a0bf528SMauro Carvalho Chehab tmp |= (3 << 12); 12969a0bf528SMauro Carvalho Chehab break; 12979a0bf528SMauro Carvalho Chehab default: 12989a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 12999a0bf528SMauro Carvalho Chehab tmp |= (4 << 12); 13009a0bf528SMauro Carvalho Chehab break; 13019a0bf528SMauro Carvalho Chehab } 13029a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ 13039a0bf528SMauro Carvalho Chehab 13049a0bf528SMauro Carvalho Chehab /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ 13059a0bf528SMauro Carvalho Chehab tmp = (0 << 4); 13069a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) { 13079a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 13089a0bf528SMauro Carvalho Chehab tmp |= 0x6; 13099a0bf528SMauro Carvalho Chehab break; 13109a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 13119a0bf528SMauro Carvalho Chehab tmp |= 0x7; 13129a0bf528SMauro Carvalho Chehab break; 13139a0bf528SMauro Carvalho Chehab default: 13149a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 13159a0bf528SMauro Carvalho Chehab tmp |= 0x8; 13169a0bf528SMauro Carvalho Chehab break; 13179a0bf528SMauro Carvalho Chehab } 13189a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 32, tmp); 13199a0bf528SMauro Carvalho Chehab 13209a0bf528SMauro Carvalho Chehab /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ 13219a0bf528SMauro Carvalho Chehab tmp = (0 << 4); 13229a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) { 13239a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 13249a0bf528SMauro Carvalho Chehab tmp |= 0x6; 13259a0bf528SMauro Carvalho Chehab break; 13269a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 13279a0bf528SMauro Carvalho Chehab tmp |= 0x7; 13289a0bf528SMauro Carvalho Chehab break; 13299a0bf528SMauro Carvalho Chehab default: 13309a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 13319a0bf528SMauro Carvalho Chehab tmp |= 0x8; 13329a0bf528SMauro Carvalho Chehab break; 13339a0bf528SMauro Carvalho Chehab } 13349a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 33, tmp); 13359a0bf528SMauro Carvalho Chehab 13369a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 509); 13379a0bf528SMauro Carvalho Chehab if (!((tmp >> 6) & 0x1)) { 13389a0bf528SMauro Carvalho Chehab /* restart the fec */ 13399a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 771); 13409a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, tmp | (1 << 1)); 13419a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, tmp); 13429a0bf528SMauro Carvalho Chehab msleep(40); 13439a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 509); 13449a0bf528SMauro Carvalho Chehab } 13459a0bf528SMauro Carvalho Chehab // we achieved a lock - it's time to update the osc freq 13469a0bf528SMauro Carvalho Chehab if ((tmp >> 6) & 0x1) { 13479a0bf528SMauro Carvalho Chehab dib7000p_update_timf(state); 13489a0bf528SMauro Carvalho Chehab /* P_timf_alpha += 2 */ 13499a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 26); 13509a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12)); 13519a0bf528SMauro Carvalho Chehab } 13529a0bf528SMauro Carvalho Chehab 13539a0bf528SMauro Carvalho Chehab if (state->cfg.spur_protect) 13549a0bf528SMauro Carvalho Chehab dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); 13559a0bf528SMauro Carvalho Chehab 13569a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); 13579a0bf528SMauro Carvalho Chehab return 0; 13589a0bf528SMauro Carvalho Chehab } 13599a0bf528SMauro Carvalho Chehab 13609a0bf528SMauro Carvalho Chehab static int dib7000p_wakeup(struct dvb_frontend *demod) 13619a0bf528SMauro Carvalho Chehab { 13629a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 13639a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); 13649a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); 13659a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 13669a0bf528SMauro Carvalho Chehab dib7000p_sad_calib(state); 13679a0bf528SMauro Carvalho Chehab return 0; 13689a0bf528SMauro Carvalho Chehab } 13699a0bf528SMauro Carvalho Chehab 13709a0bf528SMauro Carvalho Chehab static int dib7000p_sleep(struct dvb_frontend *demod) 13719a0bf528SMauro Carvalho Chehab { 13729a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv; 13739a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 13749a0bf528SMauro Carvalho Chehab return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); 13759a0bf528SMauro Carvalho Chehab return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); 13769a0bf528SMauro Carvalho Chehab } 13779a0bf528SMauro Carvalho Chehab 13789a0bf528SMauro Carvalho Chehab static int dib7000p_identify(struct dib7000p_state *st) 13799a0bf528SMauro Carvalho Chehab { 13809a0bf528SMauro Carvalho Chehab u16 value; 13819a0bf528SMauro Carvalho Chehab dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); 13829a0bf528SMauro Carvalho Chehab 13839a0bf528SMauro Carvalho Chehab if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { 13849a0bf528SMauro Carvalho Chehab dprintk("wrong Vendor ID (read=0x%x)", value); 13859a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 13869a0bf528SMauro Carvalho Chehab } 13879a0bf528SMauro Carvalho Chehab 13889a0bf528SMauro Carvalho Chehab if ((value = dib7000p_read_word(st, 769)) != 0x4000) { 13899a0bf528SMauro Carvalho Chehab dprintk("wrong Device ID (%x)", value); 13909a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 13919a0bf528SMauro Carvalho Chehab } 13929a0bf528SMauro Carvalho Chehab 13939a0bf528SMauro Carvalho Chehab return 0; 13949a0bf528SMauro Carvalho Chehab } 13959a0bf528SMauro Carvalho Chehab 13969a0bf528SMauro Carvalho Chehab static int dib7000p_get_frontend(struct dvb_frontend *fe) 13979a0bf528SMauro Carvalho Chehab { 13989a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *fep = &fe->dtv_property_cache; 13999a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 14009a0bf528SMauro Carvalho Chehab u16 tps = dib7000p_read_word(state, 463); 14019a0bf528SMauro Carvalho Chehab 14029a0bf528SMauro Carvalho Chehab fep->inversion = INVERSION_AUTO; 14039a0bf528SMauro Carvalho Chehab 14049a0bf528SMauro Carvalho Chehab fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth); 14059a0bf528SMauro Carvalho Chehab 14069a0bf528SMauro Carvalho Chehab switch ((tps >> 8) & 0x3) { 14079a0bf528SMauro Carvalho Chehab case 0: 14089a0bf528SMauro Carvalho Chehab fep->transmission_mode = TRANSMISSION_MODE_2K; 14099a0bf528SMauro Carvalho Chehab break; 14109a0bf528SMauro Carvalho Chehab case 1: 14119a0bf528SMauro Carvalho Chehab fep->transmission_mode = TRANSMISSION_MODE_8K; 14129a0bf528SMauro Carvalho Chehab break; 14139a0bf528SMauro Carvalho Chehab /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */ 14149a0bf528SMauro Carvalho Chehab } 14159a0bf528SMauro Carvalho Chehab 14169a0bf528SMauro Carvalho Chehab switch (tps & 0x3) { 14179a0bf528SMauro Carvalho Chehab case 0: 14189a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_32; 14199a0bf528SMauro Carvalho Chehab break; 14209a0bf528SMauro Carvalho Chehab case 1: 14219a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_16; 14229a0bf528SMauro Carvalho Chehab break; 14239a0bf528SMauro Carvalho Chehab case 2: 14249a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_8; 14259a0bf528SMauro Carvalho Chehab break; 14269a0bf528SMauro Carvalho Chehab case 3: 14279a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_4; 14289a0bf528SMauro Carvalho Chehab break; 14299a0bf528SMauro Carvalho Chehab } 14309a0bf528SMauro Carvalho Chehab 14319a0bf528SMauro Carvalho Chehab switch ((tps >> 14) & 0x3) { 14329a0bf528SMauro Carvalho Chehab case 0: 14339a0bf528SMauro Carvalho Chehab fep->modulation = QPSK; 14349a0bf528SMauro Carvalho Chehab break; 14359a0bf528SMauro Carvalho Chehab case 1: 14369a0bf528SMauro Carvalho Chehab fep->modulation = QAM_16; 14379a0bf528SMauro Carvalho Chehab break; 14389a0bf528SMauro Carvalho Chehab case 2: 14399a0bf528SMauro Carvalho Chehab default: 14409a0bf528SMauro Carvalho Chehab fep->modulation = QAM_64; 14419a0bf528SMauro Carvalho Chehab break; 14429a0bf528SMauro Carvalho Chehab } 14439a0bf528SMauro Carvalho Chehab 14449a0bf528SMauro Carvalho Chehab /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ 14459a0bf528SMauro Carvalho Chehab /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ 14469a0bf528SMauro Carvalho Chehab 14479a0bf528SMauro Carvalho Chehab fep->hierarchy = HIERARCHY_NONE; 14489a0bf528SMauro Carvalho Chehab switch ((tps >> 5) & 0x7) { 14499a0bf528SMauro Carvalho Chehab case 1: 14509a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_1_2; 14519a0bf528SMauro Carvalho Chehab break; 14529a0bf528SMauro Carvalho Chehab case 2: 14539a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_2_3; 14549a0bf528SMauro Carvalho Chehab break; 14559a0bf528SMauro Carvalho Chehab case 3: 14569a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_3_4; 14579a0bf528SMauro Carvalho Chehab break; 14589a0bf528SMauro Carvalho Chehab case 5: 14599a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_5_6; 14609a0bf528SMauro Carvalho Chehab break; 14619a0bf528SMauro Carvalho Chehab case 7: 14629a0bf528SMauro Carvalho Chehab default: 14639a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_7_8; 14649a0bf528SMauro Carvalho Chehab break; 14659a0bf528SMauro Carvalho Chehab 14669a0bf528SMauro Carvalho Chehab } 14679a0bf528SMauro Carvalho Chehab 14689a0bf528SMauro Carvalho Chehab switch ((tps >> 2) & 0x7) { 14699a0bf528SMauro Carvalho Chehab case 1: 14709a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_1_2; 14719a0bf528SMauro Carvalho Chehab break; 14729a0bf528SMauro Carvalho Chehab case 2: 14739a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_2_3; 14749a0bf528SMauro Carvalho Chehab break; 14759a0bf528SMauro Carvalho Chehab case 3: 14769a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_3_4; 14779a0bf528SMauro Carvalho Chehab break; 14789a0bf528SMauro Carvalho Chehab case 5: 14799a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_5_6; 14809a0bf528SMauro Carvalho Chehab break; 14819a0bf528SMauro Carvalho Chehab case 7: 14829a0bf528SMauro Carvalho Chehab default: 14839a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_7_8; 14849a0bf528SMauro Carvalho Chehab break; 14859a0bf528SMauro Carvalho Chehab } 14869a0bf528SMauro Carvalho Chehab 14879a0bf528SMauro Carvalho Chehab /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */ 14889a0bf528SMauro Carvalho Chehab 14899a0bf528SMauro Carvalho Chehab return 0; 14909a0bf528SMauro Carvalho Chehab } 14919a0bf528SMauro Carvalho Chehab 14929a0bf528SMauro Carvalho Chehab static int dib7000p_set_frontend(struct dvb_frontend *fe) 14939a0bf528SMauro Carvalho Chehab { 14949a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *fep = &fe->dtv_property_cache; 14959a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 14969a0bf528SMauro Carvalho Chehab int time, ret; 14979a0bf528SMauro Carvalho Chehab 14989a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) 14999a0bf528SMauro Carvalho Chehab dib7090_set_diversity_in(fe, 0); 15009a0bf528SMauro Carvalho Chehab else 15019a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); 15029a0bf528SMauro Carvalho Chehab 15039a0bf528SMauro Carvalho Chehab /* maybe the parameter has been changed */ 15049a0bf528SMauro Carvalho Chehab state->sfn_workaround_active = buggy_sfn_workaround; 15059a0bf528SMauro Carvalho Chehab 15069a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) 15079a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 15089a0bf528SMauro Carvalho Chehab 15099a0bf528SMauro Carvalho Chehab /* start up the AGC */ 15109a0bf528SMauro Carvalho Chehab state->agc_state = 0; 15119a0bf528SMauro Carvalho Chehab do { 15129a0bf528SMauro Carvalho Chehab time = dib7000p_agc_startup(fe); 15139a0bf528SMauro Carvalho Chehab if (time != -1) 15149a0bf528SMauro Carvalho Chehab msleep(time); 15159a0bf528SMauro Carvalho Chehab } while (time != -1); 15169a0bf528SMauro Carvalho Chehab 15179a0bf528SMauro Carvalho Chehab if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || 15189a0bf528SMauro Carvalho Chehab fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) { 15199a0bf528SMauro Carvalho Chehab int i = 800, found; 15209a0bf528SMauro Carvalho Chehab 15219a0bf528SMauro Carvalho Chehab dib7000p_autosearch_start(fe); 15229a0bf528SMauro Carvalho Chehab do { 15239a0bf528SMauro Carvalho Chehab msleep(1); 15249a0bf528SMauro Carvalho Chehab found = dib7000p_autosearch_is_irq(fe); 15259a0bf528SMauro Carvalho Chehab } while (found == 0 && i--); 15269a0bf528SMauro Carvalho Chehab 15279a0bf528SMauro Carvalho Chehab dprintk("autosearch returns: %d", found); 15289a0bf528SMauro Carvalho Chehab if (found == 0 || found == 1) 15299a0bf528SMauro Carvalho Chehab return 0; 15309a0bf528SMauro Carvalho Chehab 15319a0bf528SMauro Carvalho Chehab dib7000p_get_frontend(fe); 15329a0bf528SMauro Carvalho Chehab } 15339a0bf528SMauro Carvalho Chehab 15349a0bf528SMauro Carvalho Chehab ret = dib7000p_tune(fe); 15359a0bf528SMauro Carvalho Chehab 15369a0bf528SMauro Carvalho Chehab /* make this a config parameter */ 15379a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) { 15389a0bf528SMauro Carvalho Chehab dib7090_set_output_mode(fe, state->cfg.output_mode); 15399a0bf528SMauro Carvalho Chehab if (state->cfg.enMpegOutput == 0) { 15409a0bf528SMauro Carvalho Chehab dib7090_setDibTxMux(state, MPEG_ON_DIBTX); 15419a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); 15429a0bf528SMauro Carvalho Chehab } 15439a0bf528SMauro Carvalho Chehab } else 15449a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(state, state->cfg.output_mode); 15459a0bf528SMauro Carvalho Chehab 15469a0bf528SMauro Carvalho Chehab return ret; 15479a0bf528SMauro Carvalho Chehab } 15489a0bf528SMauro Carvalho Chehab 15499a0bf528SMauro Carvalho Chehab static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat) 15509a0bf528SMauro Carvalho Chehab { 15519a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 15529a0bf528SMauro Carvalho Chehab u16 lock = dib7000p_read_word(state, 509); 15539a0bf528SMauro Carvalho Chehab 15549a0bf528SMauro Carvalho Chehab *stat = 0; 15559a0bf528SMauro Carvalho Chehab 15569a0bf528SMauro Carvalho Chehab if (lock & 0x8000) 15579a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SIGNAL; 15589a0bf528SMauro Carvalho Chehab if (lock & 0x3000) 15599a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_CARRIER; 15609a0bf528SMauro Carvalho Chehab if (lock & 0x0100) 15619a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 15629a0bf528SMauro Carvalho Chehab if (lock & 0x0010) 15639a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SYNC; 15649a0bf528SMauro Carvalho Chehab if ((lock & 0x0038) == 0x38) 15659a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_LOCK; 15669a0bf528SMauro Carvalho Chehab 15679a0bf528SMauro Carvalho Chehab return 0; 15689a0bf528SMauro Carvalho Chehab } 15699a0bf528SMauro Carvalho Chehab 15709a0bf528SMauro Carvalho Chehab static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber) 15719a0bf528SMauro Carvalho Chehab { 15729a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 15739a0bf528SMauro Carvalho Chehab *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501); 15749a0bf528SMauro Carvalho Chehab return 0; 15759a0bf528SMauro Carvalho Chehab } 15769a0bf528SMauro Carvalho Chehab 15779a0bf528SMauro Carvalho Chehab static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) 15789a0bf528SMauro Carvalho Chehab { 15799a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 15809a0bf528SMauro Carvalho Chehab *unc = dib7000p_read_word(state, 506); 15819a0bf528SMauro Carvalho Chehab return 0; 15829a0bf528SMauro Carvalho Chehab } 15839a0bf528SMauro Carvalho Chehab 15849a0bf528SMauro Carvalho Chehab static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 15859a0bf528SMauro Carvalho Chehab { 15869a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 15879a0bf528SMauro Carvalho Chehab u16 val = dib7000p_read_word(state, 394); 15889a0bf528SMauro Carvalho Chehab *strength = 65535 - val; 15899a0bf528SMauro Carvalho Chehab return 0; 15909a0bf528SMauro Carvalho Chehab } 15919a0bf528SMauro Carvalho Chehab 15929a0bf528SMauro Carvalho Chehab static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr) 15939a0bf528SMauro Carvalho Chehab { 15949a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 15959a0bf528SMauro Carvalho Chehab u16 val; 15969a0bf528SMauro Carvalho Chehab s32 signal_mant, signal_exp, noise_mant, noise_exp; 15979a0bf528SMauro Carvalho Chehab u32 result = 0; 15989a0bf528SMauro Carvalho Chehab 15999a0bf528SMauro Carvalho Chehab val = dib7000p_read_word(state, 479); 16009a0bf528SMauro Carvalho Chehab noise_mant = (val >> 4) & 0xff; 16019a0bf528SMauro Carvalho Chehab noise_exp = ((val & 0xf) << 2); 16029a0bf528SMauro Carvalho Chehab val = dib7000p_read_word(state, 480); 16039a0bf528SMauro Carvalho Chehab noise_exp += ((val >> 14) & 0x3); 16049a0bf528SMauro Carvalho Chehab if ((noise_exp & 0x20) != 0) 16059a0bf528SMauro Carvalho Chehab noise_exp -= 0x40; 16069a0bf528SMauro Carvalho Chehab 16079a0bf528SMauro Carvalho Chehab signal_mant = (val >> 6) & 0xFF; 16089a0bf528SMauro Carvalho Chehab signal_exp = (val & 0x3F); 16099a0bf528SMauro Carvalho Chehab if ((signal_exp & 0x20) != 0) 16109a0bf528SMauro Carvalho Chehab signal_exp -= 0x40; 16119a0bf528SMauro Carvalho Chehab 16129a0bf528SMauro Carvalho Chehab if (signal_mant != 0) 16139a0bf528SMauro Carvalho Chehab result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant); 16149a0bf528SMauro Carvalho Chehab else 16159a0bf528SMauro Carvalho Chehab result = intlog10(2) * 10 * signal_exp - 100; 16169a0bf528SMauro Carvalho Chehab 16179a0bf528SMauro Carvalho Chehab if (noise_mant != 0) 16189a0bf528SMauro Carvalho Chehab result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant); 16199a0bf528SMauro Carvalho Chehab else 16209a0bf528SMauro Carvalho Chehab result -= intlog10(2) * 10 * noise_exp - 100; 16219a0bf528SMauro Carvalho Chehab 16229a0bf528SMauro Carvalho Chehab *snr = result / ((1 << 24) / 10); 16239a0bf528SMauro Carvalho Chehab return 0; 16249a0bf528SMauro Carvalho Chehab } 16259a0bf528SMauro Carvalho Chehab 16269a0bf528SMauro Carvalho Chehab static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) 16279a0bf528SMauro Carvalho Chehab { 16289a0bf528SMauro Carvalho Chehab tune->min_delay_ms = 1000; 16299a0bf528SMauro Carvalho Chehab return 0; 16309a0bf528SMauro Carvalho Chehab } 16319a0bf528SMauro Carvalho Chehab 16329a0bf528SMauro Carvalho Chehab static void dib7000p_release(struct dvb_frontend *demod) 16339a0bf528SMauro Carvalho Chehab { 16349a0bf528SMauro Carvalho Chehab struct dib7000p_state *st = demod->demodulator_priv; 16359a0bf528SMauro Carvalho Chehab dibx000_exit_i2c_master(&st->i2c_master); 16369a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->dib7090_tuner_adap); 16379a0bf528SMauro Carvalho Chehab kfree(st); 16389a0bf528SMauro Carvalho Chehab } 16399a0bf528SMauro Carvalho Chehab 1640*8abe4a0aSMauro Carvalho Chehab static int dib7000pc_detection(struct i2c_adapter *i2c_adap) 16419a0bf528SMauro Carvalho Chehab { 16429a0bf528SMauro Carvalho Chehab u8 *tx, *rx; 16439a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2] = { 16449a0bf528SMauro Carvalho Chehab {.addr = 18 >> 1, .flags = 0, .len = 2}, 16459a0bf528SMauro Carvalho Chehab {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2}, 16469a0bf528SMauro Carvalho Chehab }; 16479a0bf528SMauro Carvalho Chehab int ret = 0; 16489a0bf528SMauro Carvalho Chehab 16499a0bf528SMauro Carvalho Chehab tx = kzalloc(2*sizeof(u8), GFP_KERNEL); 16509a0bf528SMauro Carvalho Chehab if (!tx) 16519a0bf528SMauro Carvalho Chehab return -ENOMEM; 16529a0bf528SMauro Carvalho Chehab rx = kzalloc(2*sizeof(u8), GFP_KERNEL); 16539a0bf528SMauro Carvalho Chehab if (!rx) { 16549a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 16559a0bf528SMauro Carvalho Chehab goto rx_memory_error; 16569a0bf528SMauro Carvalho Chehab } 16579a0bf528SMauro Carvalho Chehab 16589a0bf528SMauro Carvalho Chehab msg[0].buf = tx; 16599a0bf528SMauro Carvalho Chehab msg[1].buf = rx; 16609a0bf528SMauro Carvalho Chehab 16619a0bf528SMauro Carvalho Chehab tx[0] = 0x03; 16629a0bf528SMauro Carvalho Chehab tx[1] = 0x00; 16639a0bf528SMauro Carvalho Chehab 16649a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c_adap, msg, 2) == 2) 16659a0bf528SMauro Carvalho Chehab if (rx[0] == 0x01 && rx[1] == 0xb3) { 16669a0bf528SMauro Carvalho Chehab dprintk("-D- DiB7000PC detected"); 16679a0bf528SMauro Carvalho Chehab return 1; 16689a0bf528SMauro Carvalho Chehab } 16699a0bf528SMauro Carvalho Chehab 16709a0bf528SMauro Carvalho Chehab msg[0].addr = msg[1].addr = 0x40; 16719a0bf528SMauro Carvalho Chehab 16729a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c_adap, msg, 2) == 2) 16739a0bf528SMauro Carvalho Chehab if (rx[0] == 0x01 && rx[1] == 0xb3) { 16749a0bf528SMauro Carvalho Chehab dprintk("-D- DiB7000PC detected"); 16759a0bf528SMauro Carvalho Chehab return 1; 16769a0bf528SMauro Carvalho Chehab } 16779a0bf528SMauro Carvalho Chehab 16789a0bf528SMauro Carvalho Chehab dprintk("-D- DiB7000PC not detected"); 16799a0bf528SMauro Carvalho Chehab 16809a0bf528SMauro Carvalho Chehab kfree(rx); 16819a0bf528SMauro Carvalho Chehab rx_memory_error: 16829a0bf528SMauro Carvalho Chehab kfree(tx); 16839a0bf528SMauro Carvalho Chehab return ret; 16849a0bf528SMauro Carvalho Chehab } 16859a0bf528SMauro Carvalho Chehab 1686*8abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) 16879a0bf528SMauro Carvalho Chehab { 16889a0bf528SMauro Carvalho Chehab struct dib7000p_state *st = demod->demodulator_priv; 16899a0bf528SMauro Carvalho Chehab return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); 16909a0bf528SMauro Carvalho Chehab } 16919a0bf528SMauro Carvalho Chehab 1692*8abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) 16939a0bf528SMauro Carvalho Chehab { 16949a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 16959a0bf528SMauro Carvalho Chehab u16 val = dib7000p_read_word(state, 235) & 0xffef; 16969a0bf528SMauro Carvalho Chehab val |= (onoff & 0x1) << 4; 16979a0bf528SMauro Carvalho Chehab dprintk("PID filter enabled %d", onoff); 16989a0bf528SMauro Carvalho Chehab return dib7000p_write_word(state, 235, val); 16999a0bf528SMauro Carvalho Chehab } 17009a0bf528SMauro Carvalho Chehab 1701*8abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) 17029a0bf528SMauro Carvalho Chehab { 17039a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 17049a0bf528SMauro Carvalho Chehab dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); 17059a0bf528SMauro Carvalho Chehab return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0); 17069a0bf528SMauro Carvalho Chehab } 17079a0bf528SMauro Carvalho Chehab 1708*8abe4a0aSMauro Carvalho Chehab static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) 17099a0bf528SMauro Carvalho Chehab { 17109a0bf528SMauro Carvalho Chehab struct dib7000p_state *dpst; 17119a0bf528SMauro Carvalho Chehab int k = 0; 17129a0bf528SMauro Carvalho Chehab u8 new_addr = 0; 17139a0bf528SMauro Carvalho Chehab 17149a0bf528SMauro Carvalho Chehab dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL); 17159a0bf528SMauro Carvalho Chehab if (!dpst) 17169a0bf528SMauro Carvalho Chehab return -ENOMEM; 17179a0bf528SMauro Carvalho Chehab 17189a0bf528SMauro Carvalho Chehab dpst->i2c_adap = i2c; 17199a0bf528SMauro Carvalho Chehab mutex_init(&dpst->i2c_buffer_lock); 17209a0bf528SMauro Carvalho Chehab 17219a0bf528SMauro Carvalho Chehab for (k = no_of_demods - 1; k >= 0; k--) { 17229a0bf528SMauro Carvalho Chehab dpst->cfg = cfg[k]; 17239a0bf528SMauro Carvalho Chehab 17249a0bf528SMauro Carvalho Chehab /* designated i2c address */ 17259a0bf528SMauro Carvalho Chehab if (cfg[k].default_i2c_addr != 0) 17269a0bf528SMauro Carvalho Chehab new_addr = cfg[k].default_i2c_addr + (k << 1); 17279a0bf528SMauro Carvalho Chehab else 17289a0bf528SMauro Carvalho Chehab new_addr = (0x40 + k) << 1; 17299a0bf528SMauro Carvalho Chehab dpst->i2c_addr = new_addr; 17309a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ 17319a0bf528SMauro Carvalho Chehab if (dib7000p_identify(dpst) != 0) { 17329a0bf528SMauro Carvalho Chehab dpst->i2c_addr = default_addr; 17339a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ 17349a0bf528SMauro Carvalho Chehab if (dib7000p_identify(dpst) != 0) { 17359a0bf528SMauro Carvalho Chehab dprintk("DiB7000P #%d: not identified\n", k); 17369a0bf528SMauro Carvalho Chehab kfree(dpst); 17379a0bf528SMauro Carvalho Chehab return -EIO; 17389a0bf528SMauro Carvalho Chehab } 17399a0bf528SMauro Carvalho Chehab } 17409a0bf528SMauro Carvalho Chehab 17419a0bf528SMauro Carvalho Chehab /* start diversity to pull_down div_str - just for i2c-enumeration */ 17429a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY); 17439a0bf528SMauro Carvalho Chehab 17449a0bf528SMauro Carvalho Chehab /* set new i2c address and force divstart */ 17459a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2); 17469a0bf528SMauro Carvalho Chehab 17479a0bf528SMauro Carvalho Chehab dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); 17489a0bf528SMauro Carvalho Chehab } 17499a0bf528SMauro Carvalho Chehab 17509a0bf528SMauro Carvalho Chehab for (k = 0; k < no_of_demods; k++) { 17519a0bf528SMauro Carvalho Chehab dpst->cfg = cfg[k]; 17529a0bf528SMauro Carvalho Chehab if (cfg[k].default_i2c_addr != 0) 17539a0bf528SMauro Carvalho Chehab dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1; 17549a0bf528SMauro Carvalho Chehab else 17559a0bf528SMauro Carvalho Chehab dpst->i2c_addr = (0x40 + k) << 1; 17569a0bf528SMauro Carvalho Chehab 17579a0bf528SMauro Carvalho Chehab // unforce divstr 17589a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2); 17599a0bf528SMauro Carvalho Chehab 17609a0bf528SMauro Carvalho Chehab /* deactivate div - it was just for i2c-enumeration */ 17619a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z); 17629a0bf528SMauro Carvalho Chehab } 17639a0bf528SMauro Carvalho Chehab 17649a0bf528SMauro Carvalho Chehab kfree(dpst); 17659a0bf528SMauro Carvalho Chehab return 0; 17669a0bf528SMauro Carvalho Chehab } 17679a0bf528SMauro Carvalho Chehab 17689a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = { 17699a0bf528SMauro Carvalho Chehab 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600 17709a0bf528SMauro Carvalho Chehab }; 17719a0bf528SMauro Carvalho Chehab 17729a0bf528SMauro Carvalho Chehab static s32 dib7000p_get_adc_power(struct dvb_frontend *fe) 17739a0bf528SMauro Carvalho Chehab { 17749a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 17759a0bf528SMauro Carvalho Chehab u32 tmp_val = 0, exp = 0, mant = 0; 17769a0bf528SMauro Carvalho Chehab s32 pow_i; 17779a0bf528SMauro Carvalho Chehab u16 buf[2]; 17789a0bf528SMauro Carvalho Chehab u8 ix = 0; 17799a0bf528SMauro Carvalho Chehab 17809a0bf528SMauro Carvalho Chehab buf[0] = dib7000p_read_word(state, 0x184); 17819a0bf528SMauro Carvalho Chehab buf[1] = dib7000p_read_word(state, 0x185); 17829a0bf528SMauro Carvalho Chehab pow_i = (buf[0] << 16) | buf[1]; 17839a0bf528SMauro Carvalho Chehab dprintk("raw pow_i = %d", pow_i); 17849a0bf528SMauro Carvalho Chehab 17859a0bf528SMauro Carvalho Chehab tmp_val = pow_i; 17869a0bf528SMauro Carvalho Chehab while (tmp_val >>= 1) 17879a0bf528SMauro Carvalho Chehab exp++; 17889a0bf528SMauro Carvalho Chehab 17899a0bf528SMauro Carvalho Chehab mant = (pow_i * 1000 / (1 << exp)); 17909a0bf528SMauro Carvalho Chehab dprintk(" mant = %d exp = %d", mant / 1000, exp); 17919a0bf528SMauro Carvalho Chehab 17929a0bf528SMauro Carvalho Chehab ix = (u8) ((mant - 1000) / 100); /* index of the LUT */ 17939a0bf528SMauro Carvalho Chehab dprintk(" ix = %d", ix); 17949a0bf528SMauro Carvalho Chehab 17959a0bf528SMauro Carvalho Chehab pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908); 17969a0bf528SMauro Carvalho Chehab pow_i = (pow_i << 8) / 1000; 17979a0bf528SMauro Carvalho Chehab dprintk(" pow_i = %d", pow_i); 17989a0bf528SMauro Carvalho Chehab 17999a0bf528SMauro Carvalho Chehab return pow_i; 18009a0bf528SMauro Carvalho Chehab } 18019a0bf528SMauro Carvalho Chehab 18029a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg) 18039a0bf528SMauro Carvalho Chehab { 18049a0bf528SMauro Carvalho Chehab if ((msg->buf[0] <= 15)) 18059a0bf528SMauro Carvalho Chehab msg->buf[0] -= 1; 18069a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 17) 18079a0bf528SMauro Carvalho Chehab msg->buf[0] = 15; 18089a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 16) 18099a0bf528SMauro Carvalho Chehab msg->buf[0] = 17; 18109a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 19) 18119a0bf528SMauro Carvalho Chehab msg->buf[0] = 16; 18129a0bf528SMauro Carvalho Chehab else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) 18139a0bf528SMauro Carvalho Chehab msg->buf[0] -= 3; 18149a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 28) 18159a0bf528SMauro Carvalho Chehab msg->buf[0] = 23; 18169a0bf528SMauro Carvalho Chehab else 18179a0bf528SMauro Carvalho Chehab return -EINVAL; 18189a0bf528SMauro Carvalho Chehab return 0; 18199a0bf528SMauro Carvalho Chehab } 18209a0bf528SMauro Carvalho Chehab 18219a0bf528SMauro Carvalho Chehab static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 18229a0bf528SMauro Carvalho Chehab { 18239a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); 18249a0bf528SMauro Carvalho Chehab u8 n_overflow = 1; 18259a0bf528SMauro Carvalho Chehab u16 i = 1000; 18269a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 18279a0bf528SMauro Carvalho Chehab 18289a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 18299a0bf528SMauro Carvalho Chehab n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; 18309a0bf528SMauro Carvalho Chehab i--; 18319a0bf528SMauro Carvalho Chehab if (i == 0) 18329a0bf528SMauro Carvalho Chehab dprintk("Tuner ITF: write busy (overflow)"); 18339a0bf528SMauro Carvalho Chehab } 18349a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); 18359a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); 18369a0bf528SMauro Carvalho Chehab 18379a0bf528SMauro Carvalho Chehab return num; 18389a0bf528SMauro Carvalho Chehab } 18399a0bf528SMauro Carvalho Chehab 18409a0bf528SMauro Carvalho Chehab static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 18419a0bf528SMauro Carvalho Chehab { 18429a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); 18439a0bf528SMauro Carvalho Chehab u8 n_overflow = 1, n_empty = 1; 18449a0bf528SMauro Carvalho Chehab u16 i = 1000; 18459a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0]; 18469a0bf528SMauro Carvalho Chehab u16 read_word; 18479a0bf528SMauro Carvalho Chehab 18489a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) { 18499a0bf528SMauro Carvalho Chehab n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; 18509a0bf528SMauro Carvalho Chehab i--; 18519a0bf528SMauro Carvalho Chehab if (i == 0) 18529a0bf528SMauro Carvalho Chehab dprintk("TunerITF: read busy (overflow)"); 18539a0bf528SMauro Carvalho Chehab } 18549a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f)); 18559a0bf528SMauro Carvalho Chehab 18569a0bf528SMauro Carvalho Chehab i = 1000; 18579a0bf528SMauro Carvalho Chehab while (n_empty == 1 && i) { 18589a0bf528SMauro Carvalho Chehab n_empty = dib7000p_read_word(state, 1984) & 0x1; 18599a0bf528SMauro Carvalho Chehab i--; 18609a0bf528SMauro Carvalho Chehab if (i == 0) 18619a0bf528SMauro Carvalho Chehab dprintk("TunerITF: read busy (empty)"); 18629a0bf528SMauro Carvalho Chehab } 18639a0bf528SMauro Carvalho Chehab read_word = dib7000p_read_word(state, 1987); 18649a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (read_word >> 8) & 0xff; 18659a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (read_word) & 0xff; 18669a0bf528SMauro Carvalho Chehab 18679a0bf528SMauro Carvalho Chehab return num; 18689a0bf528SMauro Carvalho Chehab } 18699a0bf528SMauro Carvalho Chehab 18709a0bf528SMauro Carvalho Chehab static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 18719a0bf528SMauro Carvalho Chehab { 18729a0bf528SMauro Carvalho Chehab if (map_addr_to_serpar_number(&msg[0]) == 0) { /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */ 18739a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 18749a0bf528SMauro Carvalho Chehab return w7090p_tuner_write_serpar(i2c_adap, msg, 1); 18759a0bf528SMauro Carvalho Chehab } else { /* read */ 18769a0bf528SMauro Carvalho Chehab return w7090p_tuner_read_serpar(i2c_adap, msg, 2); 18779a0bf528SMauro Carvalho Chehab } 18789a0bf528SMauro Carvalho Chehab } 18799a0bf528SMauro Carvalho Chehab return num; 18809a0bf528SMauro Carvalho Chehab } 18819a0bf528SMauro Carvalho Chehab 18829a0bf528SMauro Carvalho Chehab static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, 18839a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num, u16 apb_address) 18849a0bf528SMauro Carvalho Chehab { 18859a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); 18869a0bf528SMauro Carvalho Chehab u16 word; 18879a0bf528SMauro Carvalho Chehab 18889a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 18899a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); 18909a0bf528SMauro Carvalho Chehab } else { 18919a0bf528SMauro Carvalho Chehab word = dib7000p_read_word(state, apb_address); 18929a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 18939a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 18949a0bf528SMauro Carvalho Chehab } 18959a0bf528SMauro Carvalho Chehab 18969a0bf528SMauro Carvalho Chehab return num; 18979a0bf528SMauro Carvalho Chehab } 18989a0bf528SMauro Carvalho Chehab 18999a0bf528SMauro Carvalho Chehab static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 19009a0bf528SMauro Carvalho Chehab { 19019a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); 19029a0bf528SMauro Carvalho Chehab 19039a0bf528SMauro Carvalho Chehab u16 apb_address = 0, word; 19049a0bf528SMauro Carvalho Chehab int i = 0; 19059a0bf528SMauro Carvalho Chehab switch (msg[0].buf[0]) { 19069a0bf528SMauro Carvalho Chehab case 0x12: 19079a0bf528SMauro Carvalho Chehab apb_address = 1920; 19089a0bf528SMauro Carvalho Chehab break; 19099a0bf528SMauro Carvalho Chehab case 0x14: 19109a0bf528SMauro Carvalho Chehab apb_address = 1921; 19119a0bf528SMauro Carvalho Chehab break; 19129a0bf528SMauro Carvalho Chehab case 0x24: 19139a0bf528SMauro Carvalho Chehab apb_address = 1922; 19149a0bf528SMauro Carvalho Chehab break; 19159a0bf528SMauro Carvalho Chehab case 0x1a: 19169a0bf528SMauro Carvalho Chehab apb_address = 1923; 19179a0bf528SMauro Carvalho Chehab break; 19189a0bf528SMauro Carvalho Chehab case 0x22: 19199a0bf528SMauro Carvalho Chehab apb_address = 1924; 19209a0bf528SMauro Carvalho Chehab break; 19219a0bf528SMauro Carvalho Chehab case 0x33: 19229a0bf528SMauro Carvalho Chehab apb_address = 1926; 19239a0bf528SMauro Carvalho Chehab break; 19249a0bf528SMauro Carvalho Chehab case 0x34: 19259a0bf528SMauro Carvalho Chehab apb_address = 1927; 19269a0bf528SMauro Carvalho Chehab break; 19279a0bf528SMauro Carvalho Chehab case 0x35: 19289a0bf528SMauro Carvalho Chehab apb_address = 1928; 19299a0bf528SMauro Carvalho Chehab break; 19309a0bf528SMauro Carvalho Chehab case 0x36: 19319a0bf528SMauro Carvalho Chehab apb_address = 1929; 19329a0bf528SMauro Carvalho Chehab break; 19339a0bf528SMauro Carvalho Chehab case 0x37: 19349a0bf528SMauro Carvalho Chehab apb_address = 1930; 19359a0bf528SMauro Carvalho Chehab break; 19369a0bf528SMauro Carvalho Chehab case 0x38: 19379a0bf528SMauro Carvalho Chehab apb_address = 1931; 19389a0bf528SMauro Carvalho Chehab break; 19399a0bf528SMauro Carvalho Chehab case 0x39: 19409a0bf528SMauro Carvalho Chehab apb_address = 1932; 19419a0bf528SMauro Carvalho Chehab break; 19429a0bf528SMauro Carvalho Chehab case 0x2a: 19439a0bf528SMauro Carvalho Chehab apb_address = 1935; 19449a0bf528SMauro Carvalho Chehab break; 19459a0bf528SMauro Carvalho Chehab case 0x2b: 19469a0bf528SMauro Carvalho Chehab apb_address = 1936; 19479a0bf528SMauro Carvalho Chehab break; 19489a0bf528SMauro Carvalho Chehab case 0x2c: 19499a0bf528SMauro Carvalho Chehab apb_address = 1937; 19509a0bf528SMauro Carvalho Chehab break; 19519a0bf528SMauro Carvalho Chehab case 0x2d: 19529a0bf528SMauro Carvalho Chehab apb_address = 1938; 19539a0bf528SMauro Carvalho Chehab break; 19549a0bf528SMauro Carvalho Chehab case 0x2e: 19559a0bf528SMauro Carvalho Chehab apb_address = 1939; 19569a0bf528SMauro Carvalho Chehab break; 19579a0bf528SMauro Carvalho Chehab case 0x2f: 19589a0bf528SMauro Carvalho Chehab apb_address = 1940; 19599a0bf528SMauro Carvalho Chehab break; 19609a0bf528SMauro Carvalho Chehab case 0x30: 19619a0bf528SMauro Carvalho Chehab apb_address = 1941; 19629a0bf528SMauro Carvalho Chehab break; 19639a0bf528SMauro Carvalho Chehab case 0x31: 19649a0bf528SMauro Carvalho Chehab apb_address = 1942; 19659a0bf528SMauro Carvalho Chehab break; 19669a0bf528SMauro Carvalho Chehab case 0x32: 19679a0bf528SMauro Carvalho Chehab apb_address = 1943; 19689a0bf528SMauro Carvalho Chehab break; 19699a0bf528SMauro Carvalho Chehab case 0x3e: 19709a0bf528SMauro Carvalho Chehab apb_address = 1944; 19719a0bf528SMauro Carvalho Chehab break; 19729a0bf528SMauro Carvalho Chehab case 0x3f: 19739a0bf528SMauro Carvalho Chehab apb_address = 1945; 19749a0bf528SMauro Carvalho Chehab break; 19759a0bf528SMauro Carvalho Chehab case 0x40: 19769a0bf528SMauro Carvalho Chehab apb_address = 1948; 19779a0bf528SMauro Carvalho Chehab break; 19789a0bf528SMauro Carvalho Chehab case 0x25: 19799a0bf528SMauro Carvalho Chehab apb_address = 914; 19809a0bf528SMauro Carvalho Chehab break; 19819a0bf528SMauro Carvalho Chehab case 0x26: 19829a0bf528SMauro Carvalho Chehab apb_address = 915; 19839a0bf528SMauro Carvalho Chehab break; 19849a0bf528SMauro Carvalho Chehab case 0x27: 19859a0bf528SMauro Carvalho Chehab apb_address = 917; 19869a0bf528SMauro Carvalho Chehab break; 19879a0bf528SMauro Carvalho Chehab case 0x28: 19889a0bf528SMauro Carvalho Chehab apb_address = 916; 19899a0bf528SMauro Carvalho Chehab break; 19909a0bf528SMauro Carvalho Chehab case 0x1d: 19919a0bf528SMauro Carvalho Chehab i = ((dib7000p_read_word(state, 72) >> 12) & 0x3); 19929a0bf528SMauro Carvalho Chehab word = dib7000p_read_word(state, 384 + i); 19939a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff; 19949a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff; 19959a0bf528SMauro Carvalho Chehab return num; 19969a0bf528SMauro Carvalho Chehab case 0x1f: 19979a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */ 19989a0bf528SMauro Carvalho Chehab word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]); 19999a0bf528SMauro Carvalho Chehab word &= 0x3; 20009a0bf528SMauro Carvalho Chehab word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12); 20019a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 72, word); /* Set the proper input */ 20029a0bf528SMauro Carvalho Chehab return num; 20039a0bf528SMauro Carvalho Chehab } 20049a0bf528SMauro Carvalho Chehab } 20059a0bf528SMauro Carvalho Chehab 20069a0bf528SMauro Carvalho Chehab if (apb_address != 0) /* R/W acces via APB */ 20079a0bf528SMauro Carvalho Chehab return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address); 20089a0bf528SMauro Carvalho Chehab else /* R/W access via SERPAR */ 20099a0bf528SMauro Carvalho Chehab return w7090p_tuner_rw_serpar(i2c_adap, msg, num); 20109a0bf528SMauro Carvalho Chehab 20119a0bf528SMauro Carvalho Chehab return 0; 20129a0bf528SMauro Carvalho Chehab } 20139a0bf528SMauro Carvalho Chehab 20149a0bf528SMauro Carvalho Chehab static u32 dib7000p_i2c_func(struct i2c_adapter *adapter) 20159a0bf528SMauro Carvalho Chehab { 20169a0bf528SMauro Carvalho Chehab return I2C_FUNC_I2C; 20179a0bf528SMauro Carvalho Chehab } 20189a0bf528SMauro Carvalho Chehab 20199a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib7090_tuner_xfer_algo = { 20209a0bf528SMauro Carvalho Chehab .master_xfer = dib7090_tuner_xfer, 20219a0bf528SMauro Carvalho Chehab .functionality = dib7000p_i2c_func, 20229a0bf528SMauro Carvalho Chehab }; 20239a0bf528SMauro Carvalho Chehab 2024*8abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe) 20259a0bf528SMauro Carvalho Chehab { 20269a0bf528SMauro Carvalho Chehab struct dib7000p_state *st = fe->demodulator_priv; 20279a0bf528SMauro Carvalho Chehab return &st->dib7090_tuner_adap; 20289a0bf528SMauro Carvalho Chehab } 20299a0bf528SMauro Carvalho Chehab 20309a0bf528SMauro Carvalho Chehab static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive) 20319a0bf528SMauro Carvalho Chehab { 20329a0bf528SMauro Carvalho Chehab u16 reg; 20339a0bf528SMauro Carvalho Chehab 20349a0bf528SMauro Carvalho Chehab /* drive host bus 2, 3, 4 */ 20359a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); 20369a0bf528SMauro Carvalho Chehab reg |= (drive << 12) | (drive << 6) | drive; 20379a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1798, reg); 20389a0bf528SMauro Carvalho Chehab 20399a0bf528SMauro Carvalho Chehab /* drive host bus 5,6 */ 20409a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); 20419a0bf528SMauro Carvalho Chehab reg |= (drive << 8) | (drive << 2); 20429a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1799, reg); 20439a0bf528SMauro Carvalho Chehab 20449a0bf528SMauro Carvalho Chehab /* drive host bus 7, 8, 9 */ 20459a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); 20469a0bf528SMauro Carvalho Chehab reg |= (drive << 12) | (drive << 6) | drive; 20479a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1800, reg); 20489a0bf528SMauro Carvalho Chehab 20499a0bf528SMauro Carvalho Chehab /* drive host bus 10, 11 */ 20509a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); 20519a0bf528SMauro Carvalho Chehab reg |= (drive << 8) | (drive << 2); 20529a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1801, reg); 20539a0bf528SMauro Carvalho Chehab 20549a0bf528SMauro Carvalho Chehab /* drive host bus 12, 13, 14 */ 20559a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); 20569a0bf528SMauro Carvalho Chehab reg |= (drive << 12) | (drive << 6) | drive; 20579a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1802, reg); 20589a0bf528SMauro Carvalho Chehab 20599a0bf528SMauro Carvalho Chehab return 0; 20609a0bf528SMauro Carvalho Chehab } 20619a0bf528SMauro Carvalho Chehab 20629a0bf528SMauro Carvalho Chehab static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize) 20639a0bf528SMauro Carvalho Chehab { 20649a0bf528SMauro Carvalho Chehab u32 quantif = 3; 20659a0bf528SMauro Carvalho Chehab u32 nom = (insertExtSynchro * P_Kin + syncSize); 20669a0bf528SMauro Carvalho Chehab u32 denom = P_Kout; 20679a0bf528SMauro Carvalho Chehab u32 syncFreq = ((nom << quantif) / denom); 20689a0bf528SMauro Carvalho Chehab 20699a0bf528SMauro Carvalho Chehab if ((syncFreq & ((1 << quantif) - 1)) != 0) 20709a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif) + 1; 20719a0bf528SMauro Carvalho Chehab else 20729a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif); 20739a0bf528SMauro Carvalho Chehab 20749a0bf528SMauro Carvalho Chehab if (syncFreq != 0) 20759a0bf528SMauro Carvalho Chehab syncFreq = syncFreq - 1; 20769a0bf528SMauro Carvalho Chehab 20779a0bf528SMauro Carvalho Chehab return syncFreq; 20789a0bf528SMauro Carvalho Chehab } 20799a0bf528SMauro Carvalho Chehab 20809a0bf528SMauro Carvalho Chehab static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) 20819a0bf528SMauro Carvalho Chehab { 20829a0bf528SMauro Carvalho Chehab dprintk("Configure DibStream Tx"); 20839a0bf528SMauro Carvalho Chehab 20849a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1615, 1); 20859a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1603, P_Kin); 20869a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1605, P_Kout); 20879a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1606, insertExtSynchro); 20889a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1608, synchroMode); 20899a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff); 20909a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1610, syncWord & 0xffff); 20919a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1612, syncSize); 20929a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1615, 0); 20939a0bf528SMauro Carvalho Chehab 20949a0bf528SMauro Carvalho Chehab return 0; 20959a0bf528SMauro Carvalho Chehab } 20969a0bf528SMauro Carvalho Chehab 20979a0bf528SMauro Carvalho Chehab static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize, 20989a0bf528SMauro Carvalho Chehab u32 dataOutRate) 20999a0bf528SMauro Carvalho Chehab { 21009a0bf528SMauro Carvalho Chehab u32 syncFreq; 21019a0bf528SMauro Carvalho Chehab 21029a0bf528SMauro Carvalho Chehab dprintk("Configure DibStream Rx"); 21039a0bf528SMauro Carvalho Chehab if ((P_Kin != 0) && (P_Kout != 0)) { 21049a0bf528SMauro Carvalho Chehab syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize); 21059a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1542, syncFreq); 21069a0bf528SMauro Carvalho Chehab } 21079a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1554, 1); 21089a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1536, P_Kin); 21099a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1537, P_Kout); 21109a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1539, synchroMode); 21119a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff); 21129a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1541, syncWord & 0xffff); 21139a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1543, syncSize); 21149a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1544, dataOutRate); 21159a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1554, 0); 21169a0bf528SMauro Carvalho Chehab 21179a0bf528SMauro Carvalho Chehab return 0; 21189a0bf528SMauro Carvalho Chehab } 21199a0bf528SMauro Carvalho Chehab 21209a0bf528SMauro Carvalho Chehab static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff) 21219a0bf528SMauro Carvalho Chehab { 21229a0bf528SMauro Carvalho Chehab u16 reg_1287 = dib7000p_read_word(state, 1287); 21239a0bf528SMauro Carvalho Chehab 21249a0bf528SMauro Carvalho Chehab switch (onoff) { 21259a0bf528SMauro Carvalho Chehab case 1: 21269a0bf528SMauro Carvalho Chehab reg_1287 &= ~(1<<7); 21279a0bf528SMauro Carvalho Chehab break; 21289a0bf528SMauro Carvalho Chehab case 0: 21299a0bf528SMauro Carvalho Chehab reg_1287 |= (1<<7); 21309a0bf528SMauro Carvalho Chehab break; 21319a0bf528SMauro Carvalho Chehab } 21329a0bf528SMauro Carvalho Chehab 21339a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1287, reg_1287); 21349a0bf528SMauro Carvalho Chehab } 21359a0bf528SMauro Carvalho Chehab 21369a0bf528SMauro Carvalho Chehab static void dib7090_configMpegMux(struct dib7000p_state *state, 21379a0bf528SMauro Carvalho Chehab u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) 21389a0bf528SMauro Carvalho Chehab { 21399a0bf528SMauro Carvalho Chehab dprintk("Enable Mpeg mux"); 21409a0bf528SMauro Carvalho Chehab 21419a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 0); 21429a0bf528SMauro Carvalho Chehab 21439a0bf528SMauro Carvalho Chehab /* If the input mode is MPEG do not divide the serial clock */ 21449a0bf528SMauro Carvalho Chehab if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) 21459a0bf528SMauro Carvalho Chehab enSerialClkDiv2 = 0; 21469a0bf528SMauro Carvalho Chehab 21479a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2) 21489a0bf528SMauro Carvalho Chehab | ((enSerialMode & 0x1) << 1) 21499a0bf528SMauro Carvalho Chehab | (enSerialClkDiv2 & 0x1)); 21509a0bf528SMauro Carvalho Chehab 21519a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 1); 21529a0bf528SMauro Carvalho Chehab } 21539a0bf528SMauro Carvalho Chehab 21549a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode) 21559a0bf528SMauro Carvalho Chehab { 21569a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7); 21579a0bf528SMauro Carvalho Chehab 21589a0bf528SMauro Carvalho Chehab switch (mode) { 21599a0bf528SMauro Carvalho Chehab case MPEG_ON_DIBTX: 21609a0bf528SMauro Carvalho Chehab dprintk("SET MPEG ON DIBSTREAM TX"); 21619a0bf528SMauro Carvalho Chehab dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); 21629a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<9); 21639a0bf528SMauro Carvalho Chehab break; 21649a0bf528SMauro Carvalho Chehab case DIV_ON_DIBTX: 21659a0bf528SMauro Carvalho Chehab dprintk("SET DIV_OUT ON DIBSTREAM TX"); 21669a0bf528SMauro Carvalho Chehab dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); 21679a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<8); 21689a0bf528SMauro Carvalho Chehab break; 21699a0bf528SMauro Carvalho Chehab case ADC_ON_DIBTX: 21709a0bf528SMauro Carvalho Chehab dprintk("SET ADC_OUT ON DIBSTREAM TX"); 21719a0bf528SMauro Carvalho Chehab dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); 21729a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<7); 21739a0bf528SMauro Carvalho Chehab break; 21749a0bf528SMauro Carvalho Chehab default: 21759a0bf528SMauro Carvalho Chehab break; 21769a0bf528SMauro Carvalho Chehab } 21779a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1288, reg_1288); 21789a0bf528SMauro Carvalho Chehab } 21799a0bf528SMauro Carvalho Chehab 21809a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode) 21819a0bf528SMauro Carvalho Chehab { 21829a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4); 21839a0bf528SMauro Carvalho Chehab 21849a0bf528SMauro Carvalho Chehab switch (mode) { 21859a0bf528SMauro Carvalho Chehab case DEMOUT_ON_HOSTBUS: 21869a0bf528SMauro Carvalho Chehab dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); 21879a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 0); 21889a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<6); 21899a0bf528SMauro Carvalho Chehab break; 21909a0bf528SMauro Carvalho Chehab case DIBTX_ON_HOSTBUS: 21919a0bf528SMauro Carvalho Chehab dprintk("SET DIBSTREAM TX ON HOST BUS"); 21929a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 0); 21939a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<5); 21949a0bf528SMauro Carvalho Chehab break; 21959a0bf528SMauro Carvalho Chehab case MPEG_ON_HOSTBUS: 21969a0bf528SMauro Carvalho Chehab dprintk("SET MPEG MUX ON HOST BUS"); 21979a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<4); 21989a0bf528SMauro Carvalho Chehab break; 21999a0bf528SMauro Carvalho Chehab default: 22009a0bf528SMauro Carvalho Chehab break; 22019a0bf528SMauro Carvalho Chehab } 22029a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1288, reg_1288); 22039a0bf528SMauro Carvalho Chehab } 22049a0bf528SMauro Carvalho Chehab 22059a0bf528SMauro Carvalho Chehab int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) 22069a0bf528SMauro Carvalho Chehab { 22079a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 22089a0bf528SMauro Carvalho Chehab u16 reg_1287; 22099a0bf528SMauro Carvalho Chehab 22109a0bf528SMauro Carvalho Chehab switch (onoff) { 22119a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */ 22129a0bf528SMauro Carvalho Chehab dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__); 22139a0bf528SMauro Carvalho Chehab dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); 22149a0bf528SMauro Carvalho Chehab 22159a0bf528SMauro Carvalho Chehab /* Do not divide the serial clock of MPEG MUX */ 22169a0bf528SMauro Carvalho Chehab /* in SERIAL MODE in case input mode MPEG is used */ 22179a0bf528SMauro Carvalho Chehab reg_1287 = dib7000p_read_word(state, 1287); 22189a0bf528SMauro Carvalho Chehab /* enSerialClkDiv2 == 1 ? */ 22199a0bf528SMauro Carvalho Chehab if ((reg_1287 & 0x1) == 1) { 22209a0bf528SMauro Carvalho Chehab /* force enSerialClkDiv2 = 0 */ 22219a0bf528SMauro Carvalho Chehab reg_1287 &= ~0x1; 22229a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1287, reg_1287); 22239a0bf528SMauro Carvalho Chehab } 22249a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 1; 22259a0bf528SMauro Carvalho Chehab break; 22269a0bf528SMauro Carvalho Chehab case 1: /* both ways */ 22279a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */ 22289a0bf528SMauro Carvalho Chehab dprintk("%s ON : Enable diversity INPUT", __func__); 22299a0bf528SMauro Carvalho Chehab dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); 22309a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 0; 22319a0bf528SMauro Carvalho Chehab break; 22329a0bf528SMauro Carvalho Chehab } 22339a0bf528SMauro Carvalho Chehab 22349a0bf528SMauro Carvalho Chehab dib7000p_set_diversity_in(&state->demod, onoff); 22359a0bf528SMauro Carvalho Chehab return 0; 22369a0bf528SMauro Carvalho Chehab } 22379a0bf528SMauro Carvalho Chehab 22389a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) 22399a0bf528SMauro Carvalho Chehab { 22409a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 22419a0bf528SMauro Carvalho Chehab 22429a0bf528SMauro Carvalho Chehab u16 outreg, smo_mode, fifo_threshold; 22439a0bf528SMauro Carvalho Chehab u8 prefer_mpeg_mux_use = 1; 22449a0bf528SMauro Carvalho Chehab int ret = 0; 22459a0bf528SMauro Carvalho Chehab 22469a0bf528SMauro Carvalho Chehab dib7090_host_bus_drive(state, 1); 22479a0bf528SMauro Carvalho Chehab 22489a0bf528SMauro Carvalho Chehab fifo_threshold = 1792; 22499a0bf528SMauro Carvalho Chehab smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); 22509a0bf528SMauro Carvalho Chehab outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1)); 22519a0bf528SMauro Carvalho Chehab 22529a0bf528SMauro Carvalho Chehab switch (mode) { 22539a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: 22549a0bf528SMauro Carvalho Chehab outreg = 0; 22559a0bf528SMauro Carvalho Chehab break; 22569a0bf528SMauro Carvalho Chehab 22579a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 22589a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 22599a0bf528SMauro Carvalho Chehab dprintk("setting output mode TS_SERIAL using Mpeg Mux"); 22609a0bf528SMauro Carvalho Chehab dib7090_configMpegMux(state, 3, 1, 1); 22619a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); 22629a0bf528SMauro Carvalho Chehab } else {/* Use Smooth block */ 22639a0bf528SMauro Carvalho Chehab dprintk("setting output mode TS_SERIAL using Smooth bloc"); 22649a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 22659a0bf528SMauro Carvalho Chehab outreg |= (2<<6) | (0 << 1); 22669a0bf528SMauro Carvalho Chehab } 22679a0bf528SMauro Carvalho Chehab break; 22689a0bf528SMauro Carvalho Chehab 22699a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 22709a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) { 22719a0bf528SMauro Carvalho Chehab dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux"); 22729a0bf528SMauro Carvalho Chehab dib7090_configMpegMux(state, 2, 0, 0); 22739a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); 22749a0bf528SMauro Carvalho Chehab } else { /* Use Smooth block */ 22759a0bf528SMauro Carvalho Chehab dprintk("setting output mode TS_PARALLEL_GATED using Smooth block"); 22769a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 22779a0bf528SMauro Carvalho Chehab outreg |= (0<<6); 22789a0bf528SMauro Carvalho Chehab } 22799a0bf528SMauro Carvalho Chehab break; 22809a0bf528SMauro Carvalho Chehab 22819a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ 22829a0bf528SMauro Carvalho Chehab dprintk("setting output mode TS_PARALLEL_CONT using Smooth block"); 22839a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 22849a0bf528SMauro Carvalho Chehab outreg |= (1<<6); 22859a0bf528SMauro Carvalho Chehab break; 22869a0bf528SMauro Carvalho Chehab 22879a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ 22889a0bf528SMauro Carvalho Chehab dprintk("setting output mode TS_FIFO using Smooth block"); 22899a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); 22909a0bf528SMauro Carvalho Chehab outreg |= (5<<6); 22919a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1); 22929a0bf528SMauro Carvalho Chehab fifo_threshold = 512; 22939a0bf528SMauro Carvalho Chehab break; 22949a0bf528SMauro Carvalho Chehab 22959a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 22969a0bf528SMauro Carvalho Chehab dprintk("setting output mode MODE_DIVERSITY"); 22979a0bf528SMauro Carvalho Chehab dib7090_setDibTxMux(state, DIV_ON_DIBTX); 22989a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); 22999a0bf528SMauro Carvalho Chehab break; 23009a0bf528SMauro Carvalho Chehab 23019a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 23029a0bf528SMauro Carvalho Chehab dprintk("setting output mode MODE_ANALOG_ADC"); 23039a0bf528SMauro Carvalho Chehab dib7090_setDibTxMux(state, ADC_ON_DIBTX); 23049a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); 23059a0bf528SMauro Carvalho Chehab break; 23069a0bf528SMauro Carvalho Chehab } 23079a0bf528SMauro Carvalho Chehab if (mode != OUTMODE_HIGH_Z) 23089a0bf528SMauro Carvalho Chehab outreg |= (1 << 10); 23099a0bf528SMauro Carvalho Chehab 23109a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes) 23119a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 23129a0bf528SMauro Carvalho Chehab 23139a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 235, smo_mode); 23149a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ 23159a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 1286, outreg); 23169a0bf528SMauro Carvalho Chehab 23179a0bf528SMauro Carvalho Chehab return ret; 23189a0bf528SMauro Carvalho Chehab } 23199a0bf528SMauro Carvalho Chehab 2320*8abe4a0aSMauro Carvalho Chehab static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) 23219a0bf528SMauro Carvalho Chehab { 23229a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 23239a0bf528SMauro Carvalho Chehab u16 en_cur_state; 23249a0bf528SMauro Carvalho Chehab 23259a0bf528SMauro Carvalho Chehab dprintk("sleep dib7090: %d", onoff); 23269a0bf528SMauro Carvalho Chehab 23279a0bf528SMauro Carvalho Chehab en_cur_state = dib7000p_read_word(state, 1922); 23289a0bf528SMauro Carvalho Chehab 23299a0bf528SMauro Carvalho Chehab if (en_cur_state > 0xff) 23309a0bf528SMauro Carvalho Chehab state->tuner_enable = en_cur_state; 23319a0bf528SMauro Carvalho Chehab 23329a0bf528SMauro Carvalho Chehab if (onoff) 23339a0bf528SMauro Carvalho Chehab en_cur_state &= 0x00ff; 23349a0bf528SMauro Carvalho Chehab else { 23359a0bf528SMauro Carvalho Chehab if (state->tuner_enable != 0) 23369a0bf528SMauro Carvalho Chehab en_cur_state = state->tuner_enable; 23379a0bf528SMauro Carvalho Chehab } 23389a0bf528SMauro Carvalho Chehab 23399a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1922, en_cur_state); 23409a0bf528SMauro Carvalho Chehab 23419a0bf528SMauro Carvalho Chehab return 0; 23429a0bf528SMauro Carvalho Chehab } 23439a0bf528SMauro Carvalho Chehab 2344*8abe4a0aSMauro Carvalho Chehab static int dib7090_get_adc_power(struct dvb_frontend *fe) 23459a0bf528SMauro Carvalho Chehab { 23469a0bf528SMauro Carvalho Chehab return dib7000p_get_adc_power(fe); 23479a0bf528SMauro Carvalho Chehab } 23489a0bf528SMauro Carvalho Chehab 2349*8abe4a0aSMauro Carvalho Chehab static int dib7090_slave_reset(struct dvb_frontend *fe) 23509a0bf528SMauro Carvalho Chehab { 23519a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv; 23529a0bf528SMauro Carvalho Chehab u16 reg; 23539a0bf528SMauro Carvalho Chehab 23549a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1794); 23559a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1794, reg | (4 << 12)); 23569a0bf528SMauro Carvalho Chehab 23579a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1032, 0xffff); 23589a0bf528SMauro Carvalho Chehab return 0; 23599a0bf528SMauro Carvalho Chehab } 23609a0bf528SMauro Carvalho Chehab 23619a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops dib7000p_ops; 2362*8abe4a0aSMauro Carvalho Chehab static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) 23639a0bf528SMauro Carvalho Chehab { 23649a0bf528SMauro Carvalho Chehab struct dvb_frontend *demod; 23659a0bf528SMauro Carvalho Chehab struct dib7000p_state *st; 23669a0bf528SMauro Carvalho Chehab st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL); 23679a0bf528SMauro Carvalho Chehab if (st == NULL) 23689a0bf528SMauro Carvalho Chehab return NULL; 23699a0bf528SMauro Carvalho Chehab 23709a0bf528SMauro Carvalho Chehab memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config)); 23719a0bf528SMauro Carvalho Chehab st->i2c_adap = i2c_adap; 23729a0bf528SMauro Carvalho Chehab st->i2c_addr = i2c_addr; 23739a0bf528SMauro Carvalho Chehab st->gpio_val = cfg->gpio_val; 23749a0bf528SMauro Carvalho Chehab st->gpio_dir = cfg->gpio_dir; 23759a0bf528SMauro Carvalho Chehab 23769a0bf528SMauro Carvalho Chehab /* Ensure the output mode remains at the previous default if it's 23779a0bf528SMauro Carvalho Chehab * not specifically set by the caller. 23789a0bf528SMauro Carvalho Chehab */ 23799a0bf528SMauro Carvalho Chehab if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) 23809a0bf528SMauro Carvalho Chehab st->cfg.output_mode = OUTMODE_MPEG2_FIFO; 23819a0bf528SMauro Carvalho Chehab 23829a0bf528SMauro Carvalho Chehab demod = &st->demod; 23839a0bf528SMauro Carvalho Chehab demod->demodulator_priv = st; 23849a0bf528SMauro Carvalho Chehab memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); 23859a0bf528SMauro Carvalho Chehab mutex_init(&st->i2c_buffer_lock); 23869a0bf528SMauro Carvalho Chehab 23879a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ 23889a0bf528SMauro Carvalho Chehab 23899a0bf528SMauro Carvalho Chehab if (dib7000p_identify(st) != 0) 23909a0bf528SMauro Carvalho Chehab goto error; 23919a0bf528SMauro Carvalho Chehab 23929a0bf528SMauro Carvalho Chehab st->version = dib7000p_read_word(st, 897); 23939a0bf528SMauro Carvalho Chehab 23949a0bf528SMauro Carvalho Chehab /* FIXME: make sure the dev.parent field is initialized, or else 23959a0bf528SMauro Carvalho Chehab request_firmware() will hit an OOPS (this should be moved somewhere 23969a0bf528SMauro Carvalho Chehab more common) */ 23979a0bf528SMauro Carvalho Chehab st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; 23989a0bf528SMauro Carvalho Chehab 23999a0bf528SMauro Carvalho Chehab dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); 24009a0bf528SMauro Carvalho Chehab 24019a0bf528SMauro Carvalho Chehab /* init 7090 tuner adapter */ 24029a0bf528SMauro Carvalho Chehab strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name)); 24039a0bf528SMauro Carvalho Chehab st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo; 24049a0bf528SMauro Carvalho Chehab st->dib7090_tuner_adap.algo_data = NULL; 24059a0bf528SMauro Carvalho Chehab st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent; 24069a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&st->dib7090_tuner_adap, st); 24079a0bf528SMauro Carvalho Chehab i2c_add_adapter(&st->dib7090_tuner_adap); 24089a0bf528SMauro Carvalho Chehab 24099a0bf528SMauro Carvalho Chehab dib7000p_demod_reset(st); 24109a0bf528SMauro Carvalho Chehab 24119a0bf528SMauro Carvalho Chehab if (st->version == SOC7090) { 24129a0bf528SMauro Carvalho Chehab dib7090_set_output_mode(demod, st->cfg.output_mode); 24139a0bf528SMauro Carvalho Chehab dib7090_set_diversity_in(demod, 0); 24149a0bf528SMauro Carvalho Chehab } 24159a0bf528SMauro Carvalho Chehab 24169a0bf528SMauro Carvalho Chehab return demod; 24179a0bf528SMauro Carvalho Chehab 24189a0bf528SMauro Carvalho Chehab error: 24199a0bf528SMauro Carvalho Chehab kfree(st); 24209a0bf528SMauro Carvalho Chehab return NULL; 24219a0bf528SMauro Carvalho Chehab } 2422*8abe4a0aSMauro Carvalho Chehab 2423*8abe4a0aSMauro Carvalho Chehab void *dib7000p_attach(struct dib7000p_ops *ops) 2424*8abe4a0aSMauro Carvalho Chehab { 2425*8abe4a0aSMauro Carvalho Chehab if (!ops) 2426*8abe4a0aSMauro Carvalho Chehab return NULL; 2427*8abe4a0aSMauro Carvalho Chehab 2428*8abe4a0aSMauro Carvalho Chehab ops->slave_reset = dib7090_slave_reset; 2429*8abe4a0aSMauro Carvalho Chehab ops->get_adc_power = dib7090_get_adc_power; 2430*8abe4a0aSMauro Carvalho Chehab ops->dib7000pc_detection = dib7000pc_detection; 2431*8abe4a0aSMauro Carvalho Chehab ops->get_i2c_tuner = dib7090_get_i2c_tuner; 2432*8abe4a0aSMauro Carvalho Chehab ops->tuner_sleep = dib7090_tuner_sleep; 2433*8abe4a0aSMauro Carvalho Chehab ops->init = dib7000p_init; 2434*8abe4a0aSMauro Carvalho Chehab ops->set_agc1_min = dib7000p_set_agc1_min; 2435*8abe4a0aSMauro Carvalho Chehab ops->set_gpio = dib7000p_set_gpio; 2436*8abe4a0aSMauro Carvalho Chehab ops->i2c_enumeration = dib7000p_i2c_enumeration; 2437*8abe4a0aSMauro Carvalho Chehab ops->pid_filter = dib7000p_pid_filter; 2438*8abe4a0aSMauro Carvalho Chehab ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl; 2439*8abe4a0aSMauro Carvalho Chehab ops->get_i2c_master = dib7000p_get_i2c_master; 2440*8abe4a0aSMauro Carvalho Chehab ops->update_pll = dib7000p_update_pll; 2441*8abe4a0aSMauro Carvalho Chehab ops->ctrl_timf = dib7000p_ctrl_timf; 2442*8abe4a0aSMauro Carvalho Chehab ops->get_agc_values = dib7000p_get_agc_values; 2443*8abe4a0aSMauro Carvalho Chehab ops->set_wbd_ref = dib7000p_set_wbd_ref; 2444*8abe4a0aSMauro Carvalho Chehab 2445*8abe4a0aSMauro Carvalho Chehab return ops; 2446*8abe4a0aSMauro Carvalho Chehab } 2447*8abe4a0aSMauro Carvalho Chehab EXPORT_SYMBOL(dib7000p_attach); 24489a0bf528SMauro Carvalho Chehab 24499a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops dib7000p_ops = { 24509a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBT }, 24519a0bf528SMauro Carvalho Chehab .info = { 24529a0bf528SMauro Carvalho Chehab .name = "DiBcom 7000PC", 24539a0bf528SMauro Carvalho Chehab .frequency_min = 44250000, 24549a0bf528SMauro Carvalho Chehab .frequency_max = 867250000, 24559a0bf528SMauro Carvalho Chehab .frequency_stepsize = 62500, 24569a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | 24579a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 24589a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 24599a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 24609a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, 24619a0bf528SMauro Carvalho Chehab }, 24629a0bf528SMauro Carvalho Chehab 24639a0bf528SMauro Carvalho Chehab .release = dib7000p_release, 24649a0bf528SMauro Carvalho Chehab 24659a0bf528SMauro Carvalho Chehab .init = dib7000p_wakeup, 24669a0bf528SMauro Carvalho Chehab .sleep = dib7000p_sleep, 24679a0bf528SMauro Carvalho Chehab 24689a0bf528SMauro Carvalho Chehab .set_frontend = dib7000p_set_frontend, 24699a0bf528SMauro Carvalho Chehab .get_tune_settings = dib7000p_fe_get_tune_settings, 24709a0bf528SMauro Carvalho Chehab .get_frontend = dib7000p_get_frontend, 24719a0bf528SMauro Carvalho Chehab 24729a0bf528SMauro Carvalho Chehab .read_status = dib7000p_read_status, 24739a0bf528SMauro Carvalho Chehab .read_ber = dib7000p_read_ber, 24749a0bf528SMauro Carvalho Chehab .read_signal_strength = dib7000p_read_signal_strength, 24759a0bf528SMauro Carvalho Chehab .read_snr = dib7000p_read_snr, 24769a0bf528SMauro Carvalho Chehab .read_ucblocks = dib7000p_read_unc_blocks, 24779a0bf528SMauro Carvalho Chehab }; 24789a0bf528SMauro Carvalho Chehab 24799a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>"); 24809a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); 24819a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator"); 24829a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 2483