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