1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
49a0bf528SMauro Carvalho Chehab *
59a0bf528SMauro Carvalho Chehab * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
69a0bf528SMauro Carvalho Chehab */
75a0e2a4eSMauro Carvalho Chehab
85a0e2a4eSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
95a0e2a4eSMauro 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>
14041ad449SMauro Carvalho Chehab #include <asm/div64.h>
159a0bf528SMauro Carvalho Chehab
16f97fa3dcSAndy Shevchenko #include <linux/int_log.h>
17fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
189a0bf528SMauro Carvalho Chehab
199a0bf528SMauro Carvalho Chehab #include "dib7000p.h"
209a0bf528SMauro Carvalho Chehab
219a0bf528SMauro Carvalho Chehab static int debug;
229a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
239a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
249a0bf528SMauro Carvalho Chehab
259a0bf528SMauro Carvalho Chehab static int buggy_sfn_workaround;
269a0bf528SMauro Carvalho Chehab module_param(buggy_sfn_workaround, int, 0644);
279a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
289a0bf528SMauro Carvalho Chehab
295a0e2a4eSMauro Carvalho Chehab #define dprintk(fmt, arg...) do { \
305a0e2a4eSMauro Carvalho Chehab if (debug) \
315a0e2a4eSMauro Carvalho Chehab printk(KERN_DEBUG pr_fmt("%s: " fmt), \
325a0e2a4eSMauro Carvalho Chehab __func__, ##arg); \
335a0e2a4eSMauro Carvalho Chehab } while (0)
349a0bf528SMauro Carvalho Chehab
359a0bf528SMauro Carvalho Chehab struct i2c_device {
369a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c_adap;
379a0bf528SMauro Carvalho Chehab u8 i2c_addr;
389a0bf528SMauro Carvalho Chehab };
399a0bf528SMauro Carvalho Chehab
409a0bf528SMauro Carvalho Chehab struct dib7000p_state {
419a0bf528SMauro Carvalho Chehab struct dvb_frontend demod;
429a0bf528SMauro Carvalho Chehab struct dib7000p_config cfg;
439a0bf528SMauro Carvalho Chehab
449a0bf528SMauro Carvalho Chehab u8 i2c_addr;
459a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c_adap;
469a0bf528SMauro Carvalho Chehab
479a0bf528SMauro Carvalho Chehab struct dibx000_i2c_master i2c_master;
489a0bf528SMauro Carvalho Chehab
499a0bf528SMauro Carvalho Chehab u16 wbd_ref;
509a0bf528SMauro Carvalho Chehab
519a0bf528SMauro Carvalho Chehab u8 current_band;
529a0bf528SMauro Carvalho Chehab u32 current_bandwidth;
539a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *current_agc;
549a0bf528SMauro Carvalho Chehab u32 timf;
559a0bf528SMauro Carvalho Chehab
569a0bf528SMauro Carvalho Chehab u8 div_force_off:1;
579a0bf528SMauro Carvalho Chehab u8 div_state:1;
589a0bf528SMauro Carvalho Chehab u16 div_sync_wait;
599a0bf528SMauro Carvalho Chehab
609a0bf528SMauro Carvalho Chehab u8 agc_state;
619a0bf528SMauro Carvalho Chehab
629a0bf528SMauro Carvalho Chehab u16 gpio_dir;
639a0bf528SMauro Carvalho Chehab u16 gpio_val;
649a0bf528SMauro Carvalho Chehab
659a0bf528SMauro Carvalho Chehab u8 sfn_workaround_active:1;
669a0bf528SMauro Carvalho Chehab
679a0bf528SMauro Carvalho Chehab #define SOC7090 0x7090
689a0bf528SMauro Carvalho Chehab u16 version;
699a0bf528SMauro Carvalho Chehab
709a0bf528SMauro Carvalho Chehab u16 tuner_enable;
719a0bf528SMauro Carvalho Chehab struct i2c_adapter dib7090_tuner_adap;
729a0bf528SMauro Carvalho Chehab
739a0bf528SMauro Carvalho Chehab /* for the I2C transfer */
749a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2];
759a0bf528SMauro Carvalho Chehab u8 i2c_write_buffer[4];
769a0bf528SMauro Carvalho Chehab u8 i2c_read_buffer[2];
779a0bf528SMauro Carvalho Chehab struct mutex i2c_buffer_lock;
789a0bf528SMauro Carvalho Chehab
799a0bf528SMauro Carvalho Chehab u8 input_mode_mpeg;
80041ad449SMauro Carvalho Chehab
81041ad449SMauro Carvalho Chehab /* for DVBv5 stats */
82041ad449SMauro Carvalho Chehab s64 old_ucb;
83041ad449SMauro Carvalho Chehab unsigned long per_jiffies_stats;
84041ad449SMauro Carvalho Chehab unsigned long ber_jiffies_stats;
85041ad449SMauro Carvalho Chehab unsigned long get_stats_time;
869a0bf528SMauro Carvalho Chehab };
879a0bf528SMauro Carvalho Chehab
889a0bf528SMauro Carvalho Chehab enum dib7000p_power_mode {
899a0bf528SMauro Carvalho Chehab DIB7000P_POWER_ALL = 0,
909a0bf528SMauro Carvalho Chehab DIB7000P_POWER_ANALOG_ADC,
919a0bf528SMauro Carvalho Chehab DIB7000P_POWER_INTERFACE_ONLY,
929a0bf528SMauro Carvalho Chehab };
939a0bf528SMauro Carvalho Chehab
94868c9a17SMauro Carvalho Chehab /* dib7090 specific functions */
959a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
969a0bf528SMauro Carvalho Chehab static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
979a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
989a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
999a0bf528SMauro Carvalho Chehab
dib7000p_read_word(struct dib7000p_state * state,u16 reg)1009a0bf528SMauro Carvalho Chehab static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
1019a0bf528SMauro Carvalho Chehab {
1029a0bf528SMauro Carvalho Chehab u16 ret;
1039a0bf528SMauro Carvalho Chehab
1049a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1055a0e2a4eSMauro Carvalho Chehab dprintk("could not acquire lock\n");
1069a0bf528SMauro Carvalho Chehab return 0;
1079a0bf528SMauro Carvalho Chehab }
1089a0bf528SMauro Carvalho Chehab
1099a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = reg >> 8;
1109a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff;
1119a0bf528SMauro Carvalho Chehab
1129a0bf528SMauro Carvalho Chehab memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1139a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c_addr >> 1;
1149a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0;
1159a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer;
1169a0bf528SMauro Carvalho Chehab state->msg[0].len = 2;
1179a0bf528SMauro Carvalho Chehab state->msg[1].addr = state->i2c_addr >> 1;
1189a0bf528SMauro Carvalho Chehab state->msg[1].flags = I2C_M_RD;
1199a0bf528SMauro Carvalho Chehab state->msg[1].buf = state->i2c_read_buffer;
1209a0bf528SMauro Carvalho Chehab state->msg[1].len = 2;
1219a0bf528SMauro Carvalho Chehab
1229a0bf528SMauro Carvalho Chehab if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
1235a0e2a4eSMauro Carvalho Chehab dprintk("i2c read error on %d\n", reg);
1249a0bf528SMauro Carvalho Chehab
1259a0bf528SMauro Carvalho Chehab ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1269a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock);
1279a0bf528SMauro Carvalho Chehab return ret;
1289a0bf528SMauro Carvalho Chehab }
1299a0bf528SMauro Carvalho Chehab
dib7000p_write_word(struct dib7000p_state * state,u16 reg,u16 val)1309a0bf528SMauro Carvalho Chehab static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
1319a0bf528SMauro Carvalho Chehab {
1329a0bf528SMauro Carvalho Chehab int ret;
1339a0bf528SMauro Carvalho Chehab
1349a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1355a0e2a4eSMauro Carvalho Chehab dprintk("could not acquire lock\n");
1369a0bf528SMauro Carvalho Chehab return -EINVAL;
1379a0bf528SMauro Carvalho Chehab }
1389a0bf528SMauro Carvalho Chehab
1399a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
1409a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff;
1419a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[2] = (val >> 8) & 0xff;
1429a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[3] = val & 0xff;
1439a0bf528SMauro Carvalho Chehab
1449a0bf528SMauro Carvalho Chehab memset(&state->msg[0], 0, sizeof(struct i2c_msg));
1459a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c_addr >> 1;
1469a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0;
1479a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer;
1489a0bf528SMauro Carvalho Chehab state->msg[0].len = 4;
1499a0bf528SMauro Carvalho Chehab
1509a0bf528SMauro Carvalho Chehab ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
1519a0bf528SMauro Carvalho Chehab -EREMOTEIO : 0);
1529a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock);
1539a0bf528SMauro Carvalho Chehab return ret;
1549a0bf528SMauro Carvalho Chehab }
1559a0bf528SMauro Carvalho Chehab
dib7000p_write_tab(struct dib7000p_state * state,u16 * buf)1569a0bf528SMauro Carvalho Chehab static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
1579a0bf528SMauro Carvalho Chehab {
1589a0bf528SMauro Carvalho Chehab u16 l = 0, r, *n;
1599a0bf528SMauro Carvalho Chehab n = buf;
1609a0bf528SMauro Carvalho Chehab l = *n++;
1619a0bf528SMauro Carvalho Chehab while (l) {
1629a0bf528SMauro Carvalho Chehab r = *n++;
1639a0bf528SMauro Carvalho Chehab
1649a0bf528SMauro Carvalho Chehab do {
1659a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, r, *n++);
1669a0bf528SMauro Carvalho Chehab r++;
1679a0bf528SMauro Carvalho Chehab } while (--l);
1689a0bf528SMauro Carvalho Chehab l = *n++;
1699a0bf528SMauro Carvalho Chehab }
1709a0bf528SMauro Carvalho Chehab }
1719a0bf528SMauro Carvalho Chehab
dib7000p_set_output_mode(struct dib7000p_state * state,int mode)1729a0bf528SMauro Carvalho Chehab static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
1739a0bf528SMauro Carvalho Chehab {
1749a0bf528SMauro Carvalho Chehab int ret = 0;
1759a0bf528SMauro Carvalho Chehab u16 outreg, fifo_threshold, smo_mode;
1769a0bf528SMauro Carvalho Chehab
1779a0bf528SMauro Carvalho Chehab outreg = 0;
1789a0bf528SMauro Carvalho Chehab fifo_threshold = 1792;
1799a0bf528SMauro Carvalho Chehab smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
1809a0bf528SMauro Carvalho Chehab
1815a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode for demod %p to %d\n", &state->demod, mode);
1829a0bf528SMauro Carvalho Chehab
1839a0bf528SMauro Carvalho Chehab switch (mode) {
1849a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK:
1859a0bf528SMauro Carvalho Chehab outreg = (1 << 10); /* 0x0400 */
1869a0bf528SMauro Carvalho Chehab break;
1879a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK:
1889a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (1 << 6); /* 0x0440 */
1899a0bf528SMauro Carvalho Chehab break;
1909a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL:
1919a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
1929a0bf528SMauro Carvalho Chehab break;
1939a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY:
1949a0bf528SMauro Carvalho Chehab if (state->cfg.hostbus_diversity)
1959a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (4 << 6); /* 0x0500 */
1969a0bf528SMauro Carvalho Chehab else
1979a0bf528SMauro Carvalho Chehab outreg = (1 << 11);
1989a0bf528SMauro Carvalho Chehab break;
1999a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO:
2009a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1);
2019a0bf528SMauro Carvalho Chehab fifo_threshold = 512;
2029a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (5 << 6);
2039a0bf528SMauro Carvalho Chehab break;
2049a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC:
2059a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (3 << 6);
2069a0bf528SMauro Carvalho Chehab break;
2079a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z:
2089a0bf528SMauro Carvalho Chehab outreg = 0;
2099a0bf528SMauro Carvalho Chehab break;
2109a0bf528SMauro Carvalho Chehab default:
2115a0e2a4eSMauro Carvalho Chehab dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod);
2129a0bf528SMauro Carvalho Chehab break;
2139a0bf528SMauro Carvalho Chehab }
2149a0bf528SMauro Carvalho Chehab
2159a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes)
2169a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5);
2179a0bf528SMauro Carvalho Chehab
2189a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 235, smo_mode);
2199a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
2209a0bf528SMauro Carvalho Chehab if (state->version != SOC7090)
2219a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
2229a0bf528SMauro Carvalho Chehab
2239a0bf528SMauro Carvalho Chehab return ret;
2249a0bf528SMauro Carvalho Chehab }
2259a0bf528SMauro Carvalho Chehab
dib7000p_set_diversity_in(struct dvb_frontend * demod,int onoff)2269a0bf528SMauro Carvalho Chehab static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
2279a0bf528SMauro Carvalho Chehab {
2289a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
2299a0bf528SMauro Carvalho Chehab
2309a0bf528SMauro Carvalho Chehab if (state->div_force_off) {
2315a0e2a4eSMauro Carvalho Chehab dprintk("diversity combination deactivated - forced by COFDM parameters\n");
2329a0bf528SMauro Carvalho Chehab onoff = 0;
2339a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 207, 0);
2349a0bf528SMauro Carvalho Chehab } else
2359a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
2369a0bf528SMauro Carvalho Chehab
2379a0bf528SMauro Carvalho Chehab state->div_state = (u8) onoff;
2389a0bf528SMauro Carvalho Chehab
2399a0bf528SMauro Carvalho Chehab if (onoff) {
2409a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 204, 6);
2419a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 205, 16);
2429a0bf528SMauro Carvalho Chehab /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
2439a0bf528SMauro Carvalho Chehab } else {
2449a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 204, 1);
2459a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 205, 0);
2469a0bf528SMauro Carvalho Chehab }
2479a0bf528SMauro Carvalho Chehab
2489a0bf528SMauro Carvalho Chehab return 0;
2499a0bf528SMauro Carvalho Chehab }
2509a0bf528SMauro Carvalho Chehab
dib7000p_set_power_mode(struct dib7000p_state * state,enum dib7000p_power_mode mode)2519a0bf528SMauro Carvalho Chehab static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
2529a0bf528SMauro Carvalho Chehab {
2539a0bf528SMauro Carvalho Chehab /* by default everything is powered off */
2549a0bf528SMauro Carvalho Chehab u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
2559a0bf528SMauro Carvalho Chehab
2569a0bf528SMauro Carvalho Chehab /* now, depending on the requested mode, we power on */
2579a0bf528SMauro Carvalho Chehab switch (mode) {
2589a0bf528SMauro Carvalho Chehab /* power up everything in the demod */
2599a0bf528SMauro Carvalho Chehab case DIB7000P_POWER_ALL:
2609a0bf528SMauro Carvalho Chehab reg_774 = 0x0000;
2619a0bf528SMauro Carvalho Chehab reg_775 = 0x0000;
2629a0bf528SMauro Carvalho Chehab reg_776 = 0x0;
2639a0bf528SMauro Carvalho Chehab reg_899 = 0x0;
2649a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
2659a0bf528SMauro Carvalho Chehab reg_1280 &= 0x001f;
2669a0bf528SMauro Carvalho Chehab else
2679a0bf528SMauro Carvalho Chehab reg_1280 &= 0x01ff;
2689a0bf528SMauro Carvalho Chehab break;
2699a0bf528SMauro Carvalho Chehab
2709a0bf528SMauro Carvalho Chehab case DIB7000P_POWER_ANALOG_ADC:
2719a0bf528SMauro Carvalho Chehab /* dem, cfg, iqc, sad, agc */
2729a0bf528SMauro Carvalho Chehab reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
2739a0bf528SMauro Carvalho Chehab /* nud */
2749a0bf528SMauro Carvalho Chehab reg_776 &= ~((1 << 0));
2759a0bf528SMauro Carvalho Chehab /* Dout */
2769a0bf528SMauro Carvalho Chehab if (state->version != SOC7090)
2779a0bf528SMauro Carvalho Chehab reg_1280 &= ~((1 << 11));
2789a0bf528SMauro Carvalho Chehab reg_1280 &= ~(1 << 6);
279df561f66SGustavo A. R. Silva fallthrough;
28006eeefe8SMauro Carvalho Chehab case DIB7000P_POWER_INTERFACE_ONLY:
2819a0bf528SMauro Carvalho Chehab /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
28206eeefe8SMauro Carvalho Chehab /* TODO power up either SDIO or I2C */
2839a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
2849a0bf528SMauro Carvalho Chehab reg_1280 &= ~((1 << 7) | (1 << 5));
2859a0bf528SMauro Carvalho Chehab else
2869a0bf528SMauro Carvalho Chehab reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
2879a0bf528SMauro Carvalho Chehab break;
2889a0bf528SMauro Carvalho Chehab
2899a0bf528SMauro Carvalho Chehab /* TODO following stuff is just converted from the dib7000-driver - check when is used what */
2909a0bf528SMauro Carvalho Chehab }
2919a0bf528SMauro Carvalho Chehab
2929a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 774, reg_774);
2939a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 775, reg_775);
2949a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 776, reg_776);
2959a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1280, reg_1280);
2969a0bf528SMauro Carvalho Chehab if (state->version != SOC7090)
2979a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 899, reg_899);
2989a0bf528SMauro Carvalho Chehab
2999a0bf528SMauro Carvalho Chehab return 0;
3009a0bf528SMauro Carvalho Chehab }
3019a0bf528SMauro Carvalho Chehab
dib7000p_set_adc_state(struct dib7000p_state * state,enum dibx000_adc_states no)3029a0bf528SMauro Carvalho Chehab static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
3039a0bf528SMauro Carvalho Chehab {
3049a0bf528SMauro Carvalho Chehab u16 reg_908 = 0, reg_909 = 0;
3059a0bf528SMauro Carvalho Chehab u16 reg;
3069a0bf528SMauro Carvalho Chehab
3079a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) {
3089a0bf528SMauro Carvalho Chehab reg_908 = dib7000p_read_word(state, 908);
3099a0bf528SMauro Carvalho Chehab reg_909 = dib7000p_read_word(state, 909);
3109a0bf528SMauro Carvalho Chehab }
3119a0bf528SMauro Carvalho Chehab
3129a0bf528SMauro Carvalho Chehab switch (no) {
3139a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_ON:
3149a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) {
3159a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1925);
3169a0bf528SMauro Carvalho Chehab
3179a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
3189a0bf528SMauro Carvalho Chehab
319868c9a17SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1925); /* read access to make it works... strange ... */
3209a0bf528SMauro Carvalho Chehab msleep(200);
3219a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
3229a0bf528SMauro Carvalho Chehab
3239a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
3249a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
3259a0bf528SMauro Carvalho Chehab } else {
3269a0bf528SMauro Carvalho Chehab reg_909 |= (1 << 1) | (1 << 0);
3279a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 909, reg_909);
3289a0bf528SMauro Carvalho Chehab reg_909 &= ~(1 << 1);
3299a0bf528SMauro Carvalho Chehab }
3309a0bf528SMauro Carvalho Chehab break;
3319a0bf528SMauro Carvalho Chehab
3329a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_OFF:
3339a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) {
3349a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1925);
3359a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
3369a0bf528SMauro Carvalho Chehab } else
3379a0bf528SMauro Carvalho Chehab reg_909 |= (1 << 1) | (1 << 0);
3389a0bf528SMauro Carvalho Chehab break;
3399a0bf528SMauro Carvalho Chehab
3409a0bf528SMauro Carvalho Chehab case DIBX000_ADC_ON:
3419a0bf528SMauro Carvalho Chehab reg_908 &= 0x0fff;
3429a0bf528SMauro Carvalho Chehab reg_909 &= 0x0003;
3439a0bf528SMauro Carvalho Chehab break;
3449a0bf528SMauro Carvalho Chehab
3459a0bf528SMauro Carvalho Chehab case DIBX000_ADC_OFF:
3469a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
3479a0bf528SMauro Carvalho Chehab reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
3489a0bf528SMauro Carvalho Chehab break;
3499a0bf528SMauro Carvalho Chehab
3509a0bf528SMauro Carvalho Chehab case DIBX000_VBG_ENABLE:
3519a0bf528SMauro Carvalho Chehab reg_908 &= ~(1 << 15);
3529a0bf528SMauro Carvalho Chehab break;
3539a0bf528SMauro Carvalho Chehab
3549a0bf528SMauro Carvalho Chehab case DIBX000_VBG_DISABLE:
3559a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 15);
3569a0bf528SMauro Carvalho Chehab break;
3579a0bf528SMauro Carvalho Chehab
3589a0bf528SMauro Carvalho Chehab default:
3599a0bf528SMauro Carvalho Chehab break;
3609a0bf528SMauro Carvalho Chehab }
3619a0bf528SMauro Carvalho Chehab
3629a0bf528SMauro Carvalho Chehab // dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
3639a0bf528SMauro Carvalho Chehab
3649a0bf528SMauro Carvalho Chehab reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
3659a0bf528SMauro Carvalho Chehab reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
3669a0bf528SMauro Carvalho Chehab
3679a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) {
3689a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 908, reg_908);
3699a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 909, reg_909);
3709a0bf528SMauro Carvalho Chehab }
3719a0bf528SMauro Carvalho Chehab }
3729a0bf528SMauro Carvalho Chehab
dib7000p_set_bandwidth(struct dib7000p_state * state,u32 bw)3739a0bf528SMauro Carvalho Chehab static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
3749a0bf528SMauro Carvalho Chehab {
3759a0bf528SMauro Carvalho Chehab u32 timf;
3769a0bf528SMauro Carvalho Chehab
3779a0bf528SMauro Carvalho Chehab // store the current bandwidth for later use
3789a0bf528SMauro Carvalho Chehab state->current_bandwidth = bw;
3799a0bf528SMauro Carvalho Chehab
3809a0bf528SMauro Carvalho Chehab if (state->timf == 0) {
3815a0e2a4eSMauro Carvalho Chehab dprintk("using default timf\n");
3829a0bf528SMauro Carvalho Chehab timf = state->cfg.bw->timf;
3839a0bf528SMauro Carvalho Chehab } else {
3845a0e2a4eSMauro Carvalho Chehab dprintk("using updated timf\n");
3859a0bf528SMauro Carvalho Chehab timf = state->timf;
3869a0bf528SMauro Carvalho Chehab }
3879a0bf528SMauro Carvalho Chehab
3889a0bf528SMauro Carvalho Chehab timf = timf * (bw / 50) / 160;
3899a0bf528SMauro Carvalho Chehab
3909a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
3919a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
3929a0bf528SMauro Carvalho Chehab
3939a0bf528SMauro Carvalho Chehab return 0;
3949a0bf528SMauro Carvalho Chehab }
3959a0bf528SMauro Carvalho Chehab
dib7000p_sad_calib(struct dib7000p_state * state)3969a0bf528SMauro Carvalho Chehab static int dib7000p_sad_calib(struct dib7000p_state *state)
3979a0bf528SMauro Carvalho Chehab {
3989a0bf528SMauro Carvalho Chehab /* internal */
3999a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
4009a0bf528SMauro Carvalho Chehab
4019a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
4029a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 74, 2048);
4039a0bf528SMauro Carvalho Chehab else
4049a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 74, 776);
4059a0bf528SMauro Carvalho Chehab
4069a0bf528SMauro Carvalho Chehab /* do the calibration */
4079a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 73, (1 << 0));
4089a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 73, (0 << 0));
4099a0bf528SMauro Carvalho Chehab
4109a0bf528SMauro Carvalho Chehab msleep(1);
4119a0bf528SMauro Carvalho Chehab
4129a0bf528SMauro Carvalho Chehab return 0;
4139a0bf528SMauro Carvalho Chehab }
4149a0bf528SMauro Carvalho Chehab
dib7000p_set_wbd_ref(struct dvb_frontend * demod,u16 value)4158abe4a0aSMauro Carvalho Chehab static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
4169a0bf528SMauro Carvalho Chehab {
4179a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
4189a0bf528SMauro Carvalho Chehab if (value > 4095)
4199a0bf528SMauro Carvalho Chehab value = 4095;
4209a0bf528SMauro Carvalho Chehab state->wbd_ref = value;
4219a0bf528SMauro Carvalho Chehab return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
4229a0bf528SMauro Carvalho Chehab }
4239a0bf528SMauro Carvalho Chehab
dib7000p_get_agc_values(struct dvb_frontend * fe,u16 * agc_global,u16 * agc1,u16 * agc2,u16 * wbd)4248abe4a0aSMauro Carvalho Chehab static int dib7000p_get_agc_values(struct dvb_frontend *fe,
4259a0bf528SMauro Carvalho Chehab u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
4269a0bf528SMauro Carvalho Chehab {
4279a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
4289a0bf528SMauro Carvalho Chehab
4299a0bf528SMauro Carvalho Chehab if (agc_global != NULL)
4309a0bf528SMauro Carvalho Chehab *agc_global = dib7000p_read_word(state, 394);
4319a0bf528SMauro Carvalho Chehab if (agc1 != NULL)
4329a0bf528SMauro Carvalho Chehab *agc1 = dib7000p_read_word(state, 392);
4339a0bf528SMauro Carvalho Chehab if (agc2 != NULL)
4349a0bf528SMauro Carvalho Chehab *agc2 = dib7000p_read_word(state, 393);
4359a0bf528SMauro Carvalho Chehab if (wbd != NULL)
4369a0bf528SMauro Carvalho Chehab *wbd = dib7000p_read_word(state, 397);
4379a0bf528SMauro Carvalho Chehab
4389a0bf528SMauro Carvalho Chehab return 0;
4399a0bf528SMauro Carvalho Chehab }
4409a0bf528SMauro Carvalho Chehab
dib7000p_set_agc1_min(struct dvb_frontend * fe,u16 v)4418abe4a0aSMauro Carvalho Chehab static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
4426fe1099cSOlivier Grenie {
4436fe1099cSOlivier Grenie struct dib7000p_state *state = fe->demodulator_priv;
4446fe1099cSOlivier Grenie return dib7000p_write_word(state, 108, v);
4456fe1099cSOlivier Grenie }
4466fe1099cSOlivier Grenie
dib7000p_reset_pll(struct dib7000p_state * state)4479a0bf528SMauro Carvalho Chehab static void dib7000p_reset_pll(struct dib7000p_state *state)
4489a0bf528SMauro Carvalho Chehab {
4499a0bf528SMauro Carvalho Chehab struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
4509a0bf528SMauro Carvalho Chehab u16 clk_cfg0;
4519a0bf528SMauro Carvalho Chehab
4529a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) {
4539a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
4549a0bf528SMauro Carvalho Chehab
4559a0bf528SMauro Carvalho Chehab while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
4569a0bf528SMauro Carvalho Chehab ;
4579a0bf528SMauro Carvalho Chehab
4589a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
4599a0bf528SMauro Carvalho Chehab } else {
4609a0bf528SMauro Carvalho Chehab /* force PLL bypass */
4619a0bf528SMauro Carvalho Chehab clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
4629a0bf528SMauro Carvalho Chehab (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
4639a0bf528SMauro Carvalho Chehab
4649a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 900, clk_cfg0);
4659a0bf528SMauro Carvalho Chehab
4669a0bf528SMauro Carvalho Chehab /* P_pll_cfg */
4679a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
4689a0bf528SMauro Carvalho Chehab clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
4699a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 900, clk_cfg0);
4709a0bf528SMauro Carvalho Chehab }
4719a0bf528SMauro Carvalho Chehab
4729a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
4739a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
4749a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
4759a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
4769a0bf528SMauro Carvalho Chehab
4779a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 72, bw->sad_cfg);
4789a0bf528SMauro Carvalho Chehab }
4799a0bf528SMauro Carvalho Chehab
dib7000p_get_internal_freq(struct dib7000p_state * state)4809a0bf528SMauro Carvalho Chehab static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
4819a0bf528SMauro Carvalho Chehab {
4829a0bf528SMauro Carvalho Chehab u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
4839a0bf528SMauro Carvalho Chehab internal |= (u32) dib7000p_read_word(state, 19);
4849a0bf528SMauro Carvalho Chehab internal /= 1000;
4859a0bf528SMauro Carvalho Chehab
4869a0bf528SMauro Carvalho Chehab return internal;
4879a0bf528SMauro Carvalho Chehab }
4889a0bf528SMauro Carvalho Chehab
dib7000p_update_pll(struct dvb_frontend * fe,struct dibx000_bandwidth_config * bw)4898abe4a0aSMauro Carvalho Chehab static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
4909a0bf528SMauro Carvalho Chehab {
4919a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
4929a0bf528SMauro Carvalho Chehab u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
4939a0bf528SMauro Carvalho Chehab u8 loopdiv, prediv;
4949a0bf528SMauro Carvalho Chehab u32 internal, xtal;
4959a0bf528SMauro Carvalho Chehab
4969a0bf528SMauro Carvalho Chehab /* get back old values */
4979a0bf528SMauro Carvalho Chehab prediv = reg_1856 & 0x3f;
4989a0bf528SMauro Carvalho Chehab loopdiv = (reg_1856 >> 6) & 0x3f;
4999a0bf528SMauro Carvalho Chehab
500a1db7b2cSDaniil Dulov if (loopdiv && bw && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
5015a0e2a4eSMauro Carvalho Chehab dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
5029a0bf528SMauro Carvalho Chehab reg_1856 &= 0xf000;
5039a0bf528SMauro Carvalho Chehab reg_1857 = dib7000p_read_word(state, 1857);
5049a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
5059a0bf528SMauro Carvalho Chehab
5069a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
5079a0bf528SMauro Carvalho Chehab
5089a0bf528SMauro Carvalho Chehab /* write new system clk into P_sec_len */
5099a0bf528SMauro Carvalho Chehab internal = dib7000p_get_internal_freq(state);
5109a0bf528SMauro Carvalho Chehab xtal = (internal / loopdiv) * prediv;
5119a0bf528SMauro Carvalho Chehab internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
5129a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
5139a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
5149a0bf528SMauro Carvalho Chehab
5159a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
5169a0bf528SMauro Carvalho Chehab
5179a0bf528SMauro Carvalho Chehab while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
5185a0e2a4eSMauro Carvalho Chehab dprintk("Waiting for PLL to lock\n");
5199a0bf528SMauro Carvalho Chehab
5209a0bf528SMauro Carvalho Chehab return 0;
5219a0bf528SMauro Carvalho Chehab }
5229a0bf528SMauro Carvalho Chehab return -EIO;
5239a0bf528SMauro Carvalho Chehab }
5249a0bf528SMauro Carvalho Chehab
dib7000p_reset_gpio(struct dib7000p_state * st)5259a0bf528SMauro Carvalho Chehab static int dib7000p_reset_gpio(struct dib7000p_state *st)
5269a0bf528SMauro Carvalho Chehab {
5279a0bf528SMauro Carvalho Chehab /* reset the GPIOs */
5285a0e2a4eSMauro Carvalho Chehab dprintk("gpio dir: %x: val: %x, pwm_pos: %x\n", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
5299a0bf528SMauro Carvalho Chehab
5309a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1029, st->gpio_dir);
5319a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1030, st->gpio_val);
5329a0bf528SMauro Carvalho Chehab
5339a0bf528SMauro Carvalho Chehab /* TODO 1031 is P_gpio_od */
5349a0bf528SMauro Carvalho Chehab
5359a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
5369a0bf528SMauro Carvalho Chehab
5379a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
5389a0bf528SMauro Carvalho Chehab return 0;
5399a0bf528SMauro Carvalho Chehab }
5409a0bf528SMauro Carvalho Chehab
dib7000p_cfg_gpio(struct dib7000p_state * st,u8 num,u8 dir,u8 val)5419a0bf528SMauro Carvalho Chehab static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
5429a0bf528SMauro Carvalho Chehab {
5439a0bf528SMauro Carvalho Chehab st->gpio_dir = dib7000p_read_word(st, 1029);
5449a0bf528SMauro Carvalho Chehab st->gpio_dir &= ~(1 << num); /* reset the direction bit */
5459a0bf528SMauro Carvalho Chehab st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
5469a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1029, st->gpio_dir);
5479a0bf528SMauro Carvalho Chehab
5489a0bf528SMauro Carvalho Chehab st->gpio_val = dib7000p_read_word(st, 1030);
5499a0bf528SMauro Carvalho Chehab st->gpio_val &= ~(1 << num); /* reset the direction bit */
5509a0bf528SMauro Carvalho Chehab st->gpio_val |= (val & 0x01) << num; /* set the new value */
5519a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1030, st->gpio_val);
5529a0bf528SMauro Carvalho Chehab
5539a0bf528SMauro Carvalho Chehab return 0;
5549a0bf528SMauro Carvalho Chehab }
5559a0bf528SMauro Carvalho Chehab
dib7000p_set_gpio(struct dvb_frontend * demod,u8 num,u8 dir,u8 val)5568abe4a0aSMauro Carvalho Chehab static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
5579a0bf528SMauro Carvalho Chehab {
5589a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
5599a0bf528SMauro Carvalho Chehab return dib7000p_cfg_gpio(state, num, dir, val);
5609a0bf528SMauro Carvalho Chehab }
5619a0bf528SMauro Carvalho Chehab
5629a0bf528SMauro Carvalho Chehab static u16 dib7000p_defaults[] = {
5639a0bf528SMauro Carvalho Chehab // auto search configuration
5649a0bf528SMauro Carvalho Chehab 3, 2,
5659a0bf528SMauro Carvalho Chehab 0x0004,
5669a0bf528SMauro Carvalho Chehab (1<<3)|(1<<11)|(1<<12)|(1<<13),
5679a0bf528SMauro Carvalho Chehab 0x0814, /* Equal Lock */
5689a0bf528SMauro Carvalho Chehab
5699a0bf528SMauro Carvalho Chehab 12, 6,
5709a0bf528SMauro Carvalho Chehab 0x001b,
5719a0bf528SMauro Carvalho Chehab 0x7740,
5729a0bf528SMauro Carvalho Chehab 0x005b,
5739a0bf528SMauro Carvalho Chehab 0x8d80,
5749a0bf528SMauro Carvalho Chehab 0x01c9,
5759a0bf528SMauro Carvalho Chehab 0xc380,
5769a0bf528SMauro Carvalho Chehab 0x0000,
5779a0bf528SMauro Carvalho Chehab 0x0080,
5789a0bf528SMauro Carvalho Chehab 0x0000,
5799a0bf528SMauro Carvalho Chehab 0x0090,
5809a0bf528SMauro Carvalho Chehab 0x0001,
5819a0bf528SMauro Carvalho Chehab 0xd4c0,
5829a0bf528SMauro Carvalho Chehab
5839a0bf528SMauro Carvalho Chehab 1, 26,
5849a0bf528SMauro Carvalho Chehab 0x6680,
5859a0bf528SMauro Carvalho Chehab
5869a0bf528SMauro Carvalho Chehab /* set ADC level to -16 */
5879a0bf528SMauro Carvalho Chehab 11, 79,
5889a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117,
5899a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117,
5909a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117,
5919a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117,
5929a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117,
5939a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117,
5949a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117,
5959a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117,
5969a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117,
5979a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117,
5989a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117,
5999a0bf528SMauro Carvalho Chehab
6009a0bf528SMauro Carvalho Chehab 1, 142,
6019a0bf528SMauro Carvalho Chehab 0x0410,
6029a0bf528SMauro Carvalho Chehab
6039a0bf528SMauro Carvalho Chehab /* disable power smoothing */
6049a0bf528SMauro Carvalho Chehab 8, 145,
6059a0bf528SMauro Carvalho Chehab 0,
6069a0bf528SMauro Carvalho Chehab 0,
6079a0bf528SMauro Carvalho Chehab 0,
6089a0bf528SMauro Carvalho Chehab 0,
6099a0bf528SMauro Carvalho Chehab 0,
6109a0bf528SMauro Carvalho Chehab 0,
6119a0bf528SMauro Carvalho Chehab 0,
6129a0bf528SMauro Carvalho Chehab 0,
6139a0bf528SMauro Carvalho Chehab
6149a0bf528SMauro Carvalho Chehab 1, 154,
6159a0bf528SMauro Carvalho Chehab 1 << 13,
6169a0bf528SMauro Carvalho Chehab
6179a0bf528SMauro Carvalho Chehab 1, 168,
6189a0bf528SMauro Carvalho Chehab 0x0ccd,
6199a0bf528SMauro Carvalho Chehab
6209a0bf528SMauro Carvalho Chehab 1, 183,
6219a0bf528SMauro Carvalho Chehab 0x200f,
6229a0bf528SMauro Carvalho Chehab
6239a0bf528SMauro Carvalho Chehab 1, 212,
6249a0bf528SMauro Carvalho Chehab 0x169,
6259a0bf528SMauro Carvalho Chehab
6269a0bf528SMauro Carvalho Chehab 5, 187,
6279a0bf528SMauro Carvalho Chehab 0x023d,
6289a0bf528SMauro Carvalho Chehab 0x00a4,
6299a0bf528SMauro Carvalho Chehab 0x00a4,
6309a0bf528SMauro Carvalho Chehab 0x7ff0,
6319a0bf528SMauro Carvalho Chehab 0x3ccc,
6329a0bf528SMauro Carvalho Chehab
6339a0bf528SMauro Carvalho Chehab 1, 198,
6349a0bf528SMauro Carvalho Chehab 0x800,
6359a0bf528SMauro Carvalho Chehab
6369a0bf528SMauro Carvalho Chehab 1, 222,
6379a0bf528SMauro Carvalho Chehab 0x0010,
6389a0bf528SMauro Carvalho Chehab
6399a0bf528SMauro Carvalho Chehab 1, 235,
6409a0bf528SMauro Carvalho Chehab 0x0062,
6419a0bf528SMauro Carvalho Chehab
6429a0bf528SMauro Carvalho Chehab 0,
6439a0bf528SMauro Carvalho Chehab };
6449a0bf528SMauro Carvalho Chehab
645041ad449SMauro Carvalho Chehab static void dib7000p_reset_stats(struct dvb_frontend *fe);
646041ad449SMauro Carvalho Chehab
dib7000p_demod_reset(struct dib7000p_state * state)6479a0bf528SMauro Carvalho Chehab static int dib7000p_demod_reset(struct dib7000p_state *state)
6489a0bf528SMauro Carvalho Chehab {
6499a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
6509a0bf528SMauro Carvalho Chehab
6519a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
6529a0bf528SMauro Carvalho Chehab dibx000_reset_i2c_master(&state->i2c_master);
6539a0bf528SMauro Carvalho Chehab
6549a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
6559a0bf528SMauro Carvalho Chehab
6569a0bf528SMauro Carvalho Chehab /* restart all parts */
6579a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0xffff);
6589a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, 0xffff);
6599a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 772, 0x001f);
6609a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
6619a0bf528SMauro Carvalho Chehab
6629a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0);
6639a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, 0);
6649a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 772, 0);
6659a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1280, 0);
6669a0bf528SMauro Carvalho Chehab
6679a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) {
6689a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 898, 0x0003);
6699a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 898, 0);
6709a0bf528SMauro Carvalho Chehab }
6719a0bf528SMauro Carvalho Chehab
6729a0bf528SMauro Carvalho Chehab /* default */
6739a0bf528SMauro Carvalho Chehab dib7000p_reset_pll(state);
6749a0bf528SMauro Carvalho Chehab
6759a0bf528SMauro Carvalho Chehab if (dib7000p_reset_gpio(state) != 0)
6765a0e2a4eSMauro Carvalho Chehab dprintk("GPIO reset was not successful.\n");
6779a0bf528SMauro Carvalho Chehab
6789a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) {
6799a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 899, 0);
6809a0bf528SMauro Carvalho Chehab
6819a0bf528SMauro Carvalho Chehab /* impulse noise */
6829a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
6839a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
6849a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
6859a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 273, (0<<6) | 30);
6869a0bf528SMauro Carvalho Chehab }
6879a0bf528SMauro Carvalho Chehab if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
6885a0e2a4eSMauro Carvalho Chehab dprintk("OUTPUT_MODE could not be reset.\n");
6899a0bf528SMauro Carvalho Chehab
6909a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
6919a0bf528SMauro Carvalho Chehab dib7000p_sad_calib(state);
6929a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
6939a0bf528SMauro Carvalho Chehab
6949a0bf528SMauro Carvalho Chehab /* unforce divstr regardless whether i2c enumeration was done or not */
6959a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
6969a0bf528SMauro Carvalho Chehab
6979a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, 8000);
6989a0bf528SMauro Carvalho Chehab
6999a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) {
7009a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
7019a0bf528SMauro Carvalho Chehab } else {
7029a0bf528SMauro Carvalho Chehab if (state->cfg.tuner_is_baseband)
7039a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 36, 0x0755);
7049a0bf528SMauro Carvalho Chehab else
7059a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 36, 0x1f55);
7069a0bf528SMauro Carvalho Chehab }
7079a0bf528SMauro Carvalho Chehab
7089a0bf528SMauro Carvalho Chehab dib7000p_write_tab(state, dib7000p_defaults);
7099a0bf528SMauro Carvalho Chehab if (state->version != SOC7090) {
7109a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 901, 0x0006);
7119a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
7129a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 905, 0x2c8e);
7139a0bf528SMauro Carvalho Chehab }
7149a0bf528SMauro Carvalho Chehab
7159a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
7169a0bf528SMauro Carvalho Chehab
7179a0bf528SMauro Carvalho Chehab return 0;
7189a0bf528SMauro Carvalho Chehab }
7199a0bf528SMauro Carvalho Chehab
dib7000p_pll_clk_cfg(struct dib7000p_state * state)7209a0bf528SMauro Carvalho Chehab static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
7219a0bf528SMauro Carvalho Chehab {
7229a0bf528SMauro Carvalho Chehab u16 tmp = 0;
7239a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 903);
7249a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 903, (tmp | 0x1));
7259a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 900);
7269a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
7279a0bf528SMauro Carvalho Chehab }
7289a0bf528SMauro Carvalho Chehab
dib7000p_restart_agc(struct dib7000p_state * state)7299a0bf528SMauro Carvalho Chehab static void dib7000p_restart_agc(struct dib7000p_state *state)
7309a0bf528SMauro Carvalho Chehab {
7319a0bf528SMauro Carvalho Chehab // P_restart_iqc & P_restart_agc
7329a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
7339a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0x0000);
7349a0bf528SMauro Carvalho Chehab }
7359a0bf528SMauro Carvalho Chehab
dib7000p_update_lna(struct dib7000p_state * state)7369a0bf528SMauro Carvalho Chehab static int dib7000p_update_lna(struct dib7000p_state *state)
7379a0bf528SMauro Carvalho Chehab {
7389a0bf528SMauro Carvalho Chehab u16 dyn_gain;
7399a0bf528SMauro Carvalho Chehab
7409a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna) {
7419a0bf528SMauro Carvalho Chehab dyn_gain = dib7000p_read_word(state, 394);
7429a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna(&state->demod, dyn_gain)) {
7439a0bf528SMauro Carvalho Chehab dib7000p_restart_agc(state);
7449a0bf528SMauro Carvalho Chehab return 1;
7459a0bf528SMauro Carvalho Chehab }
7469a0bf528SMauro Carvalho Chehab }
7479a0bf528SMauro Carvalho Chehab
7489a0bf528SMauro Carvalho Chehab return 0;
7499a0bf528SMauro Carvalho Chehab }
7509a0bf528SMauro Carvalho Chehab
dib7000p_set_agc_config(struct dib7000p_state * state,u8 band)7519a0bf528SMauro Carvalho Chehab static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
7529a0bf528SMauro Carvalho Chehab {
7539a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *agc = NULL;
7549a0bf528SMauro Carvalho Chehab int i;
7559a0bf528SMauro Carvalho Chehab if (state->current_band == band && state->current_agc != NULL)
7569a0bf528SMauro Carvalho Chehab return 0;
7579a0bf528SMauro Carvalho Chehab state->current_band = band;
7589a0bf528SMauro Carvalho Chehab
7599a0bf528SMauro Carvalho Chehab for (i = 0; i < state->cfg.agc_config_count; i++)
7609a0bf528SMauro Carvalho Chehab if (state->cfg.agc[i].band_caps & band) {
7619a0bf528SMauro Carvalho Chehab agc = &state->cfg.agc[i];
7629a0bf528SMauro Carvalho Chehab break;
7639a0bf528SMauro Carvalho Chehab }
7649a0bf528SMauro Carvalho Chehab
7659a0bf528SMauro Carvalho Chehab if (agc == NULL) {
7665a0e2a4eSMauro Carvalho Chehab dprintk("no valid AGC configuration found for band 0x%02x\n", band);
7679a0bf528SMauro Carvalho Chehab return -EINVAL;
7689a0bf528SMauro Carvalho Chehab }
7699a0bf528SMauro Carvalho Chehab
7709a0bf528SMauro Carvalho Chehab state->current_agc = agc;
7719a0bf528SMauro Carvalho Chehab
7729a0bf528SMauro Carvalho Chehab /* AGC */
7739a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 75, agc->setup);
7749a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 76, agc->inv_gain);
7759a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 77, agc->time_stabiliz);
7769a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
7779a0bf528SMauro Carvalho Chehab
7789a0bf528SMauro Carvalho Chehab // Demod AGC loop configuration
7799a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
7809a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
7819a0bf528SMauro Carvalho Chehab
7829a0bf528SMauro Carvalho Chehab /* AGC continued */
7835a0e2a4eSMauro Carvalho Chehab dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
7849a0bf528SMauro Carvalho Chehab state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
7859a0bf528SMauro Carvalho Chehab
7869a0bf528SMauro Carvalho Chehab if (state->wbd_ref != 0)
7879a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
7889a0bf528SMauro Carvalho Chehab else
7899a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
7909a0bf528SMauro Carvalho Chehab
7919a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
7929a0bf528SMauro Carvalho Chehab
7939a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 107, agc->agc1_max);
7949a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 108, agc->agc1_min);
7959a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 109, agc->agc2_max);
7969a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 110, agc->agc2_min);
7979a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
7989a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 112, agc->agc1_pt3);
7999a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
8009a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
8019a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
8029a0bf528SMauro Carvalho Chehab return 0;
8039a0bf528SMauro Carvalho Chehab }
8049a0bf528SMauro Carvalho Chehab
dib7000p_set_dds(struct dib7000p_state * state,s32 offset_khz)8055332b626SMartin Wache static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
8069a0bf528SMauro Carvalho Chehab {
8079a0bf528SMauro Carvalho Chehab u32 internal = dib7000p_get_internal_freq(state);
8085332b626SMartin Wache s32 unit_khz_dds_val;
8097aa92c42SDan Gopstein u32 abs_offset_khz = abs(offset_khz);
8109a0bf528SMauro Carvalho Chehab u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
8119a0bf528SMauro Carvalho Chehab u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
8125332b626SMartin Wache if (internal == 0) {
8135332b626SMartin Wache pr_warn("DIB7000P: dib7000p_get_internal_freq returned 0\n");
8145332b626SMartin Wache return -1;
8155332b626SMartin Wache }
8165332b626SMartin Wache /* 2**26 / Fsampling is the unit 1KHz offset */
8175332b626SMartin Wache unit_khz_dds_val = 67108864 / (internal);
8189a0bf528SMauro Carvalho Chehab
8195a0e2a4eSMauro Carvalho Chehab dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d\n", offset_khz, internal, invert);
8209a0bf528SMauro Carvalho Chehab
8219a0bf528SMauro Carvalho Chehab if (offset_khz < 0)
8229a0bf528SMauro Carvalho Chehab unit_khz_dds_val *= -1;
8239a0bf528SMauro Carvalho Chehab
8249a0bf528SMauro Carvalho Chehab /* IF tuner */
8259a0bf528SMauro Carvalho Chehab if (invert)
8269a0bf528SMauro 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 */
8279a0bf528SMauro Carvalho Chehab else
8289a0bf528SMauro Carvalho Chehab dds += (abs_offset_khz * unit_khz_dds_val);
8299a0bf528SMauro Carvalho Chehab
8309a0bf528SMauro Carvalho Chehab if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
8319a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
8329a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
8339a0bf528SMauro Carvalho Chehab }
8345332b626SMartin Wache return 0;
8359a0bf528SMauro Carvalho Chehab }
8369a0bf528SMauro Carvalho Chehab
dib7000p_agc_startup(struct dvb_frontend * demod)8379a0bf528SMauro Carvalho Chehab static int dib7000p_agc_startup(struct dvb_frontend *demod)
8389a0bf528SMauro Carvalho Chehab {
8399a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
8409a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
8419a0bf528SMauro Carvalho Chehab int ret = -1;
8429a0bf528SMauro Carvalho Chehab u8 *agc_state = &state->agc_state;
8439a0bf528SMauro Carvalho Chehab u8 agc_split;
8449a0bf528SMauro Carvalho Chehab u16 reg;
8459a0bf528SMauro Carvalho Chehab u32 upd_demod_gain_period = 0x1000;
8466fe1099cSOlivier Grenie s32 frequency_offset = 0;
8479a0bf528SMauro Carvalho Chehab
8489a0bf528SMauro Carvalho Chehab switch (state->agc_state) {
8499a0bf528SMauro Carvalho Chehab case 0:
8509a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
8519a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) {
8529a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 0x79b) & 0xff00;
8539a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
8549a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
8559a0bf528SMauro Carvalho Chehab
8569a0bf528SMauro Carvalho Chehab /* enable adc i & q */
8579a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 0x780);
8589a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
8599a0bf528SMauro Carvalho Chehab } else {
8609a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_ADC_ON);
8619a0bf528SMauro Carvalho Chehab dib7000p_pll_clk_cfg(state);
8629a0bf528SMauro Carvalho Chehab }
8639a0bf528SMauro Carvalho Chehab
8649a0bf528SMauro Carvalho Chehab if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
8659a0bf528SMauro Carvalho Chehab return -1;
8669a0bf528SMauro Carvalho Chehab
8676fe1099cSOlivier Grenie if (demod->ops.tuner_ops.get_frequency) {
8686fe1099cSOlivier Grenie u32 frequency_tuner;
8696fe1099cSOlivier Grenie
8706fe1099cSOlivier Grenie demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
8716fe1099cSOlivier Grenie frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
8726fe1099cSOlivier Grenie }
8736fe1099cSOlivier Grenie
8745332b626SMartin Wache if (dib7000p_set_dds(state, frequency_offset) < 0)
8755332b626SMartin Wache return -1;
8765332b626SMartin Wache
8779a0bf528SMauro Carvalho Chehab ret = 7;
8789a0bf528SMauro Carvalho Chehab (*agc_state)++;
8799a0bf528SMauro Carvalho Chehab break;
8809a0bf528SMauro Carvalho Chehab
8819a0bf528SMauro Carvalho Chehab case 1:
8829a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control)
8839a0bf528SMauro Carvalho Chehab state->cfg.agc_control(&state->demod, 1);
8849a0bf528SMauro Carvalho Chehab
8859a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 78, 32768);
8869a0bf528SMauro Carvalho Chehab if (!state->current_agc->perform_agc_softsplit) {
8879a0bf528SMauro Carvalho Chehab /* we are using the wbd - so slow AGC startup */
8889a0bf528SMauro Carvalho Chehab /* force 0 split on WBD and restart AGC */
8899a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
8909a0bf528SMauro Carvalho Chehab (*agc_state)++;
8919a0bf528SMauro Carvalho Chehab ret = 5;
8929a0bf528SMauro Carvalho Chehab } else {
8939a0bf528SMauro Carvalho Chehab /* default AGC startup */
8949a0bf528SMauro Carvalho Chehab (*agc_state) = 4;
8959a0bf528SMauro Carvalho Chehab /* wait AGC rough lock time */
8969a0bf528SMauro Carvalho Chehab ret = 7;
8979a0bf528SMauro Carvalho Chehab }
8989a0bf528SMauro Carvalho Chehab
8999a0bf528SMauro Carvalho Chehab dib7000p_restart_agc(state);
9009a0bf528SMauro Carvalho Chehab break;
9019a0bf528SMauro Carvalho Chehab
9029a0bf528SMauro Carvalho Chehab case 2: /* fast split search path after 5sec */
9039a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
9049a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
9059a0bf528SMauro Carvalho Chehab (*agc_state)++;
9069a0bf528SMauro Carvalho Chehab ret = 14;
9079a0bf528SMauro Carvalho Chehab break;
9089a0bf528SMauro Carvalho Chehab
9099a0bf528SMauro Carvalho Chehab case 3: /* split search ended */
9109a0bf528SMauro Carvalho Chehab agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
9119a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
9129a0bf528SMauro Carvalho Chehab
9139a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
9149a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
9159a0bf528SMauro Carvalho Chehab
9169a0bf528SMauro Carvalho Chehab dib7000p_restart_agc(state);
9179a0bf528SMauro Carvalho Chehab
9184ec14f24SSean Young dprintk("SPLIT %p: %u\n", demod, agc_split);
9199a0bf528SMauro Carvalho Chehab
9209a0bf528SMauro Carvalho Chehab (*agc_state)++;
9219a0bf528SMauro Carvalho Chehab ret = 5;
9229a0bf528SMauro Carvalho Chehab break;
9239a0bf528SMauro Carvalho Chehab
9249a0bf528SMauro Carvalho Chehab case 4: /* LNA startup */
9259a0bf528SMauro Carvalho Chehab ret = 7;
9269a0bf528SMauro Carvalho Chehab
9279a0bf528SMauro Carvalho Chehab if (dib7000p_update_lna(state))
9289a0bf528SMauro Carvalho Chehab ret = 5;
9299a0bf528SMauro Carvalho Chehab else
9309a0bf528SMauro Carvalho Chehab (*agc_state)++;
9319a0bf528SMauro Carvalho Chehab break;
9329a0bf528SMauro Carvalho Chehab
9339a0bf528SMauro Carvalho Chehab case 5:
9349a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control)
9359a0bf528SMauro Carvalho Chehab state->cfg.agc_control(&state->demod, 0);
9369a0bf528SMauro Carvalho Chehab (*agc_state)++;
9379a0bf528SMauro Carvalho Chehab break;
9389a0bf528SMauro Carvalho Chehab default:
9399a0bf528SMauro Carvalho Chehab break;
9409a0bf528SMauro Carvalho Chehab }
9419a0bf528SMauro Carvalho Chehab return ret;
9429a0bf528SMauro Carvalho Chehab }
9439a0bf528SMauro Carvalho Chehab
dib7000p_update_timf(struct dib7000p_state * state)9449a0bf528SMauro Carvalho Chehab static void dib7000p_update_timf(struct dib7000p_state *state)
9459a0bf528SMauro Carvalho Chehab {
9469a0bf528SMauro Carvalho Chehab u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
9479a0bf528SMauro Carvalho Chehab state->timf = timf * 160 / (state->current_bandwidth / 50);
9489a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 23, (u16) (timf >> 16));
9499a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
9505a0e2a4eSMauro Carvalho Chehab dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->cfg.bw->timf);
9519a0bf528SMauro Carvalho Chehab
9529a0bf528SMauro Carvalho Chehab }
9539a0bf528SMauro Carvalho Chehab
dib7000p_ctrl_timf(struct dvb_frontend * fe,u8 op,u32 timf)9548abe4a0aSMauro Carvalho Chehab static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
9559a0bf528SMauro Carvalho Chehab {
9569a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
9579a0bf528SMauro Carvalho Chehab switch (op) {
9589a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_SET:
9599a0bf528SMauro Carvalho Chehab state->timf = timf;
9609a0bf528SMauro Carvalho Chehab break;
9619a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_UPDATE:
9629a0bf528SMauro Carvalho Chehab dib7000p_update_timf(state);
9639a0bf528SMauro Carvalho Chehab break;
9649a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_GET:
9659a0bf528SMauro Carvalho Chehab break;
9669a0bf528SMauro Carvalho Chehab }
9679a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, state->current_bandwidth);
9689a0bf528SMauro Carvalho Chehab return state->timf;
9699a0bf528SMauro Carvalho Chehab }
9709a0bf528SMauro Carvalho Chehab
dib7000p_set_channel(struct dib7000p_state * state,struct dtv_frontend_properties * ch,u8 seq)9719a0bf528SMauro Carvalho Chehab static void dib7000p_set_channel(struct dib7000p_state *state,
9729a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch, u8 seq)
9739a0bf528SMauro Carvalho Chehab {
9749a0bf528SMauro Carvalho Chehab u16 value, est[4];
9759a0bf528SMauro Carvalho Chehab
9769a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
9779a0bf528SMauro Carvalho Chehab
9789a0bf528SMauro Carvalho Chehab /* nfft, guard, qam, alpha */
9799a0bf528SMauro Carvalho Chehab value = 0;
9809a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) {
9819a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
9829a0bf528SMauro Carvalho Chehab value |= (0 << 7);
9839a0bf528SMauro Carvalho Chehab break;
9849a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
9859a0bf528SMauro Carvalho Chehab value |= (2 << 7);
9869a0bf528SMauro Carvalho Chehab break;
9879a0bf528SMauro Carvalho Chehab default:
9889a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
9899a0bf528SMauro Carvalho Chehab value |= (1 << 7);
9909a0bf528SMauro Carvalho Chehab break;
9919a0bf528SMauro Carvalho Chehab }
9929a0bf528SMauro Carvalho Chehab switch (ch->guard_interval) {
9939a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_32:
9949a0bf528SMauro Carvalho Chehab value |= (0 << 5);
9959a0bf528SMauro Carvalho Chehab break;
9969a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_16:
9979a0bf528SMauro Carvalho Chehab value |= (1 << 5);
9989a0bf528SMauro Carvalho Chehab break;
9999a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_4:
10009a0bf528SMauro Carvalho Chehab value |= (3 << 5);
10019a0bf528SMauro Carvalho Chehab break;
10029a0bf528SMauro Carvalho Chehab default:
10039a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_8:
10049a0bf528SMauro Carvalho Chehab value |= (2 << 5);
10059a0bf528SMauro Carvalho Chehab break;
10069a0bf528SMauro Carvalho Chehab }
10079a0bf528SMauro Carvalho Chehab switch (ch->modulation) {
10089a0bf528SMauro Carvalho Chehab case QPSK:
10099a0bf528SMauro Carvalho Chehab value |= (0 << 3);
10109a0bf528SMauro Carvalho Chehab break;
10119a0bf528SMauro Carvalho Chehab case QAM_16:
10129a0bf528SMauro Carvalho Chehab value |= (1 << 3);
10139a0bf528SMauro Carvalho Chehab break;
10149a0bf528SMauro Carvalho Chehab default:
10159a0bf528SMauro Carvalho Chehab case QAM_64:
10169a0bf528SMauro Carvalho Chehab value |= (2 << 3);
10179a0bf528SMauro Carvalho Chehab break;
10189a0bf528SMauro Carvalho Chehab }
10199a0bf528SMauro Carvalho Chehab switch (HIERARCHY_1) {
10209a0bf528SMauro Carvalho Chehab case HIERARCHY_2:
10219a0bf528SMauro Carvalho Chehab value |= 2;
10229a0bf528SMauro Carvalho Chehab break;
10239a0bf528SMauro Carvalho Chehab case HIERARCHY_4:
10249a0bf528SMauro Carvalho Chehab value |= 4;
10259a0bf528SMauro Carvalho Chehab break;
10269a0bf528SMauro Carvalho Chehab default:
10279a0bf528SMauro Carvalho Chehab case HIERARCHY_1:
10289a0bf528SMauro Carvalho Chehab value |= 1;
10299a0bf528SMauro Carvalho Chehab break;
10309a0bf528SMauro Carvalho Chehab }
10319a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0, value);
10329a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
10339a0bf528SMauro Carvalho Chehab
10349a0bf528SMauro Carvalho Chehab /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
10359a0bf528SMauro Carvalho Chehab value = 0;
10369a0bf528SMauro Carvalho Chehab if (1 != 0)
10379a0bf528SMauro Carvalho Chehab value |= (1 << 6);
10389a0bf528SMauro Carvalho Chehab if (ch->hierarchy == 1)
10399a0bf528SMauro Carvalho Chehab value |= (1 << 4);
10409a0bf528SMauro Carvalho Chehab if (1 == 1)
10419a0bf528SMauro Carvalho Chehab value |= 1;
10429a0bf528SMauro Carvalho Chehab switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
10439a0bf528SMauro Carvalho Chehab case FEC_2_3:
10449a0bf528SMauro Carvalho Chehab value |= (2 << 1);
10459a0bf528SMauro Carvalho Chehab break;
10469a0bf528SMauro Carvalho Chehab case FEC_3_4:
10479a0bf528SMauro Carvalho Chehab value |= (3 << 1);
10489a0bf528SMauro Carvalho Chehab break;
10499a0bf528SMauro Carvalho Chehab case FEC_5_6:
10509a0bf528SMauro Carvalho Chehab value |= (5 << 1);
10519a0bf528SMauro Carvalho Chehab break;
10529a0bf528SMauro Carvalho Chehab case FEC_7_8:
10539a0bf528SMauro Carvalho Chehab value |= (7 << 1);
10549a0bf528SMauro Carvalho Chehab break;
10559a0bf528SMauro Carvalho Chehab default:
10569a0bf528SMauro Carvalho Chehab case FEC_1_2:
10579a0bf528SMauro Carvalho Chehab value |= (1 << 1);
10589a0bf528SMauro Carvalho Chehab break;
10599a0bf528SMauro Carvalho Chehab }
10609a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 208, value);
10619a0bf528SMauro Carvalho Chehab
10629a0bf528SMauro Carvalho Chehab /* offset loop parameters */
10639a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 26, 0x6680);
10649a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 32, 0x0003);
10659a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 29, 0x1273);
10669a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 33, 0x0005);
10679a0bf528SMauro Carvalho Chehab
10689a0bf528SMauro Carvalho Chehab /* P_dvsy_sync_wait */
10699a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) {
10709a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
10719a0bf528SMauro Carvalho Chehab value = 256;
10729a0bf528SMauro Carvalho Chehab break;
10739a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
10749a0bf528SMauro Carvalho Chehab value = 128;
10759a0bf528SMauro Carvalho Chehab break;
10769a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
10779a0bf528SMauro Carvalho Chehab default:
10789a0bf528SMauro Carvalho Chehab value = 64;
10799a0bf528SMauro Carvalho Chehab break;
10809a0bf528SMauro Carvalho Chehab }
10819a0bf528SMauro Carvalho Chehab switch (ch->guard_interval) {
10829a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_16:
10839a0bf528SMauro Carvalho Chehab value *= 2;
10849a0bf528SMauro Carvalho Chehab break;
10859a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_8:
10869a0bf528SMauro Carvalho Chehab value *= 4;
10879a0bf528SMauro Carvalho Chehab break;
10889a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_4:
10899a0bf528SMauro Carvalho Chehab value *= 8;
10909a0bf528SMauro Carvalho Chehab break;
10919a0bf528SMauro Carvalho Chehab default:
10929a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_32:
10939a0bf528SMauro Carvalho Chehab value *= 1;
10949a0bf528SMauro Carvalho Chehab break;
10959a0bf528SMauro Carvalho Chehab }
10969a0bf528SMauro Carvalho Chehab if (state->cfg.diversity_delay == 0)
10979a0bf528SMauro Carvalho Chehab state->div_sync_wait = (value * 3) / 2 + 48;
10989a0bf528SMauro Carvalho Chehab else
10999a0bf528SMauro Carvalho Chehab state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
11009a0bf528SMauro Carvalho Chehab
1101868c9a17SMauro Carvalho Chehab /* deactivate the possibility of diversity reception if extended interleaver */
11029a0bf528SMauro Carvalho Chehab state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
11039a0bf528SMauro Carvalho Chehab dib7000p_set_diversity_in(&state->demod, state->div_state);
11049a0bf528SMauro Carvalho Chehab
11059a0bf528SMauro Carvalho Chehab /* channel estimation fine configuration */
11069a0bf528SMauro Carvalho Chehab switch (ch->modulation) {
11079a0bf528SMauro Carvalho Chehab case QAM_64:
11089a0bf528SMauro Carvalho Chehab est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
11099a0bf528SMauro Carvalho Chehab est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
11109a0bf528SMauro Carvalho Chehab est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
11119a0bf528SMauro Carvalho Chehab est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
11129a0bf528SMauro Carvalho Chehab break;
11139a0bf528SMauro Carvalho Chehab case QAM_16:
11149a0bf528SMauro Carvalho Chehab est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
11159a0bf528SMauro Carvalho Chehab est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
11169a0bf528SMauro Carvalho Chehab est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
11179a0bf528SMauro Carvalho Chehab est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
11189a0bf528SMauro Carvalho Chehab break;
11199a0bf528SMauro Carvalho Chehab default:
11209a0bf528SMauro Carvalho Chehab est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
11219a0bf528SMauro Carvalho Chehab est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
11229a0bf528SMauro Carvalho Chehab est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
11239a0bf528SMauro Carvalho Chehab est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
11249a0bf528SMauro Carvalho Chehab break;
11259a0bf528SMauro Carvalho Chehab }
11269a0bf528SMauro Carvalho Chehab for (value = 0; value < 4; value++)
11279a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 187 + value, est[value]);
11289a0bf528SMauro Carvalho Chehab }
11299a0bf528SMauro Carvalho Chehab
dib7000p_autosearch_start(struct dvb_frontend * demod)11309a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_start(struct dvb_frontend *demod)
11319a0bf528SMauro Carvalho Chehab {
11329a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
11339a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
11349a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties schan;
11359a0bf528SMauro Carvalho Chehab u32 value, factor;
11369a0bf528SMauro Carvalho Chehab u32 internal = dib7000p_get_internal_freq(state);
11379a0bf528SMauro Carvalho Chehab
11389a0bf528SMauro Carvalho Chehab schan = *ch;
11399a0bf528SMauro Carvalho Chehab schan.modulation = QAM_64;
11409a0bf528SMauro Carvalho Chehab schan.guard_interval = GUARD_INTERVAL_1_32;
11419a0bf528SMauro Carvalho Chehab schan.transmission_mode = TRANSMISSION_MODE_8K;
11429a0bf528SMauro Carvalho Chehab schan.code_rate_HP = FEC_2_3;
11439a0bf528SMauro Carvalho Chehab schan.code_rate_LP = FEC_3_4;
11449a0bf528SMauro Carvalho Chehab schan.hierarchy = 0;
11459a0bf528SMauro Carvalho Chehab
11469a0bf528SMauro Carvalho Chehab dib7000p_set_channel(state, &schan, 7);
11479a0bf528SMauro Carvalho Chehab
11489a0bf528SMauro Carvalho Chehab factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
11499a0bf528SMauro Carvalho Chehab if (factor >= 5000) {
11509a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
11519a0bf528SMauro Carvalho Chehab factor = 2;
11529a0bf528SMauro Carvalho Chehab else
11539a0bf528SMauro Carvalho Chehab factor = 1;
11549a0bf528SMauro Carvalho Chehab } else
11559a0bf528SMauro Carvalho Chehab factor = 6;
11569a0bf528SMauro Carvalho Chehab
11579a0bf528SMauro Carvalho Chehab value = 30 * internal * factor;
11589a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
11599a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 7, (u16) (value & 0xffff));
11609a0bf528SMauro Carvalho Chehab value = 100 * internal * factor;
11619a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
11629a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 9, (u16) (value & 0xffff));
11639a0bf528SMauro Carvalho Chehab value = 500 * internal * factor;
11649a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
11659a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 11, (u16) (value & 0xffff));
11669a0bf528SMauro Carvalho Chehab
11679a0bf528SMauro Carvalho Chehab value = dib7000p_read_word(state, 0);
11689a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
11699a0bf528SMauro Carvalho Chehab dib7000p_read_word(state, 1284);
11709a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 0, (u16) value);
11719a0bf528SMauro Carvalho Chehab
11729a0bf528SMauro Carvalho Chehab return 0;
11739a0bf528SMauro Carvalho Chehab }
11749a0bf528SMauro Carvalho Chehab
dib7000p_autosearch_is_irq(struct dvb_frontend * demod)11759a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
11769a0bf528SMauro Carvalho Chehab {
11779a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
11789a0bf528SMauro Carvalho Chehab u16 irq_pending = dib7000p_read_word(state, 1284);
11799a0bf528SMauro Carvalho Chehab
11809a0bf528SMauro Carvalho Chehab if (irq_pending & 0x1)
11819a0bf528SMauro Carvalho Chehab return 1;
11829a0bf528SMauro Carvalho Chehab
11839a0bf528SMauro Carvalho Chehab if (irq_pending & 0x2)
11849a0bf528SMauro Carvalho Chehab return 2;
11859a0bf528SMauro Carvalho Chehab
11869a0bf528SMauro Carvalho Chehab return 0;
11879a0bf528SMauro Carvalho Chehab }
11889a0bf528SMauro Carvalho Chehab
dib7000p_spur_protect(struct dib7000p_state * state,u32 rf_khz,u32 bw)11899a0bf528SMauro Carvalho Chehab static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
11909a0bf528SMauro Carvalho Chehab {
11919de01d22SColin Ian King static const s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
11929de01d22SColin Ian King static const u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
11939a0bf528SMauro Carvalho Chehab 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
11949a0bf528SMauro Carvalho Chehab 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
11959a0bf528SMauro Carvalho Chehab 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
11969a0bf528SMauro Carvalho Chehab 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
11979a0bf528SMauro Carvalho Chehab 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
11989a0bf528SMauro Carvalho Chehab 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
11999a0bf528SMauro Carvalho Chehab 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
12009a0bf528SMauro Carvalho Chehab 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
12019a0bf528SMauro Carvalho Chehab 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
12029a0bf528SMauro Carvalho Chehab 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
12039a0bf528SMauro Carvalho Chehab 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
12049a0bf528SMauro Carvalho Chehab 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
12059a0bf528SMauro Carvalho Chehab 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
12069a0bf528SMauro Carvalho Chehab 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
12079a0bf528SMauro Carvalho Chehab 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
12089a0bf528SMauro Carvalho Chehab 255, 255, 255, 255, 255, 255
12099a0bf528SMauro Carvalho Chehab };
12109a0bf528SMauro Carvalho Chehab
12119a0bf528SMauro Carvalho Chehab u32 xtal = state->cfg.bw->xtal_hz / 1000;
12129a0bf528SMauro Carvalho Chehab int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
12139a0bf528SMauro Carvalho Chehab int k;
12149a0bf528SMauro Carvalho Chehab int coef_re[8], coef_im[8];
12159a0bf528SMauro Carvalho Chehab int bw_khz = bw;
12169a0bf528SMauro Carvalho Chehab u32 pha;
12179a0bf528SMauro Carvalho Chehab
12185a0e2a4eSMauro Carvalho Chehab dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)\n", f_rel, rf_khz, xtal);
12199a0bf528SMauro Carvalho Chehab
12209a0bf528SMauro Carvalho Chehab if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
12219a0bf528SMauro Carvalho Chehab return;
12229a0bf528SMauro Carvalho Chehab
12239a0bf528SMauro Carvalho Chehab bw_khz /= 100;
12249a0bf528SMauro Carvalho Chehab
12259a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 142, 0x0610);
12269a0bf528SMauro Carvalho Chehab
12279a0bf528SMauro Carvalho Chehab for (k = 0; k < 8; k++) {
12289a0bf528SMauro Carvalho Chehab pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
12299a0bf528SMauro Carvalho Chehab
12309a0bf528SMauro Carvalho Chehab if (pha == 0) {
12319a0bf528SMauro Carvalho Chehab coef_re[k] = 256;
12329a0bf528SMauro Carvalho Chehab coef_im[k] = 0;
12339a0bf528SMauro Carvalho Chehab } else if (pha < 256) {
12349a0bf528SMauro Carvalho Chehab coef_re[k] = sine[256 - (pha & 0xff)];
12359a0bf528SMauro Carvalho Chehab coef_im[k] = sine[pha & 0xff];
12369a0bf528SMauro Carvalho Chehab } else if (pha == 256) {
12379a0bf528SMauro Carvalho Chehab coef_re[k] = 0;
12389a0bf528SMauro Carvalho Chehab coef_im[k] = 256;
12399a0bf528SMauro Carvalho Chehab } else if (pha < 512) {
12409a0bf528SMauro Carvalho Chehab coef_re[k] = -sine[pha & 0xff];
12419a0bf528SMauro Carvalho Chehab coef_im[k] = sine[256 - (pha & 0xff)];
12429a0bf528SMauro Carvalho Chehab } else if (pha == 512) {
12439a0bf528SMauro Carvalho Chehab coef_re[k] = -256;
12449a0bf528SMauro Carvalho Chehab coef_im[k] = 0;
12459a0bf528SMauro Carvalho Chehab } else if (pha < 768) {
12469a0bf528SMauro Carvalho Chehab coef_re[k] = -sine[256 - (pha & 0xff)];
12479a0bf528SMauro Carvalho Chehab coef_im[k] = -sine[pha & 0xff];
12489a0bf528SMauro Carvalho Chehab } else if (pha == 768) {
12499a0bf528SMauro Carvalho Chehab coef_re[k] = 0;
12509a0bf528SMauro Carvalho Chehab coef_im[k] = -256;
12519a0bf528SMauro Carvalho Chehab } else {
12529a0bf528SMauro Carvalho Chehab coef_re[k] = sine[pha & 0xff];
12539a0bf528SMauro Carvalho Chehab coef_im[k] = -sine[256 - (pha & 0xff)];
12549a0bf528SMauro Carvalho Chehab }
12559a0bf528SMauro Carvalho Chehab
12569a0bf528SMauro Carvalho Chehab coef_re[k] *= notch[k];
12579a0bf528SMauro Carvalho Chehab coef_re[k] += (1 << 14);
12589a0bf528SMauro Carvalho Chehab if (coef_re[k] >= (1 << 24))
12599a0bf528SMauro Carvalho Chehab coef_re[k] = (1 << 24) - 1;
12609a0bf528SMauro Carvalho Chehab coef_re[k] /= (1 << 15);
12619a0bf528SMauro Carvalho Chehab
12629a0bf528SMauro Carvalho Chehab coef_im[k] *= notch[k];
12639a0bf528SMauro Carvalho Chehab coef_im[k] += (1 << 14);
12649a0bf528SMauro Carvalho Chehab if (coef_im[k] >= (1 << 24))
12659a0bf528SMauro Carvalho Chehab coef_im[k] = (1 << 24) - 1;
12669a0bf528SMauro Carvalho Chehab coef_im[k] /= (1 << 15);
12679a0bf528SMauro Carvalho Chehab
12685a0e2a4eSMauro Carvalho Chehab dprintk("PALF COEF: %d re: %d im: %d\n", k, coef_re[k], coef_im[k]);
12699a0bf528SMauro Carvalho Chehab
12709a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12719a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
12729a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12739a0bf528SMauro Carvalho Chehab }
12749a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 143, 0);
12759a0bf528SMauro Carvalho Chehab }
12769a0bf528SMauro Carvalho Chehab
dib7000p_tune(struct dvb_frontend * demod)12779a0bf528SMauro Carvalho Chehab static int dib7000p_tune(struct dvb_frontend *demod)
12789a0bf528SMauro Carvalho Chehab {
12799a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
12809a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
12819a0bf528SMauro Carvalho Chehab u16 tmp = 0;
12829a0bf528SMauro Carvalho Chehab
12839a0bf528SMauro Carvalho Chehab if (ch != NULL)
12849a0bf528SMauro Carvalho Chehab dib7000p_set_channel(state, ch, 0);
12859a0bf528SMauro Carvalho Chehab else
12869a0bf528SMauro Carvalho Chehab return -EINVAL;
12879a0bf528SMauro Carvalho Chehab
12889a0bf528SMauro Carvalho Chehab // restart demod
12899a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0x4000);
12909a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 770, 0x0000);
12919a0bf528SMauro Carvalho Chehab msleep(45);
12929a0bf528SMauro Carvalho Chehab
12939a0bf528SMauro 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 */
12949a0bf528SMauro Carvalho Chehab tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
12959a0bf528SMauro Carvalho Chehab if (state->sfn_workaround_active) {
12965a0e2a4eSMauro Carvalho Chehab dprintk("SFN workaround is active\n");
12979a0bf528SMauro Carvalho Chehab tmp |= (1 << 9);
12989a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 166, 0x4000);
12999a0bf528SMauro Carvalho Chehab } else {
13009a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 166, 0x0000);
13019a0bf528SMauro Carvalho Chehab }
13029a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 29, tmp);
13039a0bf528SMauro Carvalho Chehab
13049a0bf528SMauro Carvalho Chehab // never achieved a lock with that bandwidth so far - wait for osc-freq to update
13059a0bf528SMauro Carvalho Chehab if (state->timf == 0)
13069a0bf528SMauro Carvalho Chehab msleep(200);
13079a0bf528SMauro Carvalho Chehab
13089a0bf528SMauro Carvalho Chehab /* offset loop parameters */
13099a0bf528SMauro Carvalho Chehab
13109a0bf528SMauro Carvalho Chehab /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
13119a0bf528SMauro Carvalho Chehab tmp = (6 << 8) | 0x80;
13129a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) {
13139a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
13149a0bf528SMauro Carvalho Chehab tmp |= (2 << 12);
13159a0bf528SMauro Carvalho Chehab break;
13169a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
13179a0bf528SMauro Carvalho Chehab tmp |= (3 << 12);
13189a0bf528SMauro Carvalho Chehab break;
13199a0bf528SMauro Carvalho Chehab default:
13209a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
13219a0bf528SMauro Carvalho Chehab tmp |= (4 << 12);
13229a0bf528SMauro Carvalho Chehab break;
13239a0bf528SMauro Carvalho Chehab }
13249a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
13259a0bf528SMauro Carvalho Chehab
13269a0bf528SMauro Carvalho Chehab /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
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, 32, tmp);
13419a0bf528SMauro Carvalho Chehab
13429a0bf528SMauro Carvalho Chehab /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
13439a0bf528SMauro Carvalho Chehab tmp = (0 << 4);
13449a0bf528SMauro Carvalho Chehab switch (ch->transmission_mode) {
13459a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
13469a0bf528SMauro Carvalho Chehab tmp |= 0x6;
13479a0bf528SMauro Carvalho Chehab break;
13489a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
13499a0bf528SMauro Carvalho Chehab tmp |= 0x7;
13509a0bf528SMauro Carvalho Chehab break;
13519a0bf528SMauro Carvalho Chehab default:
13529a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
13539a0bf528SMauro Carvalho Chehab tmp |= 0x8;
13549a0bf528SMauro Carvalho Chehab break;
13559a0bf528SMauro Carvalho Chehab }
13569a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 33, tmp);
13579a0bf528SMauro Carvalho Chehab
13589a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 509);
13599a0bf528SMauro Carvalho Chehab if (!((tmp >> 6) & 0x1)) {
13609a0bf528SMauro Carvalho Chehab /* restart the fec */
13619a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 771);
13629a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, tmp | (1 << 1));
13639a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 771, tmp);
13649a0bf528SMauro Carvalho Chehab msleep(40);
13659a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 509);
13669a0bf528SMauro Carvalho Chehab }
13679a0bf528SMauro Carvalho Chehab // we achieved a lock - it's time to update the osc freq
13689a0bf528SMauro Carvalho Chehab if ((tmp >> 6) & 0x1) {
13699a0bf528SMauro Carvalho Chehab dib7000p_update_timf(state);
13709a0bf528SMauro Carvalho Chehab /* P_timf_alpha += 2 */
13719a0bf528SMauro Carvalho Chehab tmp = dib7000p_read_word(state, 26);
13729a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
13739a0bf528SMauro Carvalho Chehab }
13749a0bf528SMauro Carvalho Chehab
13759a0bf528SMauro Carvalho Chehab if (state->cfg.spur_protect)
13769a0bf528SMauro Carvalho Chehab dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
13779a0bf528SMauro Carvalho Chehab
13789a0bf528SMauro Carvalho Chehab dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
1379041ad449SMauro Carvalho Chehab
1380041ad449SMauro Carvalho Chehab dib7000p_reset_stats(demod);
1381041ad449SMauro Carvalho Chehab
13829a0bf528SMauro Carvalho Chehab return 0;
13839a0bf528SMauro Carvalho Chehab }
13849a0bf528SMauro Carvalho Chehab
dib7000p_wakeup(struct dvb_frontend * demod)13859a0bf528SMauro Carvalho Chehab static int dib7000p_wakeup(struct dvb_frontend *demod)
13869a0bf528SMauro Carvalho Chehab {
13879a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
13889a0bf528SMauro Carvalho Chehab dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
13899a0bf528SMauro Carvalho Chehab dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
13909a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
13919a0bf528SMauro Carvalho Chehab dib7000p_sad_calib(state);
13929a0bf528SMauro Carvalho Chehab return 0;
13939a0bf528SMauro Carvalho Chehab }
13949a0bf528SMauro Carvalho Chehab
dib7000p_sleep(struct dvb_frontend * demod)13959a0bf528SMauro Carvalho Chehab static int dib7000p_sleep(struct dvb_frontend *demod)
13969a0bf528SMauro Carvalho Chehab {
13979a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
13989a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
13999a0bf528SMauro Carvalho Chehab return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
14009a0bf528SMauro Carvalho Chehab return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
14019a0bf528SMauro Carvalho Chehab }
14029a0bf528SMauro Carvalho Chehab
dib7000p_identify(struct dib7000p_state * st)14039a0bf528SMauro Carvalho Chehab static int dib7000p_identify(struct dib7000p_state *st)
14049a0bf528SMauro Carvalho Chehab {
14059a0bf528SMauro Carvalho Chehab u16 value;
14065a0e2a4eSMauro Carvalho Chehab dprintk("checking demod on I2C address: %d (%x)\n", st->i2c_addr, st->i2c_addr);
14079a0bf528SMauro Carvalho Chehab
14089a0bf528SMauro Carvalho Chehab if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
14095a0e2a4eSMauro Carvalho Chehab dprintk("wrong Vendor ID (read=0x%x)\n", value);
14109a0bf528SMauro Carvalho Chehab return -EREMOTEIO;
14119a0bf528SMauro Carvalho Chehab }
14129a0bf528SMauro Carvalho Chehab
14139a0bf528SMauro Carvalho Chehab if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
14145a0e2a4eSMauro Carvalho Chehab dprintk("wrong Device ID (%x)\n", value);
14159a0bf528SMauro Carvalho Chehab return -EREMOTEIO;
14169a0bf528SMauro Carvalho Chehab }
14179a0bf528SMauro Carvalho Chehab
14189a0bf528SMauro Carvalho Chehab return 0;
14199a0bf528SMauro Carvalho Chehab }
14209a0bf528SMauro Carvalho Chehab
dib7000p_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * fep)14217e3e68bcSMauro Carvalho Chehab static int dib7000p_get_frontend(struct dvb_frontend *fe,
14227e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *fep)
14239a0bf528SMauro Carvalho Chehab {
14249a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
14259a0bf528SMauro Carvalho Chehab u16 tps = dib7000p_read_word(state, 463);
14269a0bf528SMauro Carvalho Chehab
14279a0bf528SMauro Carvalho Chehab fep->inversion = INVERSION_AUTO;
14289a0bf528SMauro Carvalho Chehab
14299a0bf528SMauro Carvalho Chehab fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
14309a0bf528SMauro Carvalho Chehab
14319a0bf528SMauro Carvalho Chehab switch ((tps >> 8) & 0x3) {
14329a0bf528SMauro Carvalho Chehab case 0:
14339a0bf528SMauro Carvalho Chehab fep->transmission_mode = TRANSMISSION_MODE_2K;
14349a0bf528SMauro Carvalho Chehab break;
14359a0bf528SMauro Carvalho Chehab case 1:
14369a0bf528SMauro Carvalho Chehab fep->transmission_mode = TRANSMISSION_MODE_8K;
14379a0bf528SMauro Carvalho Chehab break;
14389a0bf528SMauro Carvalho Chehab /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
14399a0bf528SMauro Carvalho Chehab }
14409a0bf528SMauro Carvalho Chehab
14419a0bf528SMauro Carvalho Chehab switch (tps & 0x3) {
14429a0bf528SMauro Carvalho Chehab case 0:
14439a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_32;
14449a0bf528SMauro Carvalho Chehab break;
14459a0bf528SMauro Carvalho Chehab case 1:
14469a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_16;
14479a0bf528SMauro Carvalho Chehab break;
14489a0bf528SMauro Carvalho Chehab case 2:
14499a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_8;
14509a0bf528SMauro Carvalho Chehab break;
14519a0bf528SMauro Carvalho Chehab case 3:
14529a0bf528SMauro Carvalho Chehab fep->guard_interval = GUARD_INTERVAL_1_4;
14539a0bf528SMauro Carvalho Chehab break;
14549a0bf528SMauro Carvalho Chehab }
14559a0bf528SMauro Carvalho Chehab
14569a0bf528SMauro Carvalho Chehab switch ((tps >> 14) & 0x3) {
14579a0bf528SMauro Carvalho Chehab case 0:
14589a0bf528SMauro Carvalho Chehab fep->modulation = QPSK;
14599a0bf528SMauro Carvalho Chehab break;
14609a0bf528SMauro Carvalho Chehab case 1:
14619a0bf528SMauro Carvalho Chehab fep->modulation = QAM_16;
14629a0bf528SMauro Carvalho Chehab break;
14639a0bf528SMauro Carvalho Chehab case 2:
14649a0bf528SMauro Carvalho Chehab default:
14659a0bf528SMauro Carvalho Chehab fep->modulation = QAM_64;
14669a0bf528SMauro Carvalho Chehab break;
14679a0bf528SMauro Carvalho Chehab }
14689a0bf528SMauro Carvalho Chehab
14699a0bf528SMauro Carvalho Chehab /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
14709a0bf528SMauro Carvalho Chehab /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
14719a0bf528SMauro Carvalho Chehab
14729a0bf528SMauro Carvalho Chehab fep->hierarchy = HIERARCHY_NONE;
14739a0bf528SMauro Carvalho Chehab switch ((tps >> 5) & 0x7) {
14749a0bf528SMauro Carvalho Chehab case 1:
14759a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_1_2;
14769a0bf528SMauro Carvalho Chehab break;
14779a0bf528SMauro Carvalho Chehab case 2:
14789a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_2_3;
14799a0bf528SMauro Carvalho Chehab break;
14809a0bf528SMauro Carvalho Chehab case 3:
14819a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_3_4;
14829a0bf528SMauro Carvalho Chehab break;
14839a0bf528SMauro Carvalho Chehab case 5:
14849a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_5_6;
14859a0bf528SMauro Carvalho Chehab break;
14869a0bf528SMauro Carvalho Chehab case 7:
14879a0bf528SMauro Carvalho Chehab default:
14889a0bf528SMauro Carvalho Chehab fep->code_rate_HP = FEC_7_8;
14899a0bf528SMauro Carvalho Chehab break;
14909a0bf528SMauro Carvalho Chehab
14919a0bf528SMauro Carvalho Chehab }
14929a0bf528SMauro Carvalho Chehab
14939a0bf528SMauro Carvalho Chehab switch ((tps >> 2) & 0x7) {
14949a0bf528SMauro Carvalho Chehab case 1:
14959a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_1_2;
14969a0bf528SMauro Carvalho Chehab break;
14979a0bf528SMauro Carvalho Chehab case 2:
14989a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_2_3;
14999a0bf528SMauro Carvalho Chehab break;
15009a0bf528SMauro Carvalho Chehab case 3:
15019a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_3_4;
15029a0bf528SMauro Carvalho Chehab break;
15039a0bf528SMauro Carvalho Chehab case 5:
15049a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_5_6;
15059a0bf528SMauro Carvalho Chehab break;
15069a0bf528SMauro Carvalho Chehab case 7:
15079a0bf528SMauro Carvalho Chehab default:
15089a0bf528SMauro Carvalho Chehab fep->code_rate_LP = FEC_7_8;
15099a0bf528SMauro Carvalho Chehab break;
15109a0bf528SMauro Carvalho Chehab }
15119a0bf528SMauro Carvalho Chehab
15129a0bf528SMauro Carvalho Chehab /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
15139a0bf528SMauro Carvalho Chehab
15149a0bf528SMauro Carvalho Chehab return 0;
15159a0bf528SMauro Carvalho Chehab }
15169a0bf528SMauro Carvalho Chehab
dib7000p_set_frontend(struct dvb_frontend * fe)15179a0bf528SMauro Carvalho Chehab static int dib7000p_set_frontend(struct dvb_frontend *fe)
15189a0bf528SMauro Carvalho Chehab {
15199a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
15209a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
15219a0bf528SMauro Carvalho Chehab int time, ret;
15229a0bf528SMauro Carvalho Chehab
15239a0bf528SMauro Carvalho Chehab if (state->version == SOC7090)
15249a0bf528SMauro Carvalho Chehab dib7090_set_diversity_in(fe, 0);
15259a0bf528SMauro Carvalho Chehab else
15269a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
15279a0bf528SMauro Carvalho Chehab
15289a0bf528SMauro Carvalho Chehab /* maybe the parameter has been changed */
15299a0bf528SMauro Carvalho Chehab state->sfn_workaround_active = buggy_sfn_workaround;
15309a0bf528SMauro Carvalho Chehab
15319a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params)
15329a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe);
15339a0bf528SMauro Carvalho Chehab
15349a0bf528SMauro Carvalho Chehab /* start up the AGC */
15359a0bf528SMauro Carvalho Chehab state->agc_state = 0;
15369a0bf528SMauro Carvalho Chehab do {
15379a0bf528SMauro Carvalho Chehab time = dib7000p_agc_startup(fe);
15389a0bf528SMauro Carvalho Chehab if (time != -1)
15399a0bf528SMauro Carvalho Chehab msleep(time);
15409a0bf528SMauro Carvalho Chehab } while (time != -1);
15419a0bf528SMauro Carvalho Chehab
15429a0bf528SMauro Carvalho Chehab if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
15439a0bf528SMauro Carvalho Chehab fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
15449a0bf528SMauro Carvalho Chehab int i = 800, found;
15459a0bf528SMauro Carvalho Chehab
15469a0bf528SMauro Carvalho Chehab dib7000p_autosearch_start(fe);
15479a0bf528SMauro Carvalho Chehab do {
15489a0bf528SMauro Carvalho Chehab msleep(1);
15499a0bf528SMauro Carvalho Chehab found = dib7000p_autosearch_is_irq(fe);
15509a0bf528SMauro Carvalho Chehab } while (found == 0 && i--);
15519a0bf528SMauro Carvalho Chehab
15525a0e2a4eSMauro Carvalho Chehab dprintk("autosearch returns: %d\n", found);
15539a0bf528SMauro Carvalho Chehab if (found == 0 || found == 1)
15549a0bf528SMauro Carvalho Chehab return 0;
15559a0bf528SMauro Carvalho Chehab
15567e3e68bcSMauro Carvalho Chehab dib7000p_get_frontend(fe, fep);
15579a0bf528SMauro Carvalho Chehab }
15589a0bf528SMauro Carvalho Chehab
15599a0bf528SMauro Carvalho Chehab ret = dib7000p_tune(fe);
15609a0bf528SMauro Carvalho Chehab
15619a0bf528SMauro Carvalho Chehab /* make this a config parameter */
15629a0bf528SMauro Carvalho Chehab if (state->version == SOC7090) {
15639a0bf528SMauro Carvalho Chehab dib7090_set_output_mode(fe, state->cfg.output_mode);
15649a0bf528SMauro Carvalho Chehab if (state->cfg.enMpegOutput == 0) {
15659a0bf528SMauro Carvalho Chehab dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
15669a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15679a0bf528SMauro Carvalho Chehab }
15689a0bf528SMauro Carvalho Chehab } else
15699a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(state, state->cfg.output_mode);
15709a0bf528SMauro Carvalho Chehab
15719a0bf528SMauro Carvalho Chehab return ret;
15729a0bf528SMauro Carvalho Chehab }
15739a0bf528SMauro Carvalho Chehab
15740df289a2SMauro Carvalho Chehab static int dib7000p_get_stats(struct dvb_frontend *fe, enum fe_status stat);
1575041ad449SMauro Carvalho Chehab
dib7000p_read_status(struct dvb_frontend * fe,enum fe_status * stat)15760df289a2SMauro Carvalho Chehab static int dib7000p_read_status(struct dvb_frontend *fe, enum fe_status *stat)
15779a0bf528SMauro Carvalho Chehab {
15789a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
15799a0bf528SMauro Carvalho Chehab u16 lock = dib7000p_read_word(state, 509);
15809a0bf528SMauro Carvalho Chehab
15819a0bf528SMauro Carvalho Chehab *stat = 0;
15829a0bf528SMauro Carvalho Chehab
15839a0bf528SMauro Carvalho Chehab if (lock & 0x8000)
15849a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SIGNAL;
15859a0bf528SMauro Carvalho Chehab if (lock & 0x3000)
15869a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_CARRIER;
15879a0bf528SMauro Carvalho Chehab if (lock & 0x0100)
15889a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI;
15899a0bf528SMauro Carvalho Chehab if (lock & 0x0010)
15909a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SYNC;
15919a0bf528SMauro Carvalho Chehab if ((lock & 0x0038) == 0x38)
15929a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_LOCK;
15939a0bf528SMauro Carvalho Chehab
1594041ad449SMauro Carvalho Chehab dib7000p_get_stats(fe, *stat);
1595041ad449SMauro Carvalho Chehab
15969a0bf528SMauro Carvalho Chehab return 0;
15979a0bf528SMauro Carvalho Chehab }
15989a0bf528SMauro Carvalho Chehab
dib7000p_read_ber(struct dvb_frontend * fe,u32 * ber)15999a0bf528SMauro Carvalho Chehab static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
16009a0bf528SMauro Carvalho Chehab {
16019a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
16029a0bf528SMauro Carvalho Chehab *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
16039a0bf528SMauro Carvalho Chehab return 0;
16049a0bf528SMauro Carvalho Chehab }
16059a0bf528SMauro Carvalho Chehab
dib7000p_read_unc_blocks(struct dvb_frontend * fe,u32 * unc)16069a0bf528SMauro Carvalho Chehab static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
16079a0bf528SMauro Carvalho Chehab {
16089a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
16099a0bf528SMauro Carvalho Chehab *unc = dib7000p_read_word(state, 506);
16109a0bf528SMauro Carvalho Chehab return 0;
16119a0bf528SMauro Carvalho Chehab }
16129a0bf528SMauro Carvalho Chehab
dib7000p_read_signal_strength(struct dvb_frontend * fe,u16 * strength)16139a0bf528SMauro Carvalho Chehab static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
16149a0bf528SMauro Carvalho Chehab {
16159a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
16169a0bf528SMauro Carvalho Chehab u16 val = dib7000p_read_word(state, 394);
16179a0bf528SMauro Carvalho Chehab *strength = 65535 - val;
16189a0bf528SMauro Carvalho Chehab return 0;
16199a0bf528SMauro Carvalho Chehab }
16209a0bf528SMauro Carvalho Chehab
dib7000p_get_snr(struct dvb_frontend * fe)1621041ad449SMauro Carvalho Chehab static u32 dib7000p_get_snr(struct dvb_frontend *fe)
16229a0bf528SMauro Carvalho Chehab {
16239a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
16249a0bf528SMauro Carvalho Chehab u16 val;
16259a0bf528SMauro Carvalho Chehab s32 signal_mant, signal_exp, noise_mant, noise_exp;
16269a0bf528SMauro Carvalho Chehab u32 result = 0;
16279a0bf528SMauro Carvalho Chehab
16289a0bf528SMauro Carvalho Chehab val = dib7000p_read_word(state, 479);
16299a0bf528SMauro Carvalho Chehab noise_mant = (val >> 4) & 0xff;
16309a0bf528SMauro Carvalho Chehab noise_exp = ((val & 0xf) << 2);
16319a0bf528SMauro Carvalho Chehab val = dib7000p_read_word(state, 480);
16329a0bf528SMauro Carvalho Chehab noise_exp += ((val >> 14) & 0x3);
16339a0bf528SMauro Carvalho Chehab if ((noise_exp & 0x20) != 0)
16349a0bf528SMauro Carvalho Chehab noise_exp -= 0x40;
16359a0bf528SMauro Carvalho Chehab
16369a0bf528SMauro Carvalho Chehab signal_mant = (val >> 6) & 0xFF;
16379a0bf528SMauro Carvalho Chehab signal_exp = (val & 0x3F);
16389a0bf528SMauro Carvalho Chehab if ((signal_exp & 0x20) != 0)
16399a0bf528SMauro Carvalho Chehab signal_exp -= 0x40;
16409a0bf528SMauro Carvalho Chehab
16419a0bf528SMauro Carvalho Chehab if (signal_mant != 0)
16429a0bf528SMauro Carvalho Chehab result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
16439a0bf528SMauro Carvalho Chehab else
16449a0bf528SMauro Carvalho Chehab result = intlog10(2) * 10 * signal_exp - 100;
16459a0bf528SMauro Carvalho Chehab
16469a0bf528SMauro Carvalho Chehab if (noise_mant != 0)
16479a0bf528SMauro Carvalho Chehab result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
16489a0bf528SMauro Carvalho Chehab else
16499a0bf528SMauro Carvalho Chehab result -= intlog10(2) * 10 * noise_exp - 100;
16509a0bf528SMauro Carvalho Chehab
1651041ad449SMauro Carvalho Chehab return result;
1652041ad449SMauro Carvalho Chehab }
1653041ad449SMauro Carvalho Chehab
dib7000p_read_snr(struct dvb_frontend * fe,u16 * snr)1654041ad449SMauro Carvalho Chehab static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
1655041ad449SMauro Carvalho Chehab {
1656041ad449SMauro Carvalho Chehab u32 result;
1657041ad449SMauro Carvalho Chehab
1658041ad449SMauro Carvalho Chehab result = dib7000p_get_snr(fe);
1659041ad449SMauro Carvalho Chehab
16609a0bf528SMauro Carvalho Chehab *snr = result / ((1 << 24) / 10);
16619a0bf528SMauro Carvalho Chehab return 0;
16629a0bf528SMauro Carvalho Chehab }
16639a0bf528SMauro Carvalho Chehab
dib7000p_reset_stats(struct dvb_frontend * demod)1664041ad449SMauro Carvalho Chehab static void dib7000p_reset_stats(struct dvb_frontend *demod)
1665041ad449SMauro Carvalho Chehab {
1666041ad449SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
1667041ad449SMauro Carvalho Chehab struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1668041ad449SMauro Carvalho Chehab u32 ucb;
1669041ad449SMauro Carvalho Chehab
1670041ad449SMauro Carvalho Chehab memset(&c->strength, 0, sizeof(c->strength));
1671041ad449SMauro Carvalho Chehab memset(&c->cnr, 0, sizeof(c->cnr));
1672041ad449SMauro Carvalho Chehab memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1673041ad449SMauro Carvalho Chehab memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1674041ad449SMauro Carvalho Chehab memset(&c->block_error, 0, sizeof(c->block_error));
1675041ad449SMauro Carvalho Chehab
1676041ad449SMauro Carvalho Chehab c->strength.len = 1;
1677041ad449SMauro Carvalho Chehab c->cnr.len = 1;
1678041ad449SMauro Carvalho Chehab c->block_error.len = 1;
1679041ad449SMauro Carvalho Chehab c->block_count.len = 1;
1680041ad449SMauro Carvalho Chehab c->post_bit_error.len = 1;
1681041ad449SMauro Carvalho Chehab c->post_bit_count.len = 1;
1682041ad449SMauro Carvalho Chehab
1683041ad449SMauro Carvalho Chehab c->strength.stat[0].scale = FE_SCALE_DECIBEL;
1684041ad449SMauro Carvalho Chehab c->strength.stat[0].uvalue = 0;
1685041ad449SMauro Carvalho Chehab
1686041ad449SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1687041ad449SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1688041ad449SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1689041ad449SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1690041ad449SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1691041ad449SMauro Carvalho Chehab
1692041ad449SMauro Carvalho Chehab dib7000p_read_unc_blocks(demod, &ucb);
1693041ad449SMauro Carvalho Chehab
1694041ad449SMauro Carvalho Chehab state->old_ucb = ucb;
1695041ad449SMauro Carvalho Chehab state->ber_jiffies_stats = 0;
1696041ad449SMauro Carvalho Chehab state->per_jiffies_stats = 0;
1697041ad449SMauro Carvalho Chehab }
1698041ad449SMauro Carvalho Chehab
1699041ad449SMauro Carvalho Chehab struct linear_segments {
1700041ad449SMauro Carvalho Chehab unsigned x;
1701041ad449SMauro Carvalho Chehab signed y;
1702041ad449SMauro Carvalho Chehab };
1703041ad449SMauro Carvalho Chehab
1704041ad449SMauro Carvalho Chehab /*
1705041ad449SMauro Carvalho Chehab * Table to estimate signal strength in dBm.
1706041ad449SMauro Carvalho Chehab * This table should be empirically determinated by measuring the signal
1707041ad449SMauro Carvalho Chehab * strength generated by a RF generator directly connected into
1708041ad449SMauro Carvalho Chehab * a device.
17093926d91aSMauro Carvalho Chehab * This table was determinated by measuring the signal strength generated
17103926d91aSMauro Carvalho Chehab * by a DTA-2111 RF generator directly connected into a dib7000p device
17113926d91aSMauro Carvalho Chehab * (a Hauppauge Nova-TD stick), using a good quality 3 meters length
17123926d91aSMauro Carvalho Chehab * RC6 cable and good RC6 connectors, connected directly to antenna 1.
17133926d91aSMauro Carvalho Chehab * As the minimum output power of DTA-2111 is -31dBm, a 16 dBm attenuator
17143926d91aSMauro Carvalho Chehab * were used, for the lower power values.
17153926d91aSMauro Carvalho Chehab * The real value can actually be on other devices, or even at the
17163926d91aSMauro Carvalho Chehab * second antena input, depending on several factors, like if LNA
17173926d91aSMauro Carvalho Chehab * is enabled or not, if diversity is enabled, type of connectors, etc.
17183926d91aSMauro Carvalho Chehab * Yet, it is better to use this measure in dB than a random non-linear
17193926d91aSMauro Carvalho Chehab * percentage value, especially for antenna adjustments.
17203926d91aSMauro Carvalho Chehab * On my tests, the precision of the measure using this table is about
17213926d91aSMauro Carvalho Chehab * 0.5 dB, with sounds reasonable enough to adjust antennas.
1722041ad449SMauro Carvalho Chehab */
17233926d91aSMauro Carvalho Chehab #define DB_OFFSET 131000
1724041ad449SMauro Carvalho Chehab
1725041ad449SMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
17263926d91aSMauro Carvalho Chehab { 63630, DB_OFFSET - 20500},
17273926d91aSMauro Carvalho Chehab { 62273, DB_OFFSET - 21000},
17283926d91aSMauro Carvalho Chehab { 60162, DB_OFFSET - 22000},
17293926d91aSMauro Carvalho Chehab { 58730, DB_OFFSET - 23000},
17303926d91aSMauro Carvalho Chehab { 58294, DB_OFFSET - 24000},
17313926d91aSMauro Carvalho Chehab { 57778, DB_OFFSET - 25000},
17323926d91aSMauro Carvalho Chehab { 57320, DB_OFFSET - 26000},
17333926d91aSMauro Carvalho Chehab { 56779, DB_OFFSET - 27000},
17343926d91aSMauro Carvalho Chehab { 56293, DB_OFFSET - 28000},
17353926d91aSMauro Carvalho Chehab { 55724, DB_OFFSET - 29000},
17363926d91aSMauro Carvalho Chehab { 55145, DB_OFFSET - 30000},
17373926d91aSMauro Carvalho Chehab { 54680, DB_OFFSET - 31000},
17383926d91aSMauro Carvalho Chehab { 54293, DB_OFFSET - 32000},
17393926d91aSMauro Carvalho Chehab { 53813, DB_OFFSET - 33000},
17403926d91aSMauro Carvalho Chehab { 53427, DB_OFFSET - 34000},
17413926d91aSMauro Carvalho Chehab { 52981, DB_OFFSET - 35000},
17423926d91aSMauro Carvalho Chehab
17433926d91aSMauro Carvalho Chehab { 52636, DB_OFFSET - 36000},
17443926d91aSMauro Carvalho Chehab { 52014, DB_OFFSET - 37000},
17453926d91aSMauro Carvalho Chehab { 51674, DB_OFFSET - 38000},
17463926d91aSMauro Carvalho Chehab { 50692, DB_OFFSET - 39000},
17473926d91aSMauro Carvalho Chehab { 49824, DB_OFFSET - 40000},
17483926d91aSMauro Carvalho Chehab { 49052, DB_OFFSET - 41000},
17493926d91aSMauro Carvalho Chehab { 48436, DB_OFFSET - 42000},
17503926d91aSMauro Carvalho Chehab { 47836, DB_OFFSET - 43000},
17513926d91aSMauro Carvalho Chehab { 47368, DB_OFFSET - 44000},
17523926d91aSMauro Carvalho Chehab { 46468, DB_OFFSET - 45000},
17533926d91aSMauro Carvalho Chehab { 45597, DB_OFFSET - 46000},
17543926d91aSMauro Carvalho Chehab { 44586, DB_OFFSET - 47000},
17553926d91aSMauro Carvalho Chehab { 43667, DB_OFFSET - 48000},
17563926d91aSMauro Carvalho Chehab { 42673, DB_OFFSET - 49000},
17573926d91aSMauro Carvalho Chehab { 41816, DB_OFFSET - 50000},
17583926d91aSMauro Carvalho Chehab { 40876, DB_OFFSET - 51000},
1759041ad449SMauro Carvalho Chehab { 0, 0},
1760041ad449SMauro Carvalho Chehab };
1761041ad449SMauro Carvalho Chehab
interpolate_value(u32 value,struct linear_segments * segments,unsigned len)1762041ad449SMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
1763041ad449SMauro Carvalho Chehab unsigned len)
1764041ad449SMauro Carvalho Chehab {
1765041ad449SMauro Carvalho Chehab u64 tmp64;
1766041ad449SMauro Carvalho Chehab u32 dx;
1767041ad449SMauro Carvalho Chehab s32 dy;
1768041ad449SMauro Carvalho Chehab int i, ret;
1769041ad449SMauro Carvalho Chehab
1770041ad449SMauro Carvalho Chehab if (value >= segments[0].x)
1771041ad449SMauro Carvalho Chehab return segments[0].y;
1772041ad449SMauro Carvalho Chehab if (value < segments[len-1].x)
1773041ad449SMauro Carvalho Chehab return segments[len-1].y;
1774041ad449SMauro Carvalho Chehab
1775041ad449SMauro Carvalho Chehab for (i = 1; i < len - 1; i++) {
1776041ad449SMauro Carvalho Chehab /* If value is identical, no need to interpolate */
1777041ad449SMauro Carvalho Chehab if (value == segments[i].x)
1778041ad449SMauro Carvalho Chehab return segments[i].y;
1779041ad449SMauro Carvalho Chehab if (value > segments[i].x)
1780041ad449SMauro Carvalho Chehab break;
1781041ad449SMauro Carvalho Chehab }
1782041ad449SMauro Carvalho Chehab
1783041ad449SMauro Carvalho Chehab /* Linear interpolation between the two (x,y) points */
1784041ad449SMauro Carvalho Chehab dy = segments[i - 1].y - segments[i].y;
1785041ad449SMauro Carvalho Chehab dx = segments[i - 1].x - segments[i].x;
1786041ad449SMauro Carvalho Chehab
1787041ad449SMauro Carvalho Chehab tmp64 = value - segments[i].x;
1788041ad449SMauro Carvalho Chehab tmp64 *= dy;
1789041ad449SMauro Carvalho Chehab do_div(tmp64, dx);
1790041ad449SMauro Carvalho Chehab ret = segments[i].y + tmp64;
1791041ad449SMauro Carvalho Chehab
1792041ad449SMauro Carvalho Chehab return ret;
1793041ad449SMauro Carvalho Chehab }
1794041ad449SMauro Carvalho Chehab
1795041ad449SMauro Carvalho Chehab /* FIXME: may require changes - this one was borrowed from dib8000 */
dib7000p_get_time_us(struct dvb_frontend * demod)1796986f1686SMauro Carvalho Chehab static u32 dib7000p_get_time_us(struct dvb_frontend *demod)
1797041ad449SMauro Carvalho Chehab {
1798041ad449SMauro Carvalho Chehab struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1799041ad449SMauro Carvalho Chehab u64 time_us, tmp64;
1800041ad449SMauro Carvalho Chehab u32 tmp, denom;
1801041ad449SMauro Carvalho Chehab int guard, rate_num, rate_denum = 1, bits_per_symbol;
1802041ad449SMauro Carvalho Chehab int interleaving = 0, fft_div;
1803041ad449SMauro Carvalho Chehab
1804041ad449SMauro Carvalho Chehab switch (c->guard_interval) {
1805041ad449SMauro Carvalho Chehab case GUARD_INTERVAL_1_4:
1806041ad449SMauro Carvalho Chehab guard = 4;
1807041ad449SMauro Carvalho Chehab break;
1808041ad449SMauro Carvalho Chehab case GUARD_INTERVAL_1_8:
1809041ad449SMauro Carvalho Chehab guard = 8;
1810041ad449SMauro Carvalho Chehab break;
1811041ad449SMauro Carvalho Chehab case GUARD_INTERVAL_1_16:
1812041ad449SMauro Carvalho Chehab guard = 16;
1813041ad449SMauro Carvalho Chehab break;
1814041ad449SMauro Carvalho Chehab default:
1815041ad449SMauro Carvalho Chehab case GUARD_INTERVAL_1_32:
1816041ad449SMauro Carvalho Chehab guard = 32;
1817041ad449SMauro Carvalho Chehab break;
1818041ad449SMauro Carvalho Chehab }
1819041ad449SMauro Carvalho Chehab
1820041ad449SMauro Carvalho Chehab switch (c->transmission_mode) {
1821041ad449SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
1822041ad449SMauro Carvalho Chehab fft_div = 4;
1823041ad449SMauro Carvalho Chehab break;
1824041ad449SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
1825041ad449SMauro Carvalho Chehab fft_div = 2;
1826041ad449SMauro Carvalho Chehab break;
1827041ad449SMauro Carvalho Chehab default:
1828041ad449SMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
1829041ad449SMauro Carvalho Chehab fft_div = 1;
1830041ad449SMauro Carvalho Chehab break;
1831041ad449SMauro Carvalho Chehab }
1832041ad449SMauro Carvalho Chehab
1833041ad449SMauro Carvalho Chehab switch (c->modulation) {
1834041ad449SMauro Carvalho Chehab case DQPSK:
1835041ad449SMauro Carvalho Chehab case QPSK:
1836041ad449SMauro Carvalho Chehab bits_per_symbol = 2;
1837041ad449SMauro Carvalho Chehab break;
1838041ad449SMauro Carvalho Chehab case QAM_16:
1839041ad449SMauro Carvalho Chehab bits_per_symbol = 4;
1840041ad449SMauro Carvalho Chehab break;
1841041ad449SMauro Carvalho Chehab default:
1842041ad449SMauro Carvalho Chehab case QAM_64:
1843041ad449SMauro Carvalho Chehab bits_per_symbol = 6;
1844041ad449SMauro Carvalho Chehab break;
1845041ad449SMauro Carvalho Chehab }
1846041ad449SMauro Carvalho Chehab
1847041ad449SMauro Carvalho Chehab switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
1848041ad449SMauro Carvalho Chehab case FEC_1_2:
1849041ad449SMauro Carvalho Chehab rate_num = 1;
1850041ad449SMauro Carvalho Chehab rate_denum = 2;
1851041ad449SMauro Carvalho Chehab break;
1852041ad449SMauro Carvalho Chehab case FEC_2_3:
1853041ad449SMauro Carvalho Chehab rate_num = 2;
1854041ad449SMauro Carvalho Chehab rate_denum = 3;
1855041ad449SMauro Carvalho Chehab break;
1856041ad449SMauro Carvalho Chehab case FEC_3_4:
1857041ad449SMauro Carvalho Chehab rate_num = 3;
1858041ad449SMauro Carvalho Chehab rate_denum = 4;
1859041ad449SMauro Carvalho Chehab break;
1860041ad449SMauro Carvalho Chehab case FEC_5_6:
1861041ad449SMauro Carvalho Chehab rate_num = 5;
1862041ad449SMauro Carvalho Chehab rate_denum = 6;
1863041ad449SMauro Carvalho Chehab break;
1864041ad449SMauro Carvalho Chehab default:
1865041ad449SMauro Carvalho Chehab case FEC_7_8:
1866041ad449SMauro Carvalho Chehab rate_num = 7;
1867041ad449SMauro Carvalho Chehab rate_denum = 8;
1868041ad449SMauro Carvalho Chehab break;
1869041ad449SMauro Carvalho Chehab }
1870041ad449SMauro Carvalho Chehab
1871041ad449SMauro Carvalho Chehab denom = bits_per_symbol * rate_num * fft_div * 384;
1872041ad449SMauro Carvalho Chehab
1873d95947c0SSean Young /*
1874d95947c0SSean Young * FIXME: check if the math makes sense. If so, fill the
1875d95947c0SSean Young * interleaving var.
1876d95947c0SSean Young */
1877d95947c0SSean Young
1878041ad449SMauro Carvalho Chehab /* If calculus gets wrong, wait for 1s for the next stats */
1879041ad449SMauro Carvalho Chehab if (!denom)
1880041ad449SMauro Carvalho Chehab return 0;
1881041ad449SMauro Carvalho Chehab
1882041ad449SMauro Carvalho Chehab /* Estimate the period for the total bit rate */
1883041ad449SMauro Carvalho Chehab time_us = rate_denum * (1008 * 1562500L);
1884041ad449SMauro Carvalho Chehab tmp64 = time_us;
1885041ad449SMauro Carvalho Chehab do_div(tmp64, guard);
1886041ad449SMauro Carvalho Chehab time_us = time_us + tmp64;
1887041ad449SMauro Carvalho Chehab time_us += denom / 2;
1888041ad449SMauro Carvalho Chehab do_div(time_us, denom);
1889041ad449SMauro Carvalho Chehab
1890041ad449SMauro Carvalho Chehab tmp = 1008 * 96 * interleaving;
1891041ad449SMauro Carvalho Chehab time_us += tmp + tmp / guard;
1892041ad449SMauro Carvalho Chehab
1893041ad449SMauro Carvalho Chehab return time_us;
1894041ad449SMauro Carvalho Chehab }
1895041ad449SMauro Carvalho Chehab
dib7000p_get_stats(struct dvb_frontend * demod,enum fe_status stat)18960df289a2SMauro Carvalho Chehab static int dib7000p_get_stats(struct dvb_frontend *demod, enum fe_status stat)
1897041ad449SMauro Carvalho Chehab {
1898041ad449SMauro Carvalho Chehab struct dib7000p_state *state = demod->demodulator_priv;
1899041ad449SMauro Carvalho Chehab struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1900041ad449SMauro Carvalho Chehab int show_per_stats = 0;
1901041ad449SMauro Carvalho Chehab u32 time_us = 0, val, snr;
1902041ad449SMauro Carvalho Chehab u64 blocks, ucb;
1903041ad449SMauro Carvalho Chehab s32 db;
1904041ad449SMauro Carvalho Chehab u16 strength;
1905041ad449SMauro Carvalho Chehab
1906041ad449SMauro Carvalho Chehab /* Get Signal strength */
1907041ad449SMauro Carvalho Chehab dib7000p_read_signal_strength(demod, &strength);
1908041ad449SMauro Carvalho Chehab val = strength;
1909041ad449SMauro Carvalho Chehab db = interpolate_value(val,
1910041ad449SMauro Carvalho Chehab strength_to_db_table,
1911041ad449SMauro Carvalho Chehab ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
1912041ad449SMauro Carvalho Chehab c->strength.stat[0].svalue = db;
1913041ad449SMauro Carvalho Chehab
1914041ad449SMauro Carvalho Chehab /* UCB/BER/CNR measures require lock */
1915041ad449SMauro Carvalho Chehab if (!(stat & FE_HAS_LOCK)) {
1916041ad449SMauro Carvalho Chehab c->cnr.len = 1;
1917041ad449SMauro Carvalho Chehab c->block_count.len = 1;
1918041ad449SMauro Carvalho Chehab c->block_error.len = 1;
1919041ad449SMauro Carvalho Chehab c->post_bit_error.len = 1;
1920041ad449SMauro Carvalho Chehab c->post_bit_count.len = 1;
1921041ad449SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1922041ad449SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1923041ad449SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1924041ad449SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1925041ad449SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1926041ad449SMauro Carvalho Chehab return 0;
1927041ad449SMauro Carvalho Chehab }
1928041ad449SMauro Carvalho Chehab
1929041ad449SMauro Carvalho Chehab /* Check if time for stats was elapsed */
1930041ad449SMauro Carvalho Chehab if (time_after(jiffies, state->per_jiffies_stats)) {
1931041ad449SMauro Carvalho Chehab state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
1932041ad449SMauro Carvalho Chehab
1933041ad449SMauro Carvalho Chehab /* Get SNR */
1934041ad449SMauro Carvalho Chehab snr = dib7000p_get_snr(demod);
1935041ad449SMauro Carvalho Chehab if (snr)
1936041ad449SMauro Carvalho Chehab snr = (1000L * snr) >> 24;
1937041ad449SMauro Carvalho Chehab else
1938041ad449SMauro Carvalho Chehab snr = 0;
1939041ad449SMauro Carvalho Chehab c->cnr.stat[0].svalue = snr;
1940041ad449SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1941041ad449SMauro Carvalho Chehab
1942041ad449SMauro Carvalho Chehab /* Get UCB measures */
1943041ad449SMauro Carvalho Chehab dib7000p_read_unc_blocks(demod, &val);
1944041ad449SMauro Carvalho Chehab ucb = val - state->old_ucb;
1945041ad449SMauro Carvalho Chehab if (val < state->old_ucb)
1946041ad449SMauro Carvalho Chehab ucb += 0x100000000LL;
1947041ad449SMauro Carvalho Chehab
1948041ad449SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1949041ad449SMauro Carvalho Chehab c->block_error.stat[0].uvalue = ucb;
1950041ad449SMauro Carvalho Chehab
1951041ad449SMauro Carvalho Chehab /* Estimate the number of packets based on bitrate */
1952041ad449SMauro Carvalho Chehab if (!time_us)
1953986f1686SMauro Carvalho Chehab time_us = dib7000p_get_time_us(demod);
1954041ad449SMauro Carvalho Chehab
1955041ad449SMauro Carvalho Chehab if (time_us) {
1956041ad449SMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL;
1957041ad449SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204);
1958041ad449SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1959041ad449SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks;
1960041ad449SMauro Carvalho Chehab }
1961041ad449SMauro Carvalho Chehab
1962041ad449SMauro Carvalho Chehab show_per_stats = 1;
1963041ad449SMauro Carvalho Chehab }
1964041ad449SMauro Carvalho Chehab
1965041ad449SMauro Carvalho Chehab /* Get post-BER measures */
1966041ad449SMauro Carvalho Chehab if (time_after(jiffies, state->ber_jiffies_stats)) {
1967986f1686SMauro Carvalho Chehab time_us = dib7000p_get_time_us(demod);
1968041ad449SMauro Carvalho Chehab state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
1969041ad449SMauro Carvalho Chehab
19705a0e2a4eSMauro Carvalho Chehab dprintk("Next all layers stats available in %u us.\n", time_us);
1971041ad449SMauro Carvalho Chehab
1972041ad449SMauro Carvalho Chehab dib7000p_read_ber(demod, &val);
1973041ad449SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
1974041ad449SMauro Carvalho Chehab c->post_bit_error.stat[0].uvalue += val;
1975041ad449SMauro Carvalho Chehab
1976041ad449SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
1977041ad449SMauro Carvalho Chehab c->post_bit_count.stat[0].uvalue += 100000000;
1978041ad449SMauro Carvalho Chehab }
1979041ad449SMauro Carvalho Chehab
1980041ad449SMauro Carvalho Chehab /* Get PER measures */
1981041ad449SMauro Carvalho Chehab if (show_per_stats) {
1982041ad449SMauro Carvalho Chehab dib7000p_read_unc_blocks(demod, &val);
1983041ad449SMauro Carvalho Chehab
1984041ad449SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1985041ad449SMauro Carvalho Chehab c->block_error.stat[0].uvalue += val;
1986041ad449SMauro Carvalho Chehab
1987986f1686SMauro Carvalho Chehab time_us = dib7000p_get_time_us(demod);
1988041ad449SMauro Carvalho Chehab if (time_us) {
1989041ad449SMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL;
1990041ad449SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204);
1991041ad449SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1992041ad449SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks;
1993041ad449SMauro Carvalho Chehab }
1994041ad449SMauro Carvalho Chehab }
1995041ad449SMauro Carvalho Chehab return 0;
1996041ad449SMauro Carvalho Chehab }
1997041ad449SMauro Carvalho Chehab
dib7000p_fe_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * tune)19989a0bf528SMauro Carvalho Chehab static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
19999a0bf528SMauro Carvalho Chehab {
20009a0bf528SMauro Carvalho Chehab tune->min_delay_ms = 1000;
20019a0bf528SMauro Carvalho Chehab return 0;
20029a0bf528SMauro Carvalho Chehab }
20039a0bf528SMauro Carvalho Chehab
dib7000p_release(struct dvb_frontend * demod)20049a0bf528SMauro Carvalho Chehab static void dib7000p_release(struct dvb_frontend *demod)
20059a0bf528SMauro Carvalho Chehab {
20069a0bf528SMauro Carvalho Chehab struct dib7000p_state *st = demod->demodulator_priv;
20079a0bf528SMauro Carvalho Chehab dibx000_exit_i2c_master(&st->i2c_master);
20089a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->dib7090_tuner_adap);
20099a0bf528SMauro Carvalho Chehab kfree(st);
20109a0bf528SMauro Carvalho Chehab }
20119a0bf528SMauro Carvalho Chehab
dib7000pc_detection(struct i2c_adapter * i2c_adap)20128abe4a0aSMauro Carvalho Chehab static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
20139a0bf528SMauro Carvalho Chehab {
20149a0bf528SMauro Carvalho Chehab u8 *tx, *rx;
20159a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2] = {
20169a0bf528SMauro Carvalho Chehab {.addr = 18 >> 1, .flags = 0, .len = 2},
20179a0bf528SMauro Carvalho Chehab {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
20189a0bf528SMauro Carvalho Chehab };
20199a0bf528SMauro Carvalho Chehab int ret = 0;
20209a0bf528SMauro Carvalho Chehab
20216396bb22SKees Cook tx = kzalloc(2, GFP_KERNEL);
20229a0bf528SMauro Carvalho Chehab if (!tx)
20239a0bf528SMauro Carvalho Chehab return -ENOMEM;
20246396bb22SKees Cook rx = kzalloc(2, GFP_KERNEL);
20259a0bf528SMauro Carvalho Chehab if (!rx) {
20269a0bf528SMauro Carvalho Chehab ret = -ENOMEM;
20279a0bf528SMauro Carvalho Chehab goto rx_memory_error;
20289a0bf528SMauro Carvalho Chehab }
20299a0bf528SMauro Carvalho Chehab
20309a0bf528SMauro Carvalho Chehab msg[0].buf = tx;
20319a0bf528SMauro Carvalho Chehab msg[1].buf = rx;
20329a0bf528SMauro Carvalho Chehab
20339a0bf528SMauro Carvalho Chehab tx[0] = 0x03;
20349a0bf528SMauro Carvalho Chehab tx[1] = 0x00;
20359a0bf528SMauro Carvalho Chehab
20369a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c_adap, msg, 2) == 2)
20379a0bf528SMauro Carvalho Chehab if (rx[0] == 0x01 && rx[1] == 0xb3) {
20385a0e2a4eSMauro Carvalho Chehab dprintk("-D- DiB7000PC detected\n");
20398c3d3cdbSWenwen Wang ret = 1;
20408c3d3cdbSWenwen Wang goto out;
20419a0bf528SMauro Carvalho Chehab }
20429a0bf528SMauro Carvalho Chehab
20439a0bf528SMauro Carvalho Chehab msg[0].addr = msg[1].addr = 0x40;
20449a0bf528SMauro Carvalho Chehab
20459a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c_adap, msg, 2) == 2)
20469a0bf528SMauro Carvalho Chehab if (rx[0] == 0x01 && rx[1] == 0xb3) {
20475a0e2a4eSMauro Carvalho Chehab dprintk("-D- DiB7000PC detected\n");
20488c3d3cdbSWenwen Wang ret = 1;
20498c3d3cdbSWenwen Wang goto out;
20509a0bf528SMauro Carvalho Chehab }
20519a0bf528SMauro Carvalho Chehab
20525a0e2a4eSMauro Carvalho Chehab dprintk("-D- DiB7000PC not detected\n");
20539a0bf528SMauro Carvalho Chehab
20548c3d3cdbSWenwen Wang out:
20559a0bf528SMauro Carvalho Chehab kfree(rx);
20569a0bf528SMauro Carvalho Chehab rx_memory_error:
20579a0bf528SMauro Carvalho Chehab kfree(tx);
20589a0bf528SMauro Carvalho Chehab return ret;
20599a0bf528SMauro Carvalho Chehab }
20609a0bf528SMauro Carvalho Chehab
dib7000p_get_i2c_master(struct dvb_frontend * demod,enum dibx000_i2c_interface intf,int gating)20618abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
20629a0bf528SMauro Carvalho Chehab {
20639a0bf528SMauro Carvalho Chehab struct dib7000p_state *st = demod->demodulator_priv;
20649a0bf528SMauro Carvalho Chehab return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
20659a0bf528SMauro Carvalho Chehab }
20669a0bf528SMauro Carvalho Chehab
dib7000p_pid_filter_ctrl(struct dvb_frontend * fe,u8 onoff)20678abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
20689a0bf528SMauro Carvalho Chehab {
20699a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
20709a0bf528SMauro Carvalho Chehab u16 val = dib7000p_read_word(state, 235) & 0xffef;
20719a0bf528SMauro Carvalho Chehab val |= (onoff & 0x1) << 4;
20725a0e2a4eSMauro Carvalho Chehab dprintk("PID filter enabled %d\n", onoff);
20739a0bf528SMauro Carvalho Chehab return dib7000p_write_word(state, 235, val);
20749a0bf528SMauro Carvalho Chehab }
20759a0bf528SMauro Carvalho Chehab
dib7000p_pid_filter(struct dvb_frontend * fe,u8 id,u16 pid,u8 onoff)20768abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
20779a0bf528SMauro Carvalho Chehab {
20789a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
20795a0e2a4eSMauro Carvalho Chehab dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff);
20809a0bf528SMauro Carvalho Chehab return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
20819a0bf528SMauro Carvalho Chehab }
20829a0bf528SMauro Carvalho Chehab
dib7000p_i2c_enumeration(struct i2c_adapter * i2c,int no_of_demods,u8 default_addr,struct dib7000p_config cfg[])20838abe4a0aSMauro Carvalho Chehab static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
20849a0bf528SMauro Carvalho Chehab {
20859a0bf528SMauro Carvalho Chehab struct dib7000p_state *dpst;
20869a0bf528SMauro Carvalho Chehab int k = 0;
20879a0bf528SMauro Carvalho Chehab u8 new_addr = 0;
20889a0bf528SMauro Carvalho Chehab
20899a0bf528SMauro Carvalho Chehab dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
20909a0bf528SMauro Carvalho Chehab if (!dpst)
20919a0bf528SMauro Carvalho Chehab return -ENOMEM;
20929a0bf528SMauro Carvalho Chehab
20939a0bf528SMauro Carvalho Chehab dpst->i2c_adap = i2c;
20949a0bf528SMauro Carvalho Chehab mutex_init(&dpst->i2c_buffer_lock);
20959a0bf528SMauro Carvalho Chehab
20969a0bf528SMauro Carvalho Chehab for (k = no_of_demods - 1; k >= 0; k--) {
20979a0bf528SMauro Carvalho Chehab dpst->cfg = cfg[k];
20989a0bf528SMauro Carvalho Chehab
20999a0bf528SMauro Carvalho Chehab /* designated i2c address */
21009a0bf528SMauro Carvalho Chehab if (cfg[k].default_i2c_addr != 0)
21019a0bf528SMauro Carvalho Chehab new_addr = cfg[k].default_i2c_addr + (k << 1);
21029a0bf528SMauro Carvalho Chehab else
21039a0bf528SMauro Carvalho Chehab new_addr = (0x40 + k) << 1;
21049a0bf528SMauro Carvalho Chehab dpst->i2c_addr = new_addr;
21059a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
21069a0bf528SMauro Carvalho Chehab if (dib7000p_identify(dpst) != 0) {
21079a0bf528SMauro Carvalho Chehab dpst->i2c_addr = default_addr;
21089a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
21099a0bf528SMauro Carvalho Chehab if (dib7000p_identify(dpst) != 0) {
21109a0bf528SMauro Carvalho Chehab dprintk("DiB7000P #%d: not identified\n", k);
21119a0bf528SMauro Carvalho Chehab kfree(dpst);
21129a0bf528SMauro Carvalho Chehab return -EIO;
21139a0bf528SMauro Carvalho Chehab }
21149a0bf528SMauro Carvalho Chehab }
21159a0bf528SMauro Carvalho Chehab
21169a0bf528SMauro Carvalho Chehab /* start diversity to pull_down div_str - just for i2c-enumeration */
21179a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
21189a0bf528SMauro Carvalho Chehab
21199a0bf528SMauro Carvalho Chehab /* set new i2c address and force divstart */
21209a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
21219a0bf528SMauro Carvalho Chehab
21225a0e2a4eSMauro Carvalho Chehab dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
21239a0bf528SMauro Carvalho Chehab }
21249a0bf528SMauro Carvalho Chehab
21259a0bf528SMauro Carvalho Chehab for (k = 0; k < no_of_demods; k++) {
21269a0bf528SMauro Carvalho Chehab dpst->cfg = cfg[k];
21279a0bf528SMauro Carvalho Chehab if (cfg[k].default_i2c_addr != 0)
21289a0bf528SMauro Carvalho Chehab dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
21299a0bf528SMauro Carvalho Chehab else
21309a0bf528SMauro Carvalho Chehab dpst->i2c_addr = (0x40 + k) << 1;
21319a0bf528SMauro Carvalho Chehab
21329a0bf528SMauro Carvalho Chehab // unforce divstr
21339a0bf528SMauro Carvalho Chehab dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
21349a0bf528SMauro Carvalho Chehab
21359a0bf528SMauro Carvalho Chehab /* deactivate div - it was just for i2c-enumeration */
21369a0bf528SMauro Carvalho Chehab dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
21379a0bf528SMauro Carvalho Chehab }
21389a0bf528SMauro Carvalho Chehab
21399a0bf528SMauro Carvalho Chehab kfree(dpst);
21409a0bf528SMauro Carvalho Chehab return 0;
21419a0bf528SMauro Carvalho Chehab }
21429a0bf528SMauro Carvalho Chehab
21439a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = {
21449a0bf528SMauro Carvalho Chehab 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
21459a0bf528SMauro Carvalho Chehab };
21469a0bf528SMauro Carvalho Chehab
dib7000p_get_adc_power(struct dvb_frontend * fe)21479a0bf528SMauro Carvalho Chehab static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
21489a0bf528SMauro Carvalho Chehab {
21499a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
21509a0bf528SMauro Carvalho Chehab u32 tmp_val = 0, exp = 0, mant = 0;
21519a0bf528SMauro Carvalho Chehab s32 pow_i;
21529a0bf528SMauro Carvalho Chehab u16 buf[2];
21539a0bf528SMauro Carvalho Chehab u8 ix = 0;
21549a0bf528SMauro Carvalho Chehab
21559a0bf528SMauro Carvalho Chehab buf[0] = dib7000p_read_word(state, 0x184);
21569a0bf528SMauro Carvalho Chehab buf[1] = dib7000p_read_word(state, 0x185);
21579a0bf528SMauro Carvalho Chehab pow_i = (buf[0] << 16) | buf[1];
21585a0e2a4eSMauro Carvalho Chehab dprintk("raw pow_i = %d\n", pow_i);
21599a0bf528SMauro Carvalho Chehab
21609a0bf528SMauro Carvalho Chehab tmp_val = pow_i;
21619a0bf528SMauro Carvalho Chehab while (tmp_val >>= 1)
21629a0bf528SMauro Carvalho Chehab exp++;
21639a0bf528SMauro Carvalho Chehab
21649a0bf528SMauro Carvalho Chehab mant = (pow_i * 1000 / (1 << exp));
21655a0e2a4eSMauro Carvalho Chehab dprintk(" mant = %d exp = %d\n", mant / 1000, exp);
21669a0bf528SMauro Carvalho Chehab
21679a0bf528SMauro Carvalho Chehab ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
21685a0e2a4eSMauro Carvalho Chehab dprintk(" ix = %d\n", ix);
21699a0bf528SMauro Carvalho Chehab
21709a0bf528SMauro Carvalho Chehab pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
21719a0bf528SMauro Carvalho Chehab pow_i = (pow_i << 8) / 1000;
21725a0e2a4eSMauro Carvalho Chehab dprintk(" pow_i = %d\n", pow_i);
21739a0bf528SMauro Carvalho Chehab
21749a0bf528SMauro Carvalho Chehab return pow_i;
21759a0bf528SMauro Carvalho Chehab }
21769a0bf528SMauro Carvalho Chehab
map_addr_to_serpar_number(struct i2c_msg * msg)21779a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
21789a0bf528SMauro Carvalho Chehab {
21799a0bf528SMauro Carvalho Chehab if ((msg->buf[0] <= 15))
21809a0bf528SMauro Carvalho Chehab msg->buf[0] -= 1;
21819a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 17)
21829a0bf528SMauro Carvalho Chehab msg->buf[0] = 15;
21839a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 16)
21849a0bf528SMauro Carvalho Chehab msg->buf[0] = 17;
21859a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 19)
21869a0bf528SMauro Carvalho Chehab msg->buf[0] = 16;
21879a0bf528SMauro Carvalho Chehab else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
21889a0bf528SMauro Carvalho Chehab msg->buf[0] -= 3;
21899a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 28)
21909a0bf528SMauro Carvalho Chehab msg->buf[0] = 23;
21919a0bf528SMauro Carvalho Chehab else
21929a0bf528SMauro Carvalho Chehab return -EINVAL;
21939a0bf528SMauro Carvalho Chehab return 0;
21949a0bf528SMauro Carvalho Chehab }
21959a0bf528SMauro Carvalho Chehab
w7090p_tuner_write_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)21969a0bf528SMauro Carvalho Chehab static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
21979a0bf528SMauro Carvalho Chehab {
21989a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
21999a0bf528SMauro Carvalho Chehab u8 n_overflow = 1;
22009a0bf528SMauro Carvalho Chehab u16 i = 1000;
22019a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0];
22029a0bf528SMauro Carvalho Chehab
22039a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) {
22049a0bf528SMauro Carvalho Chehab n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
22059a0bf528SMauro Carvalho Chehab i--;
22069a0bf528SMauro Carvalho Chehab if (i == 0)
22075a0e2a4eSMauro Carvalho Chehab dprintk("Tuner ITF: write busy (overflow)\n");
22089a0bf528SMauro Carvalho Chehab }
22099a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
22109a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
22119a0bf528SMauro Carvalho Chehab
22129a0bf528SMauro Carvalho Chehab return num;
22139a0bf528SMauro Carvalho Chehab }
22149a0bf528SMauro Carvalho Chehab
w7090p_tuner_read_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)22159a0bf528SMauro Carvalho Chehab static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22169a0bf528SMauro Carvalho Chehab {
22179a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22189a0bf528SMauro Carvalho Chehab u8 n_overflow = 1, n_empty = 1;
22199a0bf528SMauro Carvalho Chehab u16 i = 1000;
22209a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0];
22219a0bf528SMauro Carvalho Chehab u16 read_word;
22229a0bf528SMauro Carvalho Chehab
22239a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) {
22249a0bf528SMauro Carvalho Chehab n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
22259a0bf528SMauro Carvalho Chehab i--;
22269a0bf528SMauro Carvalho Chehab if (i == 0)
22275a0e2a4eSMauro Carvalho Chehab dprintk("TunerITF: read busy (overflow)\n");
22289a0bf528SMauro Carvalho Chehab }
22299a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
22309a0bf528SMauro Carvalho Chehab
22319a0bf528SMauro Carvalho Chehab i = 1000;
22329a0bf528SMauro Carvalho Chehab while (n_empty == 1 && i) {
22339a0bf528SMauro Carvalho Chehab n_empty = dib7000p_read_word(state, 1984) & 0x1;
22349a0bf528SMauro Carvalho Chehab i--;
22359a0bf528SMauro Carvalho Chehab if (i == 0)
22365a0e2a4eSMauro Carvalho Chehab dprintk("TunerITF: read busy (empty)\n");
22379a0bf528SMauro Carvalho Chehab }
22389a0bf528SMauro Carvalho Chehab read_word = dib7000p_read_word(state, 1987);
22399a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (read_word >> 8) & 0xff;
22409a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (read_word) & 0xff;
22419a0bf528SMauro Carvalho Chehab
22429a0bf528SMauro Carvalho Chehab return num;
22439a0bf528SMauro Carvalho Chehab }
22449a0bf528SMauro Carvalho Chehab
w7090p_tuner_rw_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)22459a0bf528SMauro Carvalho Chehab static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22469a0bf528SMauro Carvalho Chehab {
22479a0bf528SMauro 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... */
22489a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */
22499a0bf528SMauro Carvalho Chehab return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
22509a0bf528SMauro Carvalho Chehab } else { /* read */
22519a0bf528SMauro Carvalho Chehab return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
22529a0bf528SMauro Carvalho Chehab }
22539a0bf528SMauro Carvalho Chehab }
22549a0bf528SMauro Carvalho Chehab return num;
22559a0bf528SMauro Carvalho Chehab }
22569a0bf528SMauro Carvalho Chehab
dib7090p_rw_on_apb(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num,u16 apb_address)22579a0bf528SMauro Carvalho Chehab static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
22589a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num, u16 apb_address)
22599a0bf528SMauro Carvalho Chehab {
22609a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22619a0bf528SMauro Carvalho Chehab u16 word;
22629a0bf528SMauro Carvalho Chehab
22639a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */
22649a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
22659a0bf528SMauro Carvalho Chehab } else {
22669a0bf528SMauro Carvalho Chehab word = dib7000p_read_word(state, apb_address);
22679a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff;
22689a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff;
22699a0bf528SMauro Carvalho Chehab }
22709a0bf528SMauro Carvalho Chehab
22719a0bf528SMauro Carvalho Chehab return num;
22729a0bf528SMauro Carvalho Chehab }
22739a0bf528SMauro Carvalho Chehab
dib7090_tuner_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)22749a0bf528SMauro Carvalho Chehab static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22759a0bf528SMauro Carvalho Chehab {
22769a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22779a0bf528SMauro Carvalho Chehab
22789a0bf528SMauro Carvalho Chehab u16 apb_address = 0, word;
22799a0bf528SMauro Carvalho Chehab int i = 0;
22809a0bf528SMauro Carvalho Chehab switch (msg[0].buf[0]) {
22819a0bf528SMauro Carvalho Chehab case 0x12:
22829a0bf528SMauro Carvalho Chehab apb_address = 1920;
22839a0bf528SMauro Carvalho Chehab break;
22849a0bf528SMauro Carvalho Chehab case 0x14:
22859a0bf528SMauro Carvalho Chehab apb_address = 1921;
22869a0bf528SMauro Carvalho Chehab break;
22879a0bf528SMauro Carvalho Chehab case 0x24:
22889a0bf528SMauro Carvalho Chehab apb_address = 1922;
22899a0bf528SMauro Carvalho Chehab break;
22909a0bf528SMauro Carvalho Chehab case 0x1a:
22919a0bf528SMauro Carvalho Chehab apb_address = 1923;
22929a0bf528SMauro Carvalho Chehab break;
22939a0bf528SMauro Carvalho Chehab case 0x22:
22949a0bf528SMauro Carvalho Chehab apb_address = 1924;
22959a0bf528SMauro Carvalho Chehab break;
22969a0bf528SMauro Carvalho Chehab case 0x33:
22979a0bf528SMauro Carvalho Chehab apb_address = 1926;
22989a0bf528SMauro Carvalho Chehab break;
22999a0bf528SMauro Carvalho Chehab case 0x34:
23009a0bf528SMauro Carvalho Chehab apb_address = 1927;
23019a0bf528SMauro Carvalho Chehab break;
23029a0bf528SMauro Carvalho Chehab case 0x35:
23039a0bf528SMauro Carvalho Chehab apb_address = 1928;
23049a0bf528SMauro Carvalho Chehab break;
23059a0bf528SMauro Carvalho Chehab case 0x36:
23069a0bf528SMauro Carvalho Chehab apb_address = 1929;
23079a0bf528SMauro Carvalho Chehab break;
23089a0bf528SMauro Carvalho Chehab case 0x37:
23099a0bf528SMauro Carvalho Chehab apb_address = 1930;
23109a0bf528SMauro Carvalho Chehab break;
23119a0bf528SMauro Carvalho Chehab case 0x38:
23129a0bf528SMauro Carvalho Chehab apb_address = 1931;
23139a0bf528SMauro Carvalho Chehab break;
23149a0bf528SMauro Carvalho Chehab case 0x39:
23159a0bf528SMauro Carvalho Chehab apb_address = 1932;
23169a0bf528SMauro Carvalho Chehab break;
23179a0bf528SMauro Carvalho Chehab case 0x2a:
23189a0bf528SMauro Carvalho Chehab apb_address = 1935;
23199a0bf528SMauro Carvalho Chehab break;
23209a0bf528SMauro Carvalho Chehab case 0x2b:
23219a0bf528SMauro Carvalho Chehab apb_address = 1936;
23229a0bf528SMauro Carvalho Chehab break;
23239a0bf528SMauro Carvalho Chehab case 0x2c:
23249a0bf528SMauro Carvalho Chehab apb_address = 1937;
23259a0bf528SMauro Carvalho Chehab break;
23269a0bf528SMauro Carvalho Chehab case 0x2d:
23279a0bf528SMauro Carvalho Chehab apb_address = 1938;
23289a0bf528SMauro Carvalho Chehab break;
23299a0bf528SMauro Carvalho Chehab case 0x2e:
23309a0bf528SMauro Carvalho Chehab apb_address = 1939;
23319a0bf528SMauro Carvalho Chehab break;
23329a0bf528SMauro Carvalho Chehab case 0x2f:
23339a0bf528SMauro Carvalho Chehab apb_address = 1940;
23349a0bf528SMauro Carvalho Chehab break;
23359a0bf528SMauro Carvalho Chehab case 0x30:
23369a0bf528SMauro Carvalho Chehab apb_address = 1941;
23379a0bf528SMauro Carvalho Chehab break;
23389a0bf528SMauro Carvalho Chehab case 0x31:
23399a0bf528SMauro Carvalho Chehab apb_address = 1942;
23409a0bf528SMauro Carvalho Chehab break;
23419a0bf528SMauro Carvalho Chehab case 0x32:
23429a0bf528SMauro Carvalho Chehab apb_address = 1943;
23439a0bf528SMauro Carvalho Chehab break;
23449a0bf528SMauro Carvalho Chehab case 0x3e:
23459a0bf528SMauro Carvalho Chehab apb_address = 1944;
23469a0bf528SMauro Carvalho Chehab break;
23479a0bf528SMauro Carvalho Chehab case 0x3f:
23489a0bf528SMauro Carvalho Chehab apb_address = 1945;
23499a0bf528SMauro Carvalho Chehab break;
23509a0bf528SMauro Carvalho Chehab case 0x40:
23519a0bf528SMauro Carvalho Chehab apb_address = 1948;
23529a0bf528SMauro Carvalho Chehab break;
23539a0bf528SMauro Carvalho Chehab case 0x25:
23549a0bf528SMauro Carvalho Chehab apb_address = 914;
23559a0bf528SMauro Carvalho Chehab break;
23569a0bf528SMauro Carvalho Chehab case 0x26:
23579a0bf528SMauro Carvalho Chehab apb_address = 915;
23589a0bf528SMauro Carvalho Chehab break;
23599a0bf528SMauro Carvalho Chehab case 0x27:
23609a0bf528SMauro Carvalho Chehab apb_address = 917;
23619a0bf528SMauro Carvalho Chehab break;
23629a0bf528SMauro Carvalho Chehab case 0x28:
23639a0bf528SMauro Carvalho Chehab apb_address = 916;
23649a0bf528SMauro Carvalho Chehab break;
23659a0bf528SMauro Carvalho Chehab case 0x1d:
23669a0bf528SMauro Carvalho Chehab i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
23679a0bf528SMauro Carvalho Chehab word = dib7000p_read_word(state, 384 + i);
23689a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff;
23699a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff;
23709a0bf528SMauro Carvalho Chehab return num;
23719a0bf528SMauro Carvalho Chehab case 0x1f:
23729a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */
23739a0bf528SMauro Carvalho Chehab word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
23749a0bf528SMauro Carvalho Chehab word &= 0x3;
23759a0bf528SMauro Carvalho Chehab word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
23769a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 72, word); /* Set the proper input */
23779a0bf528SMauro Carvalho Chehab return num;
23789a0bf528SMauro Carvalho Chehab }
23799a0bf528SMauro Carvalho Chehab }
23809a0bf528SMauro Carvalho Chehab
2381868c9a17SMauro Carvalho Chehab if (apb_address != 0) /* R/W access via APB */
23829a0bf528SMauro Carvalho Chehab return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
23839a0bf528SMauro Carvalho Chehab else /* R/W access via SERPAR */
23849a0bf528SMauro Carvalho Chehab return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
23859a0bf528SMauro Carvalho Chehab
23869a0bf528SMauro Carvalho Chehab return 0;
23879a0bf528SMauro Carvalho Chehab }
23889a0bf528SMauro Carvalho Chehab
dib7000p_i2c_func(struct i2c_adapter * adapter)23899a0bf528SMauro Carvalho Chehab static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
23909a0bf528SMauro Carvalho Chehab {
23919a0bf528SMauro Carvalho Chehab return I2C_FUNC_I2C;
23929a0bf528SMauro Carvalho Chehab }
23939a0bf528SMauro Carvalho Chehab
2394a76f094aSGustavo A. R. Silva static const struct i2c_algorithm dib7090_tuner_xfer_algo = {
23959a0bf528SMauro Carvalho Chehab .master_xfer = dib7090_tuner_xfer,
23969a0bf528SMauro Carvalho Chehab .functionality = dib7000p_i2c_func,
23979a0bf528SMauro Carvalho Chehab };
23989a0bf528SMauro Carvalho Chehab
dib7090_get_i2c_tuner(struct dvb_frontend * fe)23998abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
24009a0bf528SMauro Carvalho Chehab {
24019a0bf528SMauro Carvalho Chehab struct dib7000p_state *st = fe->demodulator_priv;
24029a0bf528SMauro Carvalho Chehab return &st->dib7090_tuner_adap;
24039a0bf528SMauro Carvalho Chehab }
24049a0bf528SMauro Carvalho Chehab
dib7090_host_bus_drive(struct dib7000p_state * state,u8 drive)24059a0bf528SMauro Carvalho Chehab static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
24069a0bf528SMauro Carvalho Chehab {
24079a0bf528SMauro Carvalho Chehab u16 reg;
24089a0bf528SMauro Carvalho Chehab
24099a0bf528SMauro Carvalho Chehab /* drive host bus 2, 3, 4 */
24109a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24119a0bf528SMauro Carvalho Chehab reg |= (drive << 12) | (drive << 6) | drive;
24129a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1798, reg);
24139a0bf528SMauro Carvalho Chehab
24149a0bf528SMauro Carvalho Chehab /* drive host bus 5,6 */
24159a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
24169a0bf528SMauro Carvalho Chehab reg |= (drive << 8) | (drive << 2);
24179a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1799, reg);
24189a0bf528SMauro Carvalho Chehab
24199a0bf528SMauro Carvalho Chehab /* drive host bus 7, 8, 9 */
24209a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24219a0bf528SMauro Carvalho Chehab reg |= (drive << 12) | (drive << 6) | drive;
24229a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1800, reg);
24239a0bf528SMauro Carvalho Chehab
24249a0bf528SMauro Carvalho Chehab /* drive host bus 10, 11 */
24259a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
24269a0bf528SMauro Carvalho Chehab reg |= (drive << 8) | (drive << 2);
24279a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1801, reg);
24289a0bf528SMauro Carvalho Chehab
24299a0bf528SMauro Carvalho Chehab /* drive host bus 12, 13, 14 */
24309a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24319a0bf528SMauro Carvalho Chehab reg |= (drive << 12) | (drive << 6) | drive;
24329a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1802, reg);
24339a0bf528SMauro Carvalho Chehab
24349a0bf528SMauro Carvalho Chehab return 0;
24359a0bf528SMauro Carvalho Chehab }
24369a0bf528SMauro Carvalho Chehab
dib7090_calcSyncFreq(u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 syncSize)24379a0bf528SMauro Carvalho Chehab static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
24389a0bf528SMauro Carvalho Chehab {
24399a0bf528SMauro Carvalho Chehab u32 quantif = 3;
24409a0bf528SMauro Carvalho Chehab u32 nom = (insertExtSynchro * P_Kin + syncSize);
24419a0bf528SMauro Carvalho Chehab u32 denom = P_Kout;
24429a0bf528SMauro Carvalho Chehab u32 syncFreq = ((nom << quantif) / denom);
24439a0bf528SMauro Carvalho Chehab
24449a0bf528SMauro Carvalho Chehab if ((syncFreq & ((1 << quantif) - 1)) != 0)
24459a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif) + 1;
24469a0bf528SMauro Carvalho Chehab else
24479a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif);
24489a0bf528SMauro Carvalho Chehab
24499a0bf528SMauro Carvalho Chehab if (syncFreq != 0)
24509a0bf528SMauro Carvalho Chehab syncFreq = syncFreq - 1;
24519a0bf528SMauro Carvalho Chehab
24529a0bf528SMauro Carvalho Chehab return syncFreq;
24539a0bf528SMauro Carvalho Chehab }
24549a0bf528SMauro Carvalho Chehab
dib7090_cfg_DibTx(struct dib7000p_state * state,u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 synchroMode,u32 syncWord,u32 syncSize)24559a0bf528SMauro 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)
24569a0bf528SMauro Carvalho Chehab {
24575a0e2a4eSMauro Carvalho Chehab dprintk("Configure DibStream Tx\n");
24589a0bf528SMauro Carvalho Chehab
24599a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1615, 1);
24609a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1603, P_Kin);
24619a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1605, P_Kout);
24629a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1606, insertExtSynchro);
24639a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1608, synchroMode);
24649a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
24659a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1610, syncWord & 0xffff);
24669a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1612, syncSize);
24679a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1615, 0);
24689a0bf528SMauro Carvalho Chehab
24699a0bf528SMauro Carvalho Chehab return 0;
24709a0bf528SMauro Carvalho Chehab }
24719a0bf528SMauro Carvalho Chehab
dib7090_cfg_DibRx(struct dib7000p_state * state,u32 P_Kin,u32 P_Kout,u32 synchroMode,u32 insertExtSynchro,u32 syncWord,u32 syncSize,u32 dataOutRate)24729a0bf528SMauro 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,
24739a0bf528SMauro Carvalho Chehab u32 dataOutRate)
24749a0bf528SMauro Carvalho Chehab {
24759a0bf528SMauro Carvalho Chehab u32 syncFreq;
24769a0bf528SMauro Carvalho Chehab
24775a0e2a4eSMauro Carvalho Chehab dprintk("Configure DibStream Rx\n");
24789a0bf528SMauro Carvalho Chehab if ((P_Kin != 0) && (P_Kout != 0)) {
24799a0bf528SMauro Carvalho Chehab syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
24809a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1542, syncFreq);
24819a0bf528SMauro Carvalho Chehab }
24829a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1554, 1);
24839a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1536, P_Kin);
24849a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1537, P_Kout);
24859a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1539, synchroMode);
24869a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
24879a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1541, syncWord & 0xffff);
24889a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1543, syncSize);
24899a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1544, dataOutRate);
24909a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1554, 0);
24919a0bf528SMauro Carvalho Chehab
24929a0bf528SMauro Carvalho Chehab return 0;
24939a0bf528SMauro Carvalho Chehab }
24949a0bf528SMauro Carvalho Chehab
dib7090_enMpegMux(struct dib7000p_state * state,int onoff)24959a0bf528SMauro Carvalho Chehab static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
24969a0bf528SMauro Carvalho Chehab {
24979a0bf528SMauro Carvalho Chehab u16 reg_1287 = dib7000p_read_word(state, 1287);
24989a0bf528SMauro Carvalho Chehab
24999a0bf528SMauro Carvalho Chehab switch (onoff) {
25009a0bf528SMauro Carvalho Chehab case 1:
25019a0bf528SMauro Carvalho Chehab reg_1287 &= ~(1<<7);
25029a0bf528SMauro Carvalho Chehab break;
25039a0bf528SMauro Carvalho Chehab case 0:
25049a0bf528SMauro Carvalho Chehab reg_1287 |= (1<<7);
25059a0bf528SMauro Carvalho Chehab break;
25069a0bf528SMauro Carvalho Chehab }
25079a0bf528SMauro Carvalho Chehab
25089a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1287, reg_1287);
25099a0bf528SMauro Carvalho Chehab }
25109a0bf528SMauro Carvalho Chehab
dib7090_configMpegMux(struct dib7000p_state * state,u16 pulseWidth,u16 enSerialMode,u16 enSerialClkDiv2)25119a0bf528SMauro Carvalho Chehab static void dib7090_configMpegMux(struct dib7000p_state *state,
25129a0bf528SMauro Carvalho Chehab u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
25139a0bf528SMauro Carvalho Chehab {
25145a0e2a4eSMauro Carvalho Chehab dprintk("Enable Mpeg mux\n");
25159a0bf528SMauro Carvalho Chehab
25169a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 0);
25179a0bf528SMauro Carvalho Chehab
25189a0bf528SMauro Carvalho Chehab /* If the input mode is MPEG do not divide the serial clock */
25199a0bf528SMauro Carvalho Chehab if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
25209a0bf528SMauro Carvalho Chehab enSerialClkDiv2 = 0;
25219a0bf528SMauro Carvalho Chehab
25229a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
25239a0bf528SMauro Carvalho Chehab | ((enSerialMode & 0x1) << 1)
25249a0bf528SMauro Carvalho Chehab | (enSerialClkDiv2 & 0x1));
25259a0bf528SMauro Carvalho Chehab
25269a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 1);
25279a0bf528SMauro Carvalho Chehab }
25289a0bf528SMauro Carvalho Chehab
dib7090_setDibTxMux(struct dib7000p_state * state,int mode)25299a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
25309a0bf528SMauro Carvalho Chehab {
25319a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
25329a0bf528SMauro Carvalho Chehab
25339a0bf528SMauro Carvalho Chehab switch (mode) {
25349a0bf528SMauro Carvalho Chehab case MPEG_ON_DIBTX:
25355a0e2a4eSMauro Carvalho Chehab dprintk("SET MPEG ON DIBSTREAM TX\n");
25369a0bf528SMauro Carvalho Chehab dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
25379a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<9);
25389a0bf528SMauro Carvalho Chehab break;
25399a0bf528SMauro Carvalho Chehab case DIV_ON_DIBTX:
25405a0e2a4eSMauro Carvalho Chehab dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
25419a0bf528SMauro Carvalho Chehab dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
25429a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<8);
25439a0bf528SMauro Carvalho Chehab break;
25449a0bf528SMauro Carvalho Chehab case ADC_ON_DIBTX:
25455a0e2a4eSMauro Carvalho Chehab dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
25469a0bf528SMauro Carvalho Chehab dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
25479a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<7);
25489a0bf528SMauro Carvalho Chehab break;
25499a0bf528SMauro Carvalho Chehab default:
25509a0bf528SMauro Carvalho Chehab break;
25519a0bf528SMauro Carvalho Chehab }
25529a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1288, reg_1288);
25539a0bf528SMauro Carvalho Chehab }
25549a0bf528SMauro Carvalho Chehab
dib7090_setHostBusMux(struct dib7000p_state * state,int mode)25559a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
25569a0bf528SMauro Carvalho Chehab {
25579a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
25589a0bf528SMauro Carvalho Chehab
25599a0bf528SMauro Carvalho Chehab switch (mode) {
25609a0bf528SMauro Carvalho Chehab case DEMOUT_ON_HOSTBUS:
25615a0e2a4eSMauro Carvalho Chehab dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
25629a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 0);
25639a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<6);
25649a0bf528SMauro Carvalho Chehab break;
25659a0bf528SMauro Carvalho Chehab case DIBTX_ON_HOSTBUS:
25665a0e2a4eSMauro Carvalho Chehab dprintk("SET DIBSTREAM TX ON HOST BUS\n");
25679a0bf528SMauro Carvalho Chehab dib7090_enMpegMux(state, 0);
25689a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<5);
25699a0bf528SMauro Carvalho Chehab break;
25709a0bf528SMauro Carvalho Chehab case MPEG_ON_HOSTBUS:
25715a0e2a4eSMauro Carvalho Chehab dprintk("SET MPEG MUX ON HOST BUS\n");
25729a0bf528SMauro Carvalho Chehab reg_1288 |= (1<<4);
25739a0bf528SMauro Carvalho Chehab break;
25749a0bf528SMauro Carvalho Chehab default:
25759a0bf528SMauro Carvalho Chehab break;
25769a0bf528SMauro Carvalho Chehab }
25779a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1288, reg_1288);
25789a0bf528SMauro Carvalho Chehab }
25799a0bf528SMauro Carvalho Chehab
dib7090_set_diversity_in(struct dvb_frontend * fe,int onoff)258018ef20daSHans Verkuil static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
25819a0bf528SMauro Carvalho Chehab {
25829a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
25839a0bf528SMauro Carvalho Chehab u16 reg_1287;
25849a0bf528SMauro Carvalho Chehab
25859a0bf528SMauro Carvalho Chehab switch (onoff) {
25869a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */
25875a0e2a4eSMauro Carvalho Chehab dprintk("%s mode OFF : by default Enable Mpeg INPUT\n", __func__);
25889a0bf528SMauro Carvalho Chehab dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
25899a0bf528SMauro Carvalho Chehab
25909a0bf528SMauro Carvalho Chehab /* Do not divide the serial clock of MPEG MUX */
25919a0bf528SMauro Carvalho Chehab /* in SERIAL MODE in case input mode MPEG is used */
25929a0bf528SMauro Carvalho Chehab reg_1287 = dib7000p_read_word(state, 1287);
25939a0bf528SMauro Carvalho Chehab /* enSerialClkDiv2 == 1 ? */
25949a0bf528SMauro Carvalho Chehab if ((reg_1287 & 0x1) == 1) {
25959a0bf528SMauro Carvalho Chehab /* force enSerialClkDiv2 = 0 */
25969a0bf528SMauro Carvalho Chehab reg_1287 &= ~0x1;
25979a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1287, reg_1287);
25989a0bf528SMauro Carvalho Chehab }
25999a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 1;
26009a0bf528SMauro Carvalho Chehab break;
26019a0bf528SMauro Carvalho Chehab case 1: /* both ways */
26029a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */
26035a0e2a4eSMauro Carvalho Chehab dprintk("%s ON : Enable diversity INPUT\n", __func__);
26049a0bf528SMauro Carvalho Chehab dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
26059a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 0;
26069a0bf528SMauro Carvalho Chehab break;
26079a0bf528SMauro Carvalho Chehab }
26089a0bf528SMauro Carvalho Chehab
26099a0bf528SMauro Carvalho Chehab dib7000p_set_diversity_in(&state->demod, onoff);
26109a0bf528SMauro Carvalho Chehab return 0;
26119a0bf528SMauro Carvalho Chehab }
26129a0bf528SMauro Carvalho Chehab
dib7090_set_output_mode(struct dvb_frontend * fe,int mode)26139a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
26149a0bf528SMauro Carvalho Chehab {
26159a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
26169a0bf528SMauro Carvalho Chehab
26179a0bf528SMauro Carvalho Chehab u16 outreg, smo_mode, fifo_threshold;
26189a0bf528SMauro Carvalho Chehab u8 prefer_mpeg_mux_use = 1;
26199a0bf528SMauro Carvalho Chehab int ret = 0;
26209a0bf528SMauro Carvalho Chehab
26219a0bf528SMauro Carvalho Chehab dib7090_host_bus_drive(state, 1);
26229a0bf528SMauro Carvalho Chehab
26239a0bf528SMauro Carvalho Chehab fifo_threshold = 1792;
26249a0bf528SMauro Carvalho Chehab smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
26259a0bf528SMauro Carvalho Chehab outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
26269a0bf528SMauro Carvalho Chehab
26279a0bf528SMauro Carvalho Chehab switch (mode) {
26289a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z:
26299a0bf528SMauro Carvalho Chehab outreg = 0;
26309a0bf528SMauro Carvalho Chehab break;
26319a0bf528SMauro Carvalho Chehab
26329a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL:
26339a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) {
26345a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode TS_SERIAL using Mpeg Mux\n");
26359a0bf528SMauro Carvalho Chehab dib7090_configMpegMux(state, 3, 1, 1);
26369a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
26379a0bf528SMauro Carvalho Chehab } else {/* Use Smooth block */
26385a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode TS_SERIAL using Smooth bloc\n");
26399a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26409a0bf528SMauro Carvalho Chehab outreg |= (2<<6) | (0 << 1);
26419a0bf528SMauro Carvalho Chehab }
26429a0bf528SMauro Carvalho Chehab break;
26439a0bf528SMauro Carvalho Chehab
26449a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK:
26459a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) {
26465a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
26479a0bf528SMauro Carvalho Chehab dib7090_configMpegMux(state, 2, 0, 0);
26489a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
26499a0bf528SMauro Carvalho Chehab } else { /* Use Smooth block */
26505a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode TS_PARALLEL_GATED using Smooth block\n");
26519a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26529a0bf528SMauro Carvalho Chehab outreg |= (0<<6);
26539a0bf528SMauro Carvalho Chehab }
26549a0bf528SMauro Carvalho Chehab break;
26559a0bf528SMauro Carvalho Chehab
26569a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
26575a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode TS_PARALLEL_CONT using Smooth block\n");
26589a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26599a0bf528SMauro Carvalho Chehab outreg |= (1<<6);
26609a0bf528SMauro Carvalho Chehab break;
26619a0bf528SMauro Carvalho Chehab
26629a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
26635a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode TS_FIFO using Smooth block\n");
26649a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26659a0bf528SMauro Carvalho Chehab outreg |= (5<<6);
26669a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1);
26679a0bf528SMauro Carvalho Chehab fifo_threshold = 512;
26689a0bf528SMauro Carvalho Chehab break;
26699a0bf528SMauro Carvalho Chehab
26709a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY:
26715a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode MODE_DIVERSITY\n");
26729a0bf528SMauro Carvalho Chehab dib7090_setDibTxMux(state, DIV_ON_DIBTX);
26739a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26749a0bf528SMauro Carvalho Chehab break;
26759a0bf528SMauro Carvalho Chehab
26769a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC:
26775a0e2a4eSMauro Carvalho Chehab dprintk("setting output mode MODE_ANALOG_ADC\n");
26789a0bf528SMauro Carvalho Chehab dib7090_setDibTxMux(state, ADC_ON_DIBTX);
26799a0bf528SMauro Carvalho Chehab dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26809a0bf528SMauro Carvalho Chehab break;
26819a0bf528SMauro Carvalho Chehab }
26829a0bf528SMauro Carvalho Chehab if (mode != OUTMODE_HIGH_Z)
26839a0bf528SMauro Carvalho Chehab outreg |= (1 << 10);
26849a0bf528SMauro Carvalho Chehab
26859a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes)
26869a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5);
26879a0bf528SMauro Carvalho Chehab
26889a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 235, smo_mode);
26899a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
26909a0bf528SMauro Carvalho Chehab ret |= dib7000p_write_word(state, 1286, outreg);
26919a0bf528SMauro Carvalho Chehab
26929a0bf528SMauro Carvalho Chehab return ret;
26939a0bf528SMauro Carvalho Chehab }
26949a0bf528SMauro Carvalho Chehab
dib7090_tuner_sleep(struct dvb_frontend * fe,int onoff)26958abe4a0aSMauro Carvalho Chehab static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
26969a0bf528SMauro Carvalho Chehab {
26979a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
26989a0bf528SMauro Carvalho Chehab u16 en_cur_state;
26999a0bf528SMauro Carvalho Chehab
27005a0e2a4eSMauro Carvalho Chehab dprintk("sleep dib7090: %d\n", onoff);
27019a0bf528SMauro Carvalho Chehab
27029a0bf528SMauro Carvalho Chehab en_cur_state = dib7000p_read_word(state, 1922);
27039a0bf528SMauro Carvalho Chehab
27049a0bf528SMauro Carvalho Chehab if (en_cur_state > 0xff)
27059a0bf528SMauro Carvalho Chehab state->tuner_enable = en_cur_state;
27069a0bf528SMauro Carvalho Chehab
27079a0bf528SMauro Carvalho Chehab if (onoff)
27089a0bf528SMauro Carvalho Chehab en_cur_state &= 0x00ff;
27099a0bf528SMauro Carvalho Chehab else {
27109a0bf528SMauro Carvalho Chehab if (state->tuner_enable != 0)
27119a0bf528SMauro Carvalho Chehab en_cur_state = state->tuner_enable;
27129a0bf528SMauro Carvalho Chehab }
27139a0bf528SMauro Carvalho Chehab
27149a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1922, en_cur_state);
27159a0bf528SMauro Carvalho Chehab
27169a0bf528SMauro Carvalho Chehab return 0;
27179a0bf528SMauro Carvalho Chehab }
27189a0bf528SMauro Carvalho Chehab
dib7090_get_adc_power(struct dvb_frontend * fe)27198abe4a0aSMauro Carvalho Chehab static int dib7090_get_adc_power(struct dvb_frontend *fe)
27209a0bf528SMauro Carvalho Chehab {
27219a0bf528SMauro Carvalho Chehab return dib7000p_get_adc_power(fe);
27229a0bf528SMauro Carvalho Chehab }
27239a0bf528SMauro Carvalho Chehab
dib7090_slave_reset(struct dvb_frontend * fe)27248abe4a0aSMauro Carvalho Chehab static int dib7090_slave_reset(struct dvb_frontend *fe)
27259a0bf528SMauro Carvalho Chehab {
27269a0bf528SMauro Carvalho Chehab struct dib7000p_state *state = fe->demodulator_priv;
27279a0bf528SMauro Carvalho Chehab u16 reg;
27289a0bf528SMauro Carvalho Chehab
27299a0bf528SMauro Carvalho Chehab reg = dib7000p_read_word(state, 1794);
27309a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1794, reg | (4 << 12));
27319a0bf528SMauro Carvalho Chehab
27329a0bf528SMauro Carvalho Chehab dib7000p_write_word(state, 1032, 0xffff);
27339a0bf528SMauro Carvalho Chehab return 0;
27349a0bf528SMauro Carvalho Chehab }
27359a0bf528SMauro Carvalho Chehab
2736bd336e63SMax Kellermann static const struct dvb_frontend_ops dib7000p_ops;
dib7000p_init(struct i2c_adapter * i2c_adap,u8 i2c_addr,struct dib7000p_config * cfg)27378abe4a0aSMauro Carvalho Chehab static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
27389a0bf528SMauro Carvalho Chehab {
27399a0bf528SMauro Carvalho Chehab struct dvb_frontend *demod;
27409a0bf528SMauro Carvalho Chehab struct dib7000p_state *st;
27419a0bf528SMauro Carvalho Chehab st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
27429a0bf528SMauro Carvalho Chehab if (st == NULL)
27439a0bf528SMauro Carvalho Chehab return NULL;
27449a0bf528SMauro Carvalho Chehab
27459a0bf528SMauro Carvalho Chehab memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
27469a0bf528SMauro Carvalho Chehab st->i2c_adap = i2c_adap;
27479a0bf528SMauro Carvalho Chehab st->i2c_addr = i2c_addr;
27489a0bf528SMauro Carvalho Chehab st->gpio_val = cfg->gpio_val;
27499a0bf528SMauro Carvalho Chehab st->gpio_dir = cfg->gpio_dir;
27509a0bf528SMauro Carvalho Chehab
27519a0bf528SMauro Carvalho Chehab /* Ensure the output mode remains at the previous default if it's
27529a0bf528SMauro Carvalho Chehab * not specifically set by the caller.
27539a0bf528SMauro Carvalho Chehab */
27549a0bf528SMauro Carvalho Chehab if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
27559a0bf528SMauro Carvalho Chehab st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
27569a0bf528SMauro Carvalho Chehab
27579a0bf528SMauro Carvalho Chehab demod = &st->demod;
27589a0bf528SMauro Carvalho Chehab demod->demodulator_priv = st;
27599a0bf528SMauro Carvalho Chehab memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
27609a0bf528SMauro Carvalho Chehab mutex_init(&st->i2c_buffer_lock);
27619a0bf528SMauro Carvalho Chehab
27629a0bf528SMauro Carvalho Chehab dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
27639a0bf528SMauro Carvalho Chehab
27649a0bf528SMauro Carvalho Chehab if (dib7000p_identify(st) != 0)
27659a0bf528SMauro Carvalho Chehab goto error;
27669a0bf528SMauro Carvalho Chehab
27679a0bf528SMauro Carvalho Chehab st->version = dib7000p_read_word(st, 897);
27689a0bf528SMauro Carvalho Chehab
27699a0bf528SMauro Carvalho Chehab /* FIXME: make sure the dev.parent field is initialized, or else
27709a0bf528SMauro Carvalho Chehab request_firmware() will hit an OOPS (this should be moved somewhere
27719a0bf528SMauro Carvalho Chehab more common) */
27729a0bf528SMauro Carvalho Chehab st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
27739a0bf528SMauro Carvalho Chehab
27749a0bf528SMauro Carvalho Chehab dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
27759a0bf528SMauro Carvalho Chehab
27769a0bf528SMauro Carvalho Chehab /* init 7090 tuner adapter */
277785709cbfSMauro Carvalho Chehab strscpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface",
277885709cbfSMauro Carvalho Chehab sizeof(st->dib7090_tuner_adap.name));
27799a0bf528SMauro Carvalho Chehab st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
27809a0bf528SMauro Carvalho Chehab st->dib7090_tuner_adap.algo_data = NULL;
27819a0bf528SMauro Carvalho Chehab st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
27829a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&st->dib7090_tuner_adap, st);
27839a0bf528SMauro Carvalho Chehab i2c_add_adapter(&st->dib7090_tuner_adap);
27849a0bf528SMauro Carvalho Chehab
27859a0bf528SMauro Carvalho Chehab dib7000p_demod_reset(st);
27869a0bf528SMauro Carvalho Chehab
2787041ad449SMauro Carvalho Chehab dib7000p_reset_stats(demod);
2788041ad449SMauro Carvalho Chehab
27899a0bf528SMauro Carvalho Chehab if (st->version == SOC7090) {
27909a0bf528SMauro Carvalho Chehab dib7090_set_output_mode(demod, st->cfg.output_mode);
27919a0bf528SMauro Carvalho Chehab dib7090_set_diversity_in(demod, 0);
27929a0bf528SMauro Carvalho Chehab }
27939a0bf528SMauro Carvalho Chehab
27949a0bf528SMauro Carvalho Chehab return demod;
27959a0bf528SMauro Carvalho Chehab
27969a0bf528SMauro Carvalho Chehab error:
27979a0bf528SMauro Carvalho Chehab kfree(st);
27989a0bf528SMauro Carvalho Chehab return NULL;
27999a0bf528SMauro Carvalho Chehab }
28008abe4a0aSMauro Carvalho Chehab
dib7000p_attach(struct dib7000p_ops * ops)28018abe4a0aSMauro Carvalho Chehab void *dib7000p_attach(struct dib7000p_ops *ops)
28028abe4a0aSMauro Carvalho Chehab {
28038abe4a0aSMauro Carvalho Chehab if (!ops)
28048abe4a0aSMauro Carvalho Chehab return NULL;
28058abe4a0aSMauro Carvalho Chehab
28068abe4a0aSMauro Carvalho Chehab ops->slave_reset = dib7090_slave_reset;
28078abe4a0aSMauro Carvalho Chehab ops->get_adc_power = dib7090_get_adc_power;
28088abe4a0aSMauro Carvalho Chehab ops->dib7000pc_detection = dib7000pc_detection;
28098abe4a0aSMauro Carvalho Chehab ops->get_i2c_tuner = dib7090_get_i2c_tuner;
28108abe4a0aSMauro Carvalho Chehab ops->tuner_sleep = dib7090_tuner_sleep;
28118abe4a0aSMauro Carvalho Chehab ops->init = dib7000p_init;
28128abe4a0aSMauro Carvalho Chehab ops->set_agc1_min = dib7000p_set_agc1_min;
28138abe4a0aSMauro Carvalho Chehab ops->set_gpio = dib7000p_set_gpio;
28148abe4a0aSMauro Carvalho Chehab ops->i2c_enumeration = dib7000p_i2c_enumeration;
28158abe4a0aSMauro Carvalho Chehab ops->pid_filter = dib7000p_pid_filter;
28168abe4a0aSMauro Carvalho Chehab ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
28178abe4a0aSMauro Carvalho Chehab ops->get_i2c_master = dib7000p_get_i2c_master;
28188abe4a0aSMauro Carvalho Chehab ops->update_pll = dib7000p_update_pll;
28198abe4a0aSMauro Carvalho Chehab ops->ctrl_timf = dib7000p_ctrl_timf;
28208abe4a0aSMauro Carvalho Chehab ops->get_agc_values = dib7000p_get_agc_values;
28218abe4a0aSMauro Carvalho Chehab ops->set_wbd_ref = dib7000p_set_wbd_ref;
28228abe4a0aSMauro Carvalho Chehab
28238abe4a0aSMauro Carvalho Chehab return ops;
28248abe4a0aSMauro Carvalho Chehab }
2825*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(dib7000p_attach);
28269a0bf528SMauro Carvalho Chehab
2827bd336e63SMax Kellermann static const struct dvb_frontend_ops dib7000p_ops = {
28289a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBT },
28299a0bf528SMauro Carvalho Chehab .info = {
28309a0bf528SMauro Carvalho Chehab .name = "DiBcom 7000PC",
2831f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 44250 * kHz,
2832f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 867250 * kHz,
2833f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 62500,
28349a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO |
28359a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
28369a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
28379a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
28389a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
28399a0bf528SMauro Carvalho Chehab },
28409a0bf528SMauro Carvalho Chehab
28419a0bf528SMauro Carvalho Chehab .release = dib7000p_release,
28429a0bf528SMauro Carvalho Chehab
28439a0bf528SMauro Carvalho Chehab .init = dib7000p_wakeup,
28449a0bf528SMauro Carvalho Chehab .sleep = dib7000p_sleep,
28459a0bf528SMauro Carvalho Chehab
28469a0bf528SMauro Carvalho Chehab .set_frontend = dib7000p_set_frontend,
28479a0bf528SMauro Carvalho Chehab .get_tune_settings = dib7000p_fe_get_tune_settings,
28489a0bf528SMauro Carvalho Chehab .get_frontend = dib7000p_get_frontend,
28499a0bf528SMauro Carvalho Chehab
28509a0bf528SMauro Carvalho Chehab .read_status = dib7000p_read_status,
28519a0bf528SMauro Carvalho Chehab .read_ber = dib7000p_read_ber,
28529a0bf528SMauro Carvalho Chehab .read_signal_strength = dib7000p_read_signal_strength,
28539a0bf528SMauro Carvalho Chehab .read_snr = dib7000p_read_snr,
28549a0bf528SMauro Carvalho Chehab .read_ucblocks = dib7000p_read_unc_blocks,
28559a0bf528SMauro Carvalho Chehab };
28569a0bf528SMauro Carvalho Chehab
285799e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <olivie.grenie@parrot.com>");
285899e44da7SPatrick Boettcher MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
28599a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
28609a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
2861