1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
49a0bf528SMauro Carvalho Chehab *
59a0bf528SMauro Carvalho Chehab * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
69a0bf528SMauro Carvalho Chehab */
78af16adfSMauro Carvalho Chehab
88af16adfSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98af16adfSMauro Carvalho Chehab
109a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
119a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
129a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
139a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
14b4600d70SMauro Carvalho Chehab #include <asm/div64.h>
159a0bf528SMauro Carvalho Chehab
16f97fa3dcSAndy Shevchenko #include <linux/int_log.h>
179a0bf528SMauro Carvalho Chehab
18fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
199a0bf528SMauro Carvalho Chehab
209a0bf528SMauro Carvalho Chehab #include "dib8000.h"
219a0bf528SMauro Carvalho Chehab
229a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1
239a0bf528SMauro Carvalho Chehab #define LAYER_A 1
249a0bf528SMauro Carvalho Chehab #define LAYER_B 2
259a0bf528SMauro Carvalho Chehab #define LAYER_C 3
269a0bf528SMauro Carvalho Chehab
279a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6
28173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */
299a0bf528SMauro Carvalho Chehab
309a0bf528SMauro Carvalho Chehab static int debug;
319a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
329a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
339a0bf528SMauro Carvalho Chehab
348af16adfSMauro Carvalho Chehab #define dprintk(fmt, arg...) do { \
358af16adfSMauro Carvalho Chehab if (debug) \
368af16adfSMauro Carvalho Chehab printk(KERN_DEBUG pr_fmt("%s: " fmt), \
378af16adfSMauro Carvalho Chehab __func__, ##arg); \
388af16adfSMauro Carvalho Chehab } while (0)
399a0bf528SMauro Carvalho Chehab
409a0bf528SMauro Carvalho Chehab struct i2c_device {
419a0bf528SMauro Carvalho Chehab struct i2c_adapter *adap;
429a0bf528SMauro Carvalho Chehab u8 addr;
439a0bf528SMauro Carvalho Chehab u8 *i2c_write_buffer;
449a0bf528SMauro Carvalho Chehab u8 *i2c_read_buffer;
459a0bf528SMauro Carvalho Chehab struct mutex *i2c_buffer_lock;
469a0bf528SMauro Carvalho Chehab };
479a0bf528SMauro Carvalho Chehab
48173a64cbSPatrick Boettcher enum param_loop_step {
49173a64cbSPatrick Boettcher LOOP_TUNE_1,
50173a64cbSPatrick Boettcher LOOP_TUNE_2
51173a64cbSPatrick Boettcher };
52173a64cbSPatrick Boettcher
53173a64cbSPatrick Boettcher enum dib8000_autosearch_step {
54173a64cbSPatrick Boettcher AS_START = 0,
55173a64cbSPatrick Boettcher AS_SEARCHING_FFT,
56173a64cbSPatrick Boettcher AS_SEARCHING_GUARD,
57173a64cbSPatrick Boettcher AS_DONE = 100,
58173a64cbSPatrick Boettcher };
59173a64cbSPatrick Boettcher
60173a64cbSPatrick Boettcher enum timeout_mode {
61173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_OFF = 0,
62173a64cbSPatrick Boettcher SYMBOL_DEPENDENT_ON,
63173a64cbSPatrick Boettcher };
64173a64cbSPatrick Boettcher
659a0bf528SMauro Carvalho Chehab struct dib8000_state {
669a0bf528SMauro Carvalho Chehab struct dib8000_config cfg;
679a0bf528SMauro Carvalho Chehab
689a0bf528SMauro Carvalho Chehab struct i2c_device i2c;
699a0bf528SMauro Carvalho Chehab
709a0bf528SMauro Carvalho Chehab struct dibx000_i2c_master i2c_master;
719a0bf528SMauro Carvalho Chehab
729a0bf528SMauro Carvalho Chehab u16 wbd_ref;
739a0bf528SMauro Carvalho Chehab
749a0bf528SMauro Carvalho Chehab u8 current_band;
759a0bf528SMauro Carvalho Chehab u32 current_bandwidth;
769a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *current_agc;
779a0bf528SMauro Carvalho Chehab u32 timf;
789a0bf528SMauro Carvalho Chehab u32 timf_default;
799a0bf528SMauro Carvalho Chehab
809a0bf528SMauro Carvalho Chehab u8 div_force_off:1;
819a0bf528SMauro Carvalho Chehab u8 div_state:1;
829a0bf528SMauro Carvalho Chehab u16 div_sync_wait;
839a0bf528SMauro Carvalho Chehab
849a0bf528SMauro Carvalho Chehab u8 agc_state;
859a0bf528SMauro Carvalho Chehab u8 differential_constellation;
869a0bf528SMauro Carvalho Chehab u8 diversity_onoff;
879a0bf528SMauro Carvalho Chehab
889a0bf528SMauro Carvalho Chehab s16 ber_monitored_layer;
899a0bf528SMauro Carvalho Chehab u16 gpio_dir;
909a0bf528SMauro Carvalho Chehab u16 gpio_val;
919a0bf528SMauro Carvalho Chehab
929a0bf528SMauro Carvalho Chehab u16 revision;
939a0bf528SMauro Carvalho Chehab u8 isdbt_cfg_loaded;
949a0bf528SMauro Carvalho Chehab enum frontend_tune_state tune_state;
95173a64cbSPatrick Boettcher s32 status;
969a0bf528SMauro Carvalho Chehab
979a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
989a0bf528SMauro Carvalho Chehab
999a0bf528SMauro Carvalho Chehab /* for the I2C transfer */
1009a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2];
1019a0bf528SMauro Carvalho Chehab u8 i2c_write_buffer[4];
1029a0bf528SMauro Carvalho Chehab u8 i2c_read_buffer[2];
1039a0bf528SMauro Carvalho Chehab struct mutex i2c_buffer_lock;
1049a0bf528SMauro Carvalho Chehab u8 input_mode_mpeg;
1059a0bf528SMauro Carvalho Chehab
1069a0bf528SMauro Carvalho Chehab u16 tuner_enable;
1079a0bf528SMauro Carvalho Chehab struct i2c_adapter dib8096p_tuner_adap;
108173a64cbSPatrick Boettcher u16 current_demod_bw;
109173a64cbSPatrick Boettcher
110173a64cbSPatrick Boettcher u16 seg_mask;
111173a64cbSPatrick Boettcher u16 seg_diff_mask;
112173a64cbSPatrick Boettcher u16 mode;
113173a64cbSPatrick Boettcher u8 layer_b_nb_seg;
114173a64cbSPatrick Boettcher u8 layer_c_nb_seg;
115173a64cbSPatrick Boettcher
116173a64cbSPatrick Boettcher u8 channel_parameters_set;
117173a64cbSPatrick Boettcher u16 autosearch_state;
118173a64cbSPatrick Boettcher u16 found_nfft;
119173a64cbSPatrick Boettcher u16 found_guard;
120173a64cbSPatrick Boettcher u8 subchannel;
121173a64cbSPatrick Boettcher u8 symbol_duration;
122d6c62b76SMauro Carvalho Chehab unsigned long timeout;
123173a64cbSPatrick Boettcher u8 longest_intlv_layer;
124173a64cbSPatrick Boettcher u16 output_mode;
125173a64cbSPatrick Boettcher
126704f01bbSMauro Carvalho Chehab /* for DVBv5 stats */
1277a9d85d5SMauro Carvalho Chehab s64 init_ucb;
1280400c535SMauro Carvalho Chehab unsigned long per_jiffies_stats;
1290400c535SMauro Carvalho Chehab unsigned long ber_jiffies_stats;
1300400c535SMauro Carvalho Chehab unsigned long ber_jiffies_stats_layer[3];
131704f01bbSMauro Carvalho Chehab
132173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
133173a64cbSPatrick Boettcher u16 agc1_max;
134173a64cbSPatrick Boettcher u16 agc1_min;
135173a64cbSPatrick Boettcher u16 agc2_max;
136173a64cbSPatrick Boettcher u16 agc2_min;
137173a64cbSPatrick Boettcher #endif
1389a0bf528SMauro Carvalho Chehab };
1399a0bf528SMauro Carvalho Chehab
1409a0bf528SMauro Carvalho Chehab enum dib8000_power_mode {
1419a0bf528SMauro Carvalho Chehab DIB8000_POWER_ALL = 0,
1429a0bf528SMauro Carvalho Chehab DIB8000_POWER_INTERFACE_ONLY,
1439a0bf528SMauro Carvalho Chehab };
1449a0bf528SMauro Carvalho Chehab
dib8000_i2c_read16(struct i2c_device * i2c,u16 reg)1459a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
1469a0bf528SMauro Carvalho Chehab {
1479a0bf528SMauro Carvalho Chehab u16 ret;
1489a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2] = {
1499a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
1509a0bf528SMauro Carvalho Chehab {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
1519a0bf528SMauro Carvalho Chehab };
1529a0bf528SMauro Carvalho Chehab
1539a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
1548af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n");
1559a0bf528SMauro Carvalho Chehab return 0;
1569a0bf528SMauro Carvalho Chehab }
1579a0bf528SMauro Carvalho Chehab
1589a0bf528SMauro Carvalho Chehab msg[0].buf = i2c->i2c_write_buffer;
1599a0bf528SMauro Carvalho Chehab msg[0].buf[0] = reg >> 8;
1609a0bf528SMauro Carvalho Chehab msg[0].buf[1] = reg & 0xff;
1619a0bf528SMauro Carvalho Chehab msg[1].buf = i2c->i2c_read_buffer;
1629a0bf528SMauro Carvalho Chehab
1639a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c->adap, msg, 2) != 2)
1648af16adfSMauro Carvalho Chehab dprintk("i2c read error on %d\n", reg);
1659a0bf528SMauro Carvalho Chehab
1669a0bf528SMauro Carvalho Chehab ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
1679a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock);
1689a0bf528SMauro Carvalho Chehab return ret;
1699a0bf528SMauro Carvalho Chehab }
1709a0bf528SMauro Carvalho Chehab
__dib8000_read_word(struct dib8000_state * state,u16 reg)1715ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
1729a0bf528SMauro Carvalho Chehab {
1739a0bf528SMauro Carvalho Chehab u16 ret;
1749a0bf528SMauro Carvalho Chehab
1759a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = reg >> 8;
1769a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff;
1779a0bf528SMauro Carvalho Chehab
1789a0bf528SMauro Carvalho Chehab memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1799a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1;
1809a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0;
1819a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer;
1829a0bf528SMauro Carvalho Chehab state->msg[0].len = 2;
1839a0bf528SMauro Carvalho Chehab state->msg[1].addr = state->i2c.addr >> 1;
1849a0bf528SMauro Carvalho Chehab state->msg[1].flags = I2C_M_RD;
1859a0bf528SMauro Carvalho Chehab state->msg[1].buf = state->i2c_read_buffer;
1869a0bf528SMauro Carvalho Chehab state->msg[1].len = 2;
1879a0bf528SMauro Carvalho Chehab
1889a0bf528SMauro Carvalho Chehab if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
1898af16adfSMauro Carvalho Chehab dprintk("i2c read error on %d\n", reg);
1909a0bf528SMauro Carvalho Chehab
1919a0bf528SMauro Carvalho Chehab ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1925ac64ba1SMauro Carvalho Chehab
1935ac64ba1SMauro Carvalho Chehab return ret;
1945ac64ba1SMauro Carvalho Chehab }
1955ac64ba1SMauro Carvalho Chehab
dib8000_read_word(struct dib8000_state * state,u16 reg)1965ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
1975ac64ba1SMauro Carvalho Chehab {
1985ac64ba1SMauro Carvalho Chehab u16 ret;
1995ac64ba1SMauro Carvalho Chehab
2005ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2018af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n");
2025ac64ba1SMauro Carvalho Chehab return 0;
2035ac64ba1SMauro Carvalho Chehab }
2045ac64ba1SMauro Carvalho Chehab
2055ac64ba1SMauro Carvalho Chehab ret = __dib8000_read_word(state, reg);
2065ac64ba1SMauro Carvalho Chehab
2079a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock);
2089a0bf528SMauro Carvalho Chehab
2099a0bf528SMauro Carvalho Chehab return ret;
2109a0bf528SMauro Carvalho Chehab }
2119a0bf528SMauro Carvalho Chehab
dib8000_read32(struct dib8000_state * state,u16 reg)2129a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
2139a0bf528SMauro Carvalho Chehab {
2149a0bf528SMauro Carvalho Chehab u16 rw[2];
2159a0bf528SMauro Carvalho Chehab
2165ac64ba1SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2178af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n");
2185ac64ba1SMauro Carvalho Chehab return 0;
2195ac64ba1SMauro Carvalho Chehab }
2205ac64ba1SMauro Carvalho Chehab
2215ac64ba1SMauro Carvalho Chehab rw[0] = __dib8000_read_word(state, reg + 0);
2225ac64ba1SMauro Carvalho Chehab rw[1] = __dib8000_read_word(state, reg + 1);
2235ac64ba1SMauro Carvalho Chehab
2245ac64ba1SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock);
2259a0bf528SMauro Carvalho Chehab
2269a0bf528SMauro Carvalho Chehab return ((rw[0] << 16) | (rw[1]));
2279a0bf528SMauro Carvalho Chehab }
2289a0bf528SMauro Carvalho Chehab
dib8000_i2c_write16(struct i2c_device * i2c,u16 reg,u16 val)2299a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
2309a0bf528SMauro Carvalho Chehab {
2319a0bf528SMauro Carvalho Chehab struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
2329a0bf528SMauro Carvalho Chehab int ret = 0;
2339a0bf528SMauro Carvalho Chehab
2349a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
2358af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n");
2369a0bf528SMauro Carvalho Chehab return -EINVAL;
2379a0bf528SMauro Carvalho Chehab }
2389a0bf528SMauro Carvalho Chehab
2399a0bf528SMauro Carvalho Chehab msg.buf = i2c->i2c_write_buffer;
2409a0bf528SMauro Carvalho Chehab msg.buf[0] = (reg >> 8) & 0xff;
2419a0bf528SMauro Carvalho Chehab msg.buf[1] = reg & 0xff;
2429a0bf528SMauro Carvalho Chehab msg.buf[2] = (val >> 8) & 0xff;
2439a0bf528SMauro Carvalho Chehab msg.buf[3] = val & 0xff;
2449a0bf528SMauro Carvalho Chehab
2459a0bf528SMauro Carvalho Chehab ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
2469a0bf528SMauro Carvalho Chehab mutex_unlock(i2c->i2c_buffer_lock);
2479a0bf528SMauro Carvalho Chehab
2489a0bf528SMauro Carvalho Chehab return ret;
2499a0bf528SMauro Carvalho Chehab }
2509a0bf528SMauro Carvalho Chehab
dib8000_write_word(struct dib8000_state * state,u16 reg,u16 val)2519a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
2529a0bf528SMauro Carvalho Chehab {
2539a0bf528SMauro Carvalho Chehab int ret;
2549a0bf528SMauro Carvalho Chehab
2559a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2568af16adfSMauro Carvalho Chehab dprintk("could not acquire lock\n");
2579a0bf528SMauro Carvalho Chehab return -EINVAL;
2589a0bf528SMauro Carvalho Chehab }
2599a0bf528SMauro Carvalho Chehab
2609a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
2619a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff;
2629a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[2] = (val >> 8) & 0xff;
2639a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[3] = val & 0xff;
2649a0bf528SMauro Carvalho Chehab
2659a0bf528SMauro Carvalho Chehab memset(&state->msg[0], 0, sizeof(struct i2c_msg));
2669a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.addr >> 1;
2679a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0;
2689a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer;
2699a0bf528SMauro Carvalho Chehab state->msg[0].len = 4;
2709a0bf528SMauro Carvalho Chehab
2719a0bf528SMauro Carvalho Chehab ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
2729a0bf528SMauro Carvalho Chehab -EREMOTEIO : 0);
2739a0bf528SMauro Carvalho Chehab mutex_unlock(&state->i2c_buffer_lock);
2749a0bf528SMauro Carvalho Chehab
2759a0bf528SMauro Carvalho Chehab return ret;
2769a0bf528SMauro Carvalho Chehab }
2779a0bf528SMauro Carvalho Chehab
2789a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
2799a0bf528SMauro Carvalho Chehab (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
2809a0bf528SMauro Carvalho Chehab (920 << 5) | 0x09
2819a0bf528SMauro Carvalho Chehab };
2829a0bf528SMauro Carvalho Chehab
2839a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = {
2849a0bf528SMauro Carvalho Chehab (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
2859a0bf528SMauro Carvalho Chehab };
2869a0bf528SMauro Carvalho Chehab
2879a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
2889a0bf528SMauro Carvalho Chehab (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
2899a0bf528SMauro Carvalho Chehab (-931 << 5) | 0x0f
2909a0bf528SMauro Carvalho Chehab };
2919a0bf528SMauro Carvalho Chehab
2929a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
2939a0bf528SMauro Carvalho Chehab (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
2949a0bf528SMauro Carvalho Chehab (982 << 5) | 0x0c
2959a0bf528SMauro Carvalho Chehab };
2969a0bf528SMauro Carvalho Chehab
2979a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
2989a0bf528SMauro Carvalho Chehab (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
2999a0bf528SMauro Carvalho Chehab (-720 << 5) | 0x0d
3009a0bf528SMauro Carvalho Chehab };
3019a0bf528SMauro Carvalho Chehab
3029a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = {
3039a0bf528SMauro Carvalho Chehab (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
3049a0bf528SMauro Carvalho Chehab (-610 << 5) | 0x0a
3059a0bf528SMauro Carvalho Chehab };
3069a0bf528SMauro Carvalho Chehab
3079a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
3089a0bf528SMauro Carvalho Chehab (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
3099a0bf528SMauro Carvalho Chehab (-922 << 5) | 0x0d
3109a0bf528SMauro Carvalho Chehab };
3119a0bf528SMauro Carvalho Chehab
3129a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = {
3139a0bf528SMauro Carvalho Chehab (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
3149a0bf528SMauro Carvalho Chehab (-655 << 5) | 0x0a
3159a0bf528SMauro Carvalho Chehab };
3169a0bf528SMauro Carvalho Chehab
3179a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
3189a0bf528SMauro Carvalho Chehab (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
3199a0bf528SMauro Carvalho Chehab (-958 << 5) | 0x13
3209a0bf528SMauro Carvalho Chehab };
3219a0bf528SMauro Carvalho Chehab
3229a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
3239a0bf528SMauro Carvalho Chehab (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
3249a0bf528SMauro Carvalho Chehab (-568 << 5) | 0x0f
3259a0bf528SMauro Carvalho Chehab };
3269a0bf528SMauro Carvalho Chehab
3279a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
3289a0bf528SMauro Carvalho Chehab (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
3299a0bf528SMauro Carvalho Chehab (-848 << 5) | 0x13
3309a0bf528SMauro Carvalho Chehab };
3319a0bf528SMauro Carvalho Chehab
3329a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = {
3339a0bf528SMauro Carvalho Chehab (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
3349a0bf528SMauro Carvalho Chehab (-869 << 5) | 0x13
3359a0bf528SMauro Carvalho Chehab };
3369a0bf528SMauro Carvalho Chehab
3379a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
3389a0bf528SMauro Carvalho Chehab (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
3399a0bf528SMauro Carvalho Chehab (-598 << 5) | 0x10
3409a0bf528SMauro Carvalho Chehab };
3419a0bf528SMauro Carvalho Chehab
3429a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = {
3439a0bf528SMauro Carvalho Chehab (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
3449a0bf528SMauro Carvalho Chehab (585 << 5) | 0x0f
3459a0bf528SMauro Carvalho Chehab };
3469a0bf528SMauro Carvalho Chehab
3479a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
3489a0bf528SMauro Carvalho Chehab (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
3499a0bf528SMauro Carvalho Chehab (0 << 5) | 0x14
3509a0bf528SMauro Carvalho Chehab };
3519a0bf528SMauro Carvalho Chehab
3529a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
3539a0bf528SMauro Carvalho Chehab (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
3549a0bf528SMauro Carvalho Chehab (-877 << 5) | 0x15
3559a0bf528SMauro Carvalho Chehab };
3569a0bf528SMauro Carvalho Chehab
3579a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
3589a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
3599a0bf528SMauro Carvalho Chehab (-921 << 5) | 0x14
3609a0bf528SMauro Carvalho Chehab };
3619a0bf528SMauro Carvalho Chehab
3629a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = {
3639a0bf528SMauro Carvalho Chehab (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
3649a0bf528SMauro Carvalho Chehab (690 << 5) | 0x14
3659a0bf528SMauro Carvalho Chehab };
3669a0bf528SMauro Carvalho Chehab
3679a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = {
3689a0bf528SMauro Carvalho Chehab 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
3699a0bf528SMauro Carvalho Chehab };
3709a0bf528SMauro Carvalho Chehab
3719a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = {
3729a0bf528SMauro Carvalho Chehab 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
3739a0bf528SMauro Carvalho Chehab };
3749a0bf528SMauro Carvalho Chehab
3759a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = {
3769a0bf528SMauro Carvalho Chehab 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
3779a0bf528SMauro Carvalho Chehab };
3789a0bf528SMauro Carvalho Chehab
fft_to_mode(struct dib8000_state * state)3799a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state)
3809a0bf528SMauro Carvalho Chehab {
3819a0bf528SMauro Carvalho Chehab u16 mode;
3829a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) {
3839a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
3849a0bf528SMauro Carvalho Chehab mode = 1;
3859a0bf528SMauro Carvalho Chehab break;
3869a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
3879a0bf528SMauro Carvalho Chehab mode = 2;
3889a0bf528SMauro Carvalho Chehab break;
3899a0bf528SMauro Carvalho Chehab default:
3909a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_AUTO:
3919a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
3929a0bf528SMauro Carvalho Chehab mode = 3;
3939a0bf528SMauro Carvalho Chehab break;
3949a0bf528SMauro Carvalho Chehab }
3959a0bf528SMauro Carvalho Chehab return mode;
3969a0bf528SMauro Carvalho Chehab }
3979a0bf528SMauro Carvalho Chehab
dib8000_set_acquisition_mode(struct dib8000_state * state)3989a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state)
3999a0bf528SMauro Carvalho Chehab {
4009a0bf528SMauro Carvalho Chehab u16 nud = dib8000_read_word(state, 298);
4019a0bf528SMauro Carvalho Chehab nud |= (1 << 3) | (1 << 0);
4028af16adfSMauro Carvalho Chehab dprintk("acquisition mode activated\n");
4039a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 298, nud);
4049a0bf528SMauro Carvalho Chehab }
dib8000_set_output_mode(struct dvb_frontend * fe,int mode)4059a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
4069a0bf528SMauro Carvalho Chehab {
4079a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
4089a0bf528SMauro Carvalho Chehab u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
4099a0bf528SMauro Carvalho Chehab
410173a64cbSPatrick Boettcher state->output_mode = mode;
4119a0bf528SMauro Carvalho Chehab outreg = 0;
4129a0bf528SMauro Carvalho Chehab fifo_threshold = 1792;
4139a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
4149a0bf528SMauro Carvalho Chehab
4158af16adfSMauro Carvalho Chehab dprintk("-I- Setting output mode for demod %p to %d\n",
4169a0bf528SMauro Carvalho Chehab &state->fe[0], mode);
4179a0bf528SMauro Carvalho Chehab
4189a0bf528SMauro Carvalho Chehab switch (mode) {
4199a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
4209a0bf528SMauro Carvalho Chehab outreg = (1 << 10); /* 0x0400 */
4219a0bf528SMauro Carvalho Chehab break;
4229a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
4239a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (1 << 6); /* 0x0440 */
4249a0bf528SMauro Carvalho Chehab break;
4259a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: // STBs with serial input
4269a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
4279a0bf528SMauro Carvalho Chehab break;
4289a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY:
4299a0bf528SMauro Carvalho Chehab if (state->cfg.hostbus_diversity) {
4309a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (4 << 6); /* 0x0500 */
4319a0bf528SMauro Carvalho Chehab sram &= 0xfdff;
4329a0bf528SMauro Carvalho Chehab } else
4339a0bf528SMauro Carvalho Chehab sram |= 0x0c00;
4349a0bf528SMauro Carvalho Chehab break;
4359a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
4369a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1);
4379a0bf528SMauro Carvalho Chehab fifo_threshold = 512;
4389a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (5 << 6);
4399a0bf528SMauro Carvalho Chehab break;
4409a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: // disable
4419a0bf528SMauro Carvalho Chehab outreg = 0;
4429a0bf528SMauro Carvalho Chehab break;
4439a0bf528SMauro Carvalho Chehab
4449a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC:
4459a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (3 << 6);
4469a0bf528SMauro Carvalho Chehab dib8000_set_acquisition_mode(state);
4479a0bf528SMauro Carvalho Chehab break;
4489a0bf528SMauro Carvalho Chehab
4499a0bf528SMauro Carvalho Chehab default:
4508af16adfSMauro Carvalho Chehab dprintk("Unhandled output_mode passed to be set for demod %p\n",
4519a0bf528SMauro Carvalho Chehab &state->fe[0]);
4529a0bf528SMauro Carvalho Chehab return -EINVAL;
4539a0bf528SMauro Carvalho Chehab }
4549a0bf528SMauro Carvalho Chehab
4559a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes)
4569a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5);
4579a0bf528SMauro Carvalho Chehab
4589a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 299, smo_mode);
4599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
4609a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1286, outreg);
4619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1291, sram);
4629a0bf528SMauro Carvalho Chehab
4639a0bf528SMauro Carvalho Chehab return 0;
4649a0bf528SMauro Carvalho Chehab }
4659a0bf528SMauro Carvalho Chehab
dib8000_set_diversity_in(struct dvb_frontend * fe,int onoff)4669a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
4679a0bf528SMauro Carvalho Chehab {
4689a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
469173a64cbSPatrick Boettcher u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
4709a0bf528SMauro Carvalho Chehab
4718af16adfSMauro Carvalho Chehab dprintk("set diversity input to %i\n", onoff);
4729a0bf528SMauro Carvalho Chehab if (!state->differential_constellation) {
4739a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
4749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
4759a0bf528SMauro Carvalho Chehab } else {
4769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
4779a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
4789a0bf528SMauro Carvalho Chehab }
4799a0bf528SMauro Carvalho Chehab state->diversity_onoff = onoff;
4809a0bf528SMauro Carvalho Chehab
4819a0bf528SMauro Carvalho Chehab switch (onoff) {
4829a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */
4839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 1);
4849a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 0);
4859a0bf528SMauro Carvalho Chehab break;
4869a0bf528SMauro Carvalho Chehab case 1: /* both ways */
4879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 6);
4889a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 6);
4899a0bf528SMauro Carvalho Chehab break;
4909a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */
4919a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 270, 0);
4929a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 271, 1);
4939a0bf528SMauro Carvalho Chehab break;
4949a0bf528SMauro Carvalho Chehab }
495173a64cbSPatrick Boettcher
496173a64cbSPatrick Boettcher if (state->revision == 0x8002) {
497173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 903);
498173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp & ~(1 << 3));
499173a64cbSPatrick Boettcher msleep(30);
500173a64cbSPatrick Boettcher dib8000_write_word(state, 903, tmp | (1 << 3));
501173a64cbSPatrick Boettcher }
5029a0bf528SMauro Carvalho Chehab return 0;
5039a0bf528SMauro Carvalho Chehab }
5049a0bf528SMauro Carvalho Chehab
dib8000_set_power_mode(struct dib8000_state * state,enum dib8000_power_mode mode)5059a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
5069a0bf528SMauro Carvalho Chehab {
5079a0bf528SMauro Carvalho Chehab /* by default everything is going to be powered off */
5089a0bf528SMauro Carvalho Chehab u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
5099a0bf528SMauro Carvalho Chehab reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
5109a0bf528SMauro Carvalho Chehab reg_1280;
5119a0bf528SMauro Carvalho Chehab
5129a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
5139a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
5149a0bf528SMauro Carvalho Chehab else
5159a0bf528SMauro Carvalho Chehab reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
5169a0bf528SMauro Carvalho Chehab
5179a0bf528SMauro Carvalho Chehab /* now, depending on the requested mode, we power on */
5189a0bf528SMauro Carvalho Chehab switch (mode) {
5199a0bf528SMauro Carvalho Chehab /* power up everything in the demod */
5209a0bf528SMauro Carvalho Chehab case DIB8000_POWER_ALL:
5219a0bf528SMauro Carvalho Chehab reg_774 = 0x0000;
5229a0bf528SMauro Carvalho Chehab reg_775 = 0x0000;
5239a0bf528SMauro Carvalho Chehab reg_776 = 0x0000;
5249a0bf528SMauro Carvalho Chehab reg_900 &= 0xfffc;
5259a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
5269a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff;
5279a0bf528SMauro Carvalho Chehab else
5289a0bf528SMauro Carvalho Chehab reg_1280 &= 0x707f;
5299a0bf528SMauro Carvalho Chehab break;
5309a0bf528SMauro Carvalho Chehab case DIB8000_POWER_INTERFACE_ONLY:
5319a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
5329a0bf528SMauro Carvalho Chehab reg_1280 &= 0x00ff;
5339a0bf528SMauro Carvalho Chehab else
5349a0bf528SMauro Carvalho Chehab reg_1280 &= 0xfa7b;
5359a0bf528SMauro Carvalho Chehab break;
5369a0bf528SMauro Carvalho Chehab }
5379a0bf528SMauro Carvalho Chehab
5388af16adfSMauro Carvalho Chehab dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x\n", reg_774, reg_775, reg_776, reg_900, reg_1280);
5399a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 774, reg_774);
5409a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 775, reg_775);
5419a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 776, reg_776);
5429a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 900, reg_900);
5439a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, reg_1280);
5449a0bf528SMauro Carvalho Chehab }
5459a0bf528SMauro Carvalho Chehab
dib8000_set_adc_state(struct dib8000_state * state,enum dibx000_adc_states no)5469a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
5479a0bf528SMauro Carvalho Chehab {
5489a0bf528SMauro Carvalho Chehab int ret = 0;
5499a0bf528SMauro Carvalho Chehab u16 reg, reg_907 = dib8000_read_word(state, 907);
5509a0bf528SMauro Carvalho Chehab u16 reg_908 = dib8000_read_word(state, 908);
5519a0bf528SMauro Carvalho Chehab
5529a0bf528SMauro Carvalho Chehab switch (no) {
5539a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_ON:
5549a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) {
5559a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0);
5569a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908);
5579a0bf528SMauro Carvalho Chehab reg_908 &= ~(1 << 1);
5589a0bf528SMauro Carvalho Chehab } else {
5599a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925);
5609a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 1 */
5619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg |
5629a0bf528SMauro Carvalho Chehab (1<<4) | (1<<2));
5639a0bf528SMauro Carvalho Chehab
564868c9a17SMauro Carvalho Chehab /* read access to make it works... strange ... */
5659a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925);
5669a0bf528SMauro Carvalho Chehab msleep(20);
5679a0bf528SMauro Carvalho Chehab /* en_slowAdc = 1 & reset_sladc = 0 */
5689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925, reg & ~(1<<4));
5699a0bf528SMauro Carvalho Chehab
5709a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
5719a0bf528SMauro Carvalho Chehab | (0x3 << 12));
5729a0bf528SMauro Carvalho Chehab /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
5739a0bf528SMauro Carvalho Chehab (Vin2 = Vcm) */
5749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, reg | (1 << 14)
5759a0bf528SMauro Carvalho Chehab | (3 << 12));
5769a0bf528SMauro Carvalho Chehab }
5779a0bf528SMauro Carvalho Chehab break;
5789a0bf528SMauro Carvalho Chehab
5799a0bf528SMauro Carvalho Chehab case DIBX000_SLOW_ADC_OFF:
5809a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) {
5819a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1925);
5829a0bf528SMauro Carvalho Chehab /* reset_sladc = 1 en_slowAdc = 0 */
5839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1925,
5849a0bf528SMauro Carvalho Chehab (reg & ~(1<<2)) | (1<<4));
5859a0bf528SMauro Carvalho Chehab }
5869a0bf528SMauro Carvalho Chehab reg_908 |= (1 << 1) | (1 << 0);
5879a0bf528SMauro Carvalho Chehab break;
5889a0bf528SMauro Carvalho Chehab
5899a0bf528SMauro Carvalho Chehab case DIBX000_ADC_ON:
5909a0bf528SMauro Carvalho Chehab reg_907 &= 0x0fff;
5919a0bf528SMauro Carvalho Chehab reg_908 &= 0x0003;
5929a0bf528SMauro Carvalho Chehab break;
5939a0bf528SMauro Carvalho Chehab
5949a0bf528SMauro Carvalho Chehab case DIBX000_ADC_OFF: // leave the VBG voltage on
595c063c7c6SMauro Carvalho Chehab reg_907 = (1 << 13) | (1 << 12);
596c063c7c6SMauro Carvalho Chehab reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
5979a0bf528SMauro Carvalho Chehab break;
5989a0bf528SMauro Carvalho Chehab
5999a0bf528SMauro Carvalho Chehab case DIBX000_VBG_ENABLE:
6009a0bf528SMauro Carvalho Chehab reg_907 &= ~(1 << 15);
6019a0bf528SMauro Carvalho Chehab break;
6029a0bf528SMauro Carvalho Chehab
6039a0bf528SMauro Carvalho Chehab case DIBX000_VBG_DISABLE:
6049a0bf528SMauro Carvalho Chehab reg_907 |= (1 << 15);
6059a0bf528SMauro Carvalho Chehab break;
6069a0bf528SMauro Carvalho Chehab
6079a0bf528SMauro Carvalho Chehab default:
6089a0bf528SMauro Carvalho Chehab break;
6099a0bf528SMauro Carvalho Chehab }
6109a0bf528SMauro Carvalho Chehab
6119a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 907, reg_907);
6129a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 908, reg_908);
6139a0bf528SMauro Carvalho Chehab
6149a0bf528SMauro Carvalho Chehab return ret;
6159a0bf528SMauro Carvalho Chehab }
6169a0bf528SMauro Carvalho Chehab
dib8000_set_bandwidth(struct dvb_frontend * fe,u32 bw)6179a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
6189a0bf528SMauro Carvalho Chehab {
6199a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
6209a0bf528SMauro Carvalho Chehab u32 timf;
6219a0bf528SMauro Carvalho Chehab
6229a0bf528SMauro Carvalho Chehab if (bw == 0)
6239a0bf528SMauro Carvalho Chehab bw = 6000;
6249a0bf528SMauro Carvalho Chehab
6259a0bf528SMauro Carvalho Chehab if (state->timf == 0) {
6268af16adfSMauro Carvalho Chehab dprintk("using default timf\n");
6279a0bf528SMauro Carvalho Chehab timf = state->timf_default;
6289a0bf528SMauro Carvalho Chehab } else {
6298af16adfSMauro Carvalho Chehab dprintk("using updated timf\n");
6309a0bf528SMauro Carvalho Chehab timf = state->timf;
6319a0bf528SMauro Carvalho Chehab }
6329a0bf528SMauro Carvalho Chehab
6339a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
6349a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
6359a0bf528SMauro Carvalho Chehab
6369a0bf528SMauro Carvalho Chehab return 0;
6379a0bf528SMauro Carvalho Chehab }
6389a0bf528SMauro Carvalho Chehab
dib8000_sad_calib(struct dib8000_state * state)6399a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state)
6409a0bf528SMauro Carvalho Chehab {
641173a64cbSPatrick Boettcher u8 sad_sel = 3;
642173a64cbSPatrick Boettcher
6439a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) {
644173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2));
645173a64cbSPatrick Boettcher dib8000_write_word(state, 923, 2048);
646173a64cbSPatrick Boettcher
647173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
648173a64cbSPatrick Boettcher dib8000_write_word(state, 922, (sad_sel << 2));
649173a64cbSPatrick Boettcher } else {
6509a0bf528SMauro Carvalho Chehab /* internal */
6519a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
652173a64cbSPatrick Boettcher dib8000_write_word(state, 924, 776);
6539a0bf528SMauro Carvalho Chehab
6549a0bf528SMauro Carvalho Chehab /* do the calibration */
6559a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (1 << 0));
6569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923, (0 << 0));
657173a64cbSPatrick Boettcher }
6589a0bf528SMauro Carvalho Chehab
6599a0bf528SMauro Carvalho Chehab msleep(1);
6609a0bf528SMauro Carvalho Chehab return 0;
6619a0bf528SMauro Carvalho Chehab }
6629a0bf528SMauro Carvalho Chehab
dib8000_set_wbd_ref(struct dvb_frontend * fe,u16 value)663d44913c1SMauro Carvalho Chehab static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
6649a0bf528SMauro Carvalho Chehab {
6659a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
6669a0bf528SMauro Carvalho Chehab if (value > 4095)
6679a0bf528SMauro Carvalho Chehab value = 4095;
6689a0bf528SMauro Carvalho Chehab state->wbd_ref = value;
6699a0bf528SMauro Carvalho Chehab return dib8000_write_word(state, 106, value);
6709a0bf528SMauro Carvalho Chehab }
671173a64cbSPatrick Boettcher
dib8000_reset_pll_common(struct dib8000_state * state,const struct dibx000_bandwidth_config * bw)6729a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
6739a0bf528SMauro Carvalho Chehab {
6748af16adfSMauro Carvalho Chehab dprintk("ifreq: %d %x, inversion: %d\n", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
6759a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) {
6769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23,
6779a0bf528SMauro Carvalho Chehab (u16) (((bw->internal * 1000) >> 16) & 0xffff));
6789a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24,
6799a0bf528SMauro Carvalho Chehab (u16) ((bw->internal * 1000) & 0xffff));
6809a0bf528SMauro Carvalho Chehab } else {
6819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
6829a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24,
6839a0bf528SMauro Carvalho Chehab (u16) ((bw->internal / 2 * 1000) & 0xffff));
6849a0bf528SMauro Carvalho Chehab }
6859a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
6869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
6879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
6889a0bf528SMauro Carvalho Chehab
6899a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
6909a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, bw->sad_cfg);
6919a0bf528SMauro Carvalho Chehab }
6929a0bf528SMauro Carvalho Chehab
dib8000_reset_pll(struct dib8000_state * state)6939a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state)
6949a0bf528SMauro Carvalho Chehab {
6959a0bf528SMauro Carvalho Chehab const struct dibx000_bandwidth_config *pll = state->cfg.pll;
6969a0bf528SMauro Carvalho Chehab u16 clk_cfg1, reg;
6979a0bf528SMauro Carvalho Chehab
6989a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) {
6999a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 901,
7009a0bf528SMauro Carvalho Chehab (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
7019a0bf528SMauro Carvalho Chehab
7029a0bf528SMauro Carvalho Chehab clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
7039a0bf528SMauro Carvalho Chehab (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
7049a0bf528SMauro Carvalho Chehab (1 << 3) | (pll->pll_range << 1) |
7059a0bf528SMauro Carvalho Chehab (pll->pll_reset << 0);
7069a0bf528SMauro Carvalho Chehab
7079a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1);
7089a0bf528SMauro Carvalho Chehab clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
7099a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 902, clk_cfg1);
7109a0bf528SMauro Carvalho Chehab
7118af16adfSMauro Carvalho Chehab dprintk("clk_cfg1: 0x%04x\n", clk_cfg1);
7129a0bf528SMauro Carvalho Chehab
7139a0bf528SMauro Carvalho Chehab /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
7149a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ADClkSrc == 0)
7159a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904,
7169a0bf528SMauro Carvalho Chehab (0 << 15) | (0 << 12) | (0 << 10) |
7179a0bf528SMauro Carvalho Chehab (pll->modulo << 8) |
7189a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1));
7199a0bf528SMauro Carvalho Chehab else if (state->cfg.refclksel != 0)
7209a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7219a0bf528SMauro Carvalho Chehab ((state->cfg.refclksel & 0x3) << 10) |
7229a0bf528SMauro Carvalho Chehab (pll->modulo << 8) |
7239a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1));
7249a0bf528SMauro Carvalho Chehab else
7259a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7269a0bf528SMauro Carvalho Chehab (3 << 10) | (pll->modulo << 8) |
7279a0bf528SMauro Carvalho Chehab (pll->ADClkSrc << 7) | (0 << 1));
7289a0bf528SMauro Carvalho Chehab } else {
7299a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
7309a0bf528SMauro Carvalho Chehab (pll->pll_range<<12) | (pll->pll_ratio<<6) |
7319a0bf528SMauro Carvalho Chehab (pll->pll_prediv));
7329a0bf528SMauro Carvalho Chehab
7339a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1857);
7349a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
7359a0bf528SMauro Carvalho Chehab
7369a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
7379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1858, reg | 1);
7389a0bf528SMauro Carvalho Chehab
7399a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 904, (pll->modulo << 8));
7409a0bf528SMauro Carvalho Chehab }
7419a0bf528SMauro Carvalho Chehab
7429a0bf528SMauro Carvalho Chehab dib8000_reset_pll_common(state, pll);
7439a0bf528SMauro Carvalho Chehab }
7449a0bf528SMauro Carvalho Chehab
dib8000_update_pll(struct dvb_frontend * fe,struct dibx000_bandwidth_config * pll,u32 bw,u8 ratio)745d44913c1SMauro Carvalho Chehab static int dib8000_update_pll(struct dvb_frontend *fe,
746173a64cbSPatrick Boettcher struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
7479a0bf528SMauro Carvalho Chehab {
7489a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
7499a0bf528SMauro Carvalho Chehab u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
750173a64cbSPatrick Boettcher u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
7519a0bf528SMauro Carvalho Chehab u32 internal, xtal;
7529a0bf528SMauro Carvalho Chehab
7539a0bf528SMauro Carvalho Chehab /* get back old values */
7549a0bf528SMauro Carvalho Chehab prediv = reg_1856 & 0x3f;
7559a0bf528SMauro Carvalho Chehab loopdiv = (reg_1856 >> 6) & 0x3f;
7569a0bf528SMauro Carvalho Chehab
757173a64cbSPatrick Boettcher if ((pll == NULL) || (pll->pll_prediv == prediv &&
758173a64cbSPatrick Boettcher pll->pll_ratio == loopdiv))
759173a64cbSPatrick Boettcher return -EINVAL;
760173a64cbSPatrick Boettcher
7618af16adfSMauro Carvalho Chehab dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
762173a64cbSPatrick Boettcher if (state->revision == 0x8090) {
7639a0bf528SMauro Carvalho Chehab reg_1856 &= 0xf000;
7649a0bf528SMauro Carvalho Chehab reg_1857 = dib8000_read_word(state, 1857);
7659a0bf528SMauro Carvalho Chehab /* disable PLL */
7669a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
7679a0bf528SMauro Carvalho Chehab
7689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1856, reg_1856 |
7699a0bf528SMauro Carvalho Chehab ((pll->pll_ratio & 0x3f) << 6) |
7709a0bf528SMauro Carvalho Chehab (pll->pll_prediv & 0x3f));
7719a0bf528SMauro Carvalho Chehab
7729a0bf528SMauro Carvalho Chehab /* write new system clk into P_sec_len */
7739a0bf528SMauro Carvalho Chehab internal = dib8000_read32(state, 23) / 1000;
7748af16adfSMauro Carvalho Chehab dprintk("Old Internal = %d\n", internal);
7759a0bf528SMauro Carvalho Chehab xtal = 2 * (internal / loopdiv) * prediv;
7769a0bf528SMauro Carvalho Chehab internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
7778af16adfSMauro Carvalho Chehab dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d\n", xtal, internal/1000, internal/2000, internal/8000);
7788af16adfSMauro Carvalho Chehab dprintk("New Internal = %d\n", internal);
7799a0bf528SMauro Carvalho Chehab
7809a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 23,
7819a0bf528SMauro Carvalho Chehab (u16) (((internal / 2) >> 16) & 0xffff));
7829a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
7839a0bf528SMauro Carvalho Chehab /* enable PLL */
7849a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
7859a0bf528SMauro Carvalho Chehab
7869a0bf528SMauro Carvalho Chehab while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
7878af16adfSMauro Carvalho Chehab dprintk("Waiting for PLL to lock\n");
7889a0bf528SMauro Carvalho Chehab
7899a0bf528SMauro Carvalho Chehab /* verify */
7909a0bf528SMauro Carvalho Chehab reg_1856 = dib8000_read_word(state, 1856);
7918af16adfSMauro Carvalho Chehab dprintk("PLL Updated with prediv = %d and loopdiv = %d\n",
7929a0bf528SMauro Carvalho Chehab reg_1856&0x3f, (reg_1856>>6)&0x3f);
793173a64cbSPatrick Boettcher } else {
794173a64cbSPatrick Boettcher if (bw != state->current_demod_bw) {
795173a64cbSPatrick Boettcher /** Bandwidth change => force PLL update **/
7968af16adfSMauro Carvalho Chehab dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)\n", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
797173a64cbSPatrick Boettcher
798173a64cbSPatrick Boettcher if (state->cfg.pll->pll_prediv != oldprediv) {
799173a64cbSPatrick Boettcher /** Full PLL change only if prediv is changed **/
800173a64cbSPatrick Boettcher
801173a64cbSPatrick Boettcher /** full update => bypass and reconfigure **/
8028af16adfSMauro Carvalho Chehab dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)\n", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
803173a64cbSPatrick Boettcher dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
804173a64cbSPatrick Boettcher dib8000_reset_pll(state);
805173a64cbSPatrick Boettcher dib8000_write_word(state, 898, 0x0004); /* sad */
806173a64cbSPatrick Boettcher } else
807173a64cbSPatrick Boettcher ratio = state->cfg.pll->pll_ratio;
808173a64cbSPatrick Boettcher
809173a64cbSPatrick Boettcher state->current_demod_bw = bw;
810173a64cbSPatrick Boettcher }
811173a64cbSPatrick Boettcher
812173a64cbSPatrick Boettcher if (ratio != 0) {
813173a64cbSPatrick Boettcher /** ratio update => only change ratio **/
8148af16adfSMauro Carvalho Chehab dprintk("PLL: Update ratio (prediv: %d, ratio: %d)\n", state->cfg.pll->pll_prediv, ratio);
815173a64cbSPatrick Boettcher dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
816173a64cbSPatrick Boettcher }
817173a64cbSPatrick Boettcher }
8189a0bf528SMauro Carvalho Chehab
8199a0bf528SMauro Carvalho Chehab return 0;
8209a0bf528SMauro Carvalho Chehab }
8219a0bf528SMauro Carvalho Chehab
dib8000_reset_gpio(struct dib8000_state * st)8229a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st)
8239a0bf528SMauro Carvalho Chehab {
8249a0bf528SMauro Carvalho Chehab /* reset the GPIOs */
8259a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8269a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val);
8279a0bf528SMauro Carvalho Chehab
8289a0bf528SMauro Carvalho Chehab /* TODO 782 is P_gpio_od */
8299a0bf528SMauro Carvalho Chehab
8309a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
8319a0bf528SMauro Carvalho Chehab
8329a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
8339a0bf528SMauro Carvalho Chehab return 0;
8349a0bf528SMauro Carvalho Chehab }
8359a0bf528SMauro Carvalho Chehab
dib8000_cfg_gpio(struct dib8000_state * st,u8 num,u8 dir,u8 val)8369a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
8379a0bf528SMauro Carvalho Chehab {
8389a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir = dib8000_read_word(st, 1029);
8399a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
8409a0bf528SMauro Carvalho Chehab st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
8419a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8429a0bf528SMauro Carvalho Chehab
8439a0bf528SMauro Carvalho Chehab st->cfg.gpio_val = dib8000_read_word(st, 1030);
8449a0bf528SMauro Carvalho Chehab st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
8459a0bf528SMauro Carvalho Chehab st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
8469a0bf528SMauro Carvalho Chehab dib8000_write_word(st, 1030, st->cfg.gpio_val);
8479a0bf528SMauro Carvalho Chehab
8488af16adfSMauro Carvalho Chehab dprintk("gpio dir: %x: gpio val: %x\n", st->cfg.gpio_dir, st->cfg.gpio_val);
8499a0bf528SMauro Carvalho Chehab
8509a0bf528SMauro Carvalho Chehab return 0;
8519a0bf528SMauro Carvalho Chehab }
8529a0bf528SMauro Carvalho Chehab
dib8000_set_gpio(struct dvb_frontend * fe,u8 num,u8 dir,u8 val)853d44913c1SMauro Carvalho Chehab static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
8549a0bf528SMauro Carvalho Chehab {
8559a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
8569a0bf528SMauro Carvalho Chehab return dib8000_cfg_gpio(state, num, dir, val);
8579a0bf528SMauro Carvalho Chehab }
8589a0bf528SMauro Carvalho Chehab
8599a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = {
8609a0bf528SMauro Carvalho Chehab /* auto search configuration - lock0 by default waiting
8619a0bf528SMauro Carvalho Chehab * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
8629a0bf528SMauro Carvalho Chehab 3, 7,
8639a0bf528SMauro Carvalho Chehab 0x0004,
8649a0bf528SMauro Carvalho Chehab 0x0400,
8659a0bf528SMauro Carvalho Chehab 0x0814,
8669a0bf528SMauro Carvalho Chehab
8679a0bf528SMauro Carvalho Chehab 12, 11,
8689a0bf528SMauro Carvalho Chehab 0x001b,
8699a0bf528SMauro Carvalho Chehab 0x7740,
8709a0bf528SMauro Carvalho Chehab 0x005b,
8719a0bf528SMauro Carvalho Chehab 0x8d80,
8729a0bf528SMauro Carvalho Chehab 0x01c9,
8739a0bf528SMauro Carvalho Chehab 0xc380,
8749a0bf528SMauro Carvalho Chehab 0x0000,
8759a0bf528SMauro Carvalho Chehab 0x0080,
8769a0bf528SMauro Carvalho Chehab 0x0000,
8779a0bf528SMauro Carvalho Chehab 0x0090,
8789a0bf528SMauro Carvalho Chehab 0x0001,
8799a0bf528SMauro Carvalho Chehab 0xd4c0,
8809a0bf528SMauro Carvalho Chehab
8819a0bf528SMauro Carvalho Chehab /*1, 32,
8829a0bf528SMauro Carvalho Chehab 0x6680 // P_corm_thres Lock algorithms configuration */
8839a0bf528SMauro Carvalho Chehab
8849a0bf528SMauro Carvalho Chehab 11, 80, /* set ADC level to -16 */
8859a0bf528SMauro Carvalho Chehab (1 << 13) - 825 - 117,
8869a0bf528SMauro Carvalho Chehab (1 << 13) - 837 - 117,
8879a0bf528SMauro Carvalho Chehab (1 << 13) - 811 - 117,
8889a0bf528SMauro Carvalho Chehab (1 << 13) - 766 - 117,
8899a0bf528SMauro Carvalho Chehab (1 << 13) - 737 - 117,
8909a0bf528SMauro Carvalho Chehab (1 << 13) - 693 - 117,
8919a0bf528SMauro Carvalho Chehab (1 << 13) - 648 - 117,
8929a0bf528SMauro Carvalho Chehab (1 << 13) - 619 - 117,
8939a0bf528SMauro Carvalho Chehab (1 << 13) - 575 - 117,
8949a0bf528SMauro Carvalho Chehab (1 << 13) - 531 - 117,
8959a0bf528SMauro Carvalho Chehab (1 << 13) - 501 - 117,
8969a0bf528SMauro Carvalho Chehab
8979a0bf528SMauro Carvalho Chehab 4, 108,
8989a0bf528SMauro Carvalho Chehab 0,
8999a0bf528SMauro Carvalho Chehab 0,
9009a0bf528SMauro Carvalho Chehab 0,
9019a0bf528SMauro Carvalho Chehab 0,
9029a0bf528SMauro Carvalho Chehab
9039a0bf528SMauro Carvalho Chehab 1, 175,
9049a0bf528SMauro Carvalho Chehab 0x0410,
9059a0bf528SMauro Carvalho Chehab 1, 179,
9069a0bf528SMauro Carvalho Chehab 8192, // P_fft_nb_to_cut
9079a0bf528SMauro Carvalho Chehab
9089a0bf528SMauro Carvalho Chehab 6, 181,
9099a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
9109a0bf528SMauro Carvalho Chehab 0x2800,
9119a0bf528SMauro Carvalho Chehab 0x2800,
9129a0bf528SMauro Carvalho Chehab 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
9139a0bf528SMauro Carvalho Chehab 0x2800,
9149a0bf528SMauro Carvalho Chehab 0x2800,
9159a0bf528SMauro Carvalho Chehab
9169a0bf528SMauro Carvalho Chehab 2, 193,
9179a0bf528SMauro Carvalho Chehab 0x0666, // P_pha3_thres
9189a0bf528SMauro Carvalho Chehab 0x0000, // P_cti_use_cpe, P_cti_use_prog
9199a0bf528SMauro Carvalho Chehab
9209a0bf528SMauro Carvalho Chehab 2, 205,
9219a0bf528SMauro Carvalho Chehab 0x200f, // P_cspu_regul, P_cspu_win_cut
9229a0bf528SMauro Carvalho Chehab 0x000f, // P_des_shift_work
9239a0bf528SMauro Carvalho Chehab
9249a0bf528SMauro Carvalho Chehab 5, 215,
9259a0bf528SMauro Carvalho Chehab 0x023d, // P_adp_regul_cnt
9269a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_noise_cnt
9279a0bf528SMauro Carvalho Chehab 0x00a4, // P_adp_regul_ext
9289a0bf528SMauro Carvalho Chehab 0x7ff0, // P_adp_noise_ext
9299a0bf528SMauro Carvalho Chehab 0x3ccc, // P_adp_fil
9309a0bf528SMauro Carvalho Chehab
9319a0bf528SMauro Carvalho Chehab 1, 230,
9329a0bf528SMauro Carvalho Chehab 0x0000, // P_2d_byp_ti_num
9339a0bf528SMauro Carvalho Chehab
9349a0bf528SMauro Carvalho Chehab 1, 263,
9359a0bf528SMauro Carvalho Chehab 0x800, //P_equal_thres_wgn
9369a0bf528SMauro Carvalho Chehab
9379a0bf528SMauro Carvalho Chehab 1, 268,
9389a0bf528SMauro Carvalho Chehab (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
9399a0bf528SMauro Carvalho Chehab
9409a0bf528SMauro Carvalho Chehab 1, 270,
9419a0bf528SMauro Carvalho Chehab 0x0001, // P_div_lock0_wait
9429a0bf528SMauro Carvalho Chehab 1, 285,
9439a0bf528SMauro Carvalho Chehab 0x0020, //p_fec_
9449a0bf528SMauro Carvalho Chehab 1, 299,
9459a0bf528SMauro Carvalho Chehab 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
9469a0bf528SMauro Carvalho Chehab
9479a0bf528SMauro Carvalho Chehab 1, 338,
9489a0bf528SMauro Carvalho Chehab (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
9499a0bf528SMauro Carvalho Chehab (1 << 10) |
9509a0bf528SMauro Carvalho Chehab (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
9519a0bf528SMauro Carvalho Chehab (3 << 5) | /* P_ctrl_pre_freq_step=3 */
9529a0bf528SMauro Carvalho Chehab (1 << 0), /* P_pre_freq_win_len=1 */
9539a0bf528SMauro Carvalho Chehab
9549a0bf528SMauro Carvalho Chehab 0,
9559a0bf528SMauro Carvalho Chehab };
9569a0bf528SMauro Carvalho Chehab
dib8000_identify(struct i2c_device * client)9579a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client)
9589a0bf528SMauro Carvalho Chehab {
9599a0bf528SMauro Carvalho Chehab u16 value;
9609a0bf528SMauro Carvalho Chehab
9619a0bf528SMauro Carvalho Chehab //because of glitches sometimes
9629a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 896);
9639a0bf528SMauro Carvalho Chehab
9649a0bf528SMauro Carvalho Chehab if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
9658af16adfSMauro Carvalho Chehab dprintk("wrong Vendor ID (read=0x%x)\n", value);
9669a0bf528SMauro Carvalho Chehab return 0;
9679a0bf528SMauro Carvalho Chehab }
9689a0bf528SMauro Carvalho Chehab
9699a0bf528SMauro Carvalho Chehab value = dib8000_i2c_read16(client, 897);
9709a0bf528SMauro Carvalho Chehab if (value != 0x8000 && value != 0x8001 &&
9719a0bf528SMauro Carvalho Chehab value != 0x8002 && value != 0x8090) {
9728af16adfSMauro Carvalho Chehab dprintk("wrong Device ID (%x)\n", value);
9739a0bf528SMauro Carvalho Chehab return 0;
9749a0bf528SMauro Carvalho Chehab }
9759a0bf528SMauro Carvalho Chehab
9769a0bf528SMauro Carvalho Chehab switch (value) {
9779a0bf528SMauro Carvalho Chehab case 0x8000:
9788af16adfSMauro Carvalho Chehab dprintk("found DiB8000A\n");
9799a0bf528SMauro Carvalho Chehab break;
9809a0bf528SMauro Carvalho Chehab case 0x8001:
9818af16adfSMauro Carvalho Chehab dprintk("found DiB8000B\n");
9829a0bf528SMauro Carvalho Chehab break;
9839a0bf528SMauro Carvalho Chehab case 0x8002:
9848af16adfSMauro Carvalho Chehab dprintk("found DiB8000C\n");
9859a0bf528SMauro Carvalho Chehab break;
9869a0bf528SMauro Carvalho Chehab case 0x8090:
9878af16adfSMauro Carvalho Chehab dprintk("found DiB8096P\n");
9889a0bf528SMauro Carvalho Chehab break;
9899a0bf528SMauro Carvalho Chehab }
9909a0bf528SMauro Carvalho Chehab return value;
9919a0bf528SMauro Carvalho Chehab }
9929a0bf528SMauro Carvalho Chehab
9937a9d85d5SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
9947a9d85d5SMauro Carvalho Chehab
dib8000_reset_stats(struct dvb_frontend * fe)9956ef06e78SMauro Carvalho Chehab static void dib8000_reset_stats(struct dvb_frontend *fe)
9966ef06e78SMauro Carvalho Chehab {
9976ef06e78SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
9986ef06e78SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
9997a9d85d5SMauro Carvalho Chehab u32 ucb;
10006ef06e78SMauro Carvalho Chehab
10016ef06e78SMauro Carvalho Chehab memset(&c->strength, 0, sizeof(c->strength));
10026ef06e78SMauro Carvalho Chehab memset(&c->cnr, 0, sizeof(c->cnr));
10036ef06e78SMauro Carvalho Chehab memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
10046ef06e78SMauro Carvalho Chehab memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
10056ef06e78SMauro Carvalho Chehab memset(&c->block_error, 0, sizeof(c->block_error));
10066ef06e78SMauro Carvalho Chehab
10076ef06e78SMauro Carvalho Chehab c->strength.len = 1;
10086ef06e78SMauro Carvalho Chehab c->cnr.len = 1;
10096ef06e78SMauro Carvalho Chehab c->block_error.len = 1;
10100400c535SMauro Carvalho Chehab c->block_count.len = 1;
10116ef06e78SMauro Carvalho Chehab c->post_bit_error.len = 1;
10126ef06e78SMauro Carvalho Chehab c->post_bit_count.len = 1;
10136ef06e78SMauro Carvalho Chehab
1014b4600d70SMauro Carvalho Chehab c->strength.stat[0].scale = FE_SCALE_DECIBEL;
10156ef06e78SMauro Carvalho Chehab c->strength.stat[0].uvalue = 0;
10166ef06e78SMauro Carvalho Chehab
10176ef06e78SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10186ef06e78SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10190400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10206ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10216ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10227a9d85d5SMauro Carvalho Chehab
10237a9d85d5SMauro Carvalho Chehab dib8000_read_unc_blocks(fe, &ucb);
1024704f01bbSMauro Carvalho Chehab
10257a9d85d5SMauro Carvalho Chehab state->init_ucb = -ucb;
10260400c535SMauro Carvalho Chehab state->ber_jiffies_stats = 0;
10270400c535SMauro Carvalho Chehab state->per_jiffies_stats = 0;
10280400c535SMauro Carvalho Chehab memset(&state->ber_jiffies_stats_layer, 0,
10290400c535SMauro Carvalho Chehab sizeof(state->ber_jiffies_stats_layer));
10306ef06e78SMauro Carvalho Chehab }
10316ef06e78SMauro Carvalho Chehab
dib8000_reset(struct dvb_frontend * fe)10329a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe)
10339a0bf528SMauro Carvalho Chehab {
10349a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
10359a0bf528SMauro Carvalho Chehab
10369a0bf528SMauro Carvalho Chehab if ((state->revision = dib8000_identify(&state->i2c)) == 0)
10379a0bf528SMauro Carvalho Chehab return -EINVAL;
10389a0bf528SMauro Carvalho Chehab
10399a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */
10409a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
10419a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, 0x0003);
10429a0bf528SMauro Carvalho Chehab
10439a0bf528SMauro Carvalho Chehab if (state->revision == 0x8000)
10448af16adfSMauro Carvalho Chehab dprintk("error : dib8000 MA not supported\n");
10459a0bf528SMauro Carvalho Chehab
10469a0bf528SMauro Carvalho Chehab dibx000_reset_i2c_master(&state->i2c_master);
10479a0bf528SMauro Carvalho Chehab
10489a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL);
10499a0bf528SMauro Carvalho Chehab
10509a0bf528SMauro Carvalho Chehab /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
1051173a64cbSPatrick Boettcher dib8000_set_adc_state(state, DIBX000_ADC_OFF);
10529a0bf528SMauro Carvalho Chehab
10539a0bf528SMauro Carvalho Chehab /* restart all parts */
10549a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0xffff);
10559a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0xffff);
10569a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0xfffc);
10576d38454aSMauro Carvalho Chehab dib8000_write_word(state, 898, 0x000c); /* restart sad */
10589a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090)
10599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0045);
10609a0bf528SMauro Carvalho Chehab else
10619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x004d);
10629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x000c);
10639a0bf528SMauro Carvalho Chehab
10649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000);
10659a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 771, 0x0000);
10669a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 772, 0x0000);
10679a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004); // sad
10689a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1280, 0x0000);
10699a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1281, 0x0000);
10709a0bf528SMauro Carvalho Chehab
10719a0bf528SMauro Carvalho Chehab /* drives */
10729a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090) {
10739a0bf528SMauro Carvalho Chehab if (state->cfg.drives)
10749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, state->cfg.drives);
10759a0bf528SMauro Carvalho Chehab else {
10768af16adfSMauro Carvalho Chehab dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.\n");
10779a0bf528SMauro Carvalho Chehab /* min drive SDRAM - not optimal - adjust */
10789a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 906, 0x2d98);
10799a0bf528SMauro Carvalho Chehab }
10809a0bf528SMauro Carvalho Chehab }
10819a0bf528SMauro Carvalho Chehab
10829a0bf528SMauro Carvalho Chehab dib8000_reset_pll(state);
10839a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
10849a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 898, 0x0004);
10859a0bf528SMauro Carvalho Chehab
10869a0bf528SMauro Carvalho Chehab if (dib8000_reset_gpio(state) != 0)
10878af16adfSMauro Carvalho Chehab dprintk("GPIO reset was not successful.\n");
10889a0bf528SMauro Carvalho Chehab
10899a0bf528SMauro Carvalho Chehab if ((state->revision != 0x8090) &&
10909a0bf528SMauro Carvalho Chehab (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
1091868c9a17SMauro Carvalho Chehab dprintk("OUTPUT_MODE could not be reset.\n");
10929a0bf528SMauro Carvalho Chehab
10939a0bf528SMauro Carvalho Chehab state->current_agc = NULL;
10949a0bf528SMauro Carvalho Chehab
10959a0bf528SMauro Carvalho Chehab // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
10969a0bf528SMauro Carvalho Chehab /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
10979a0bf528SMauro Carvalho Chehab if (state->cfg.pll->ifreq == 0)
10989a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
10999a0bf528SMauro Carvalho Chehab else
11009a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
11019a0bf528SMauro Carvalho Chehab
11029a0bf528SMauro Carvalho Chehab {
11039a0bf528SMauro Carvalho Chehab u16 l = 0, r;
11049a0bf528SMauro Carvalho Chehab const u16 *n;
11059a0bf528SMauro Carvalho Chehab n = dib8000_defaults;
11069a0bf528SMauro Carvalho Chehab l = *n++;
11079a0bf528SMauro Carvalho Chehab while (l) {
11089a0bf528SMauro Carvalho Chehab r = *n++;
11099a0bf528SMauro Carvalho Chehab do {
11109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, r, *n++);
11119a0bf528SMauro Carvalho Chehab r++;
11129a0bf528SMauro Carvalho Chehab } while (--l);
11139a0bf528SMauro Carvalho Chehab l = *n++;
11149a0bf528SMauro Carvalho Chehab }
11159a0bf528SMauro Carvalho Chehab }
1116173a64cbSPatrick Boettcher
11179a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0;
11189a0bf528SMauro Carvalho Chehab
11199a0bf528SMauro Carvalho Chehab //div_cfg override for special configs
1120173a64cbSPatrick Boettcher if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
11219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 903, state->cfg.div_cfg);
11229a0bf528SMauro Carvalho Chehab
11239a0bf528SMauro Carvalho Chehab /* unforce divstr regardless whether i2c enumeration was done or not */
11249a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
11259a0bf528SMauro Carvalho Chehab
11269a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(fe, 6000);
11279a0bf528SMauro Carvalho Chehab
11289a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
11299a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state);
1130173a64cbSPatrick Boettcher if (state->revision != 0x8090)
11319a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1132173a64cbSPatrick Boettcher
1133173a64cbSPatrick Boettcher /* ber_rs_len = 3 */
1134173a64cbSPatrick Boettcher dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
11359a0bf528SMauro Carvalho Chehab
11369a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
11379a0bf528SMauro Carvalho Chehab
11386ef06e78SMauro Carvalho Chehab dib8000_reset_stats(fe);
11396ef06e78SMauro Carvalho Chehab
11409a0bf528SMauro Carvalho Chehab return 0;
11419a0bf528SMauro Carvalho Chehab }
11429a0bf528SMauro Carvalho Chehab
dib8000_restart_agc(struct dib8000_state * state)11439a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state)
11449a0bf528SMauro Carvalho Chehab {
11459a0bf528SMauro Carvalho Chehab // P_restart_iqc & P_restart_agc
11469a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0a00);
11479a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 770, 0x0000);
11489a0bf528SMauro Carvalho Chehab }
11499a0bf528SMauro Carvalho Chehab
dib8000_update_lna(struct dib8000_state * state)11509a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state)
11519a0bf528SMauro Carvalho Chehab {
11529a0bf528SMauro Carvalho Chehab u16 dyn_gain;
11539a0bf528SMauro Carvalho Chehab
11549a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna) {
11559a0bf528SMauro Carvalho Chehab // read dyn_gain here (because it is demod-dependent and not tuner)
11569a0bf528SMauro Carvalho Chehab dyn_gain = dib8000_read_word(state, 390);
11579a0bf528SMauro Carvalho Chehab
11589a0bf528SMauro Carvalho Chehab if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
11599a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state);
11609a0bf528SMauro Carvalho Chehab return 1;
11619a0bf528SMauro Carvalho Chehab }
11629a0bf528SMauro Carvalho Chehab }
11639a0bf528SMauro Carvalho Chehab return 0;
11649a0bf528SMauro Carvalho Chehab }
11659a0bf528SMauro Carvalho Chehab
dib8000_set_agc_config(struct dib8000_state * state,u8 band)11669a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
11679a0bf528SMauro Carvalho Chehab {
11689a0bf528SMauro Carvalho Chehab struct dibx000_agc_config *agc = NULL;
11699a0bf528SMauro Carvalho Chehab int i;
11709a0bf528SMauro Carvalho Chehab u16 reg;
11719a0bf528SMauro Carvalho Chehab
11729a0bf528SMauro Carvalho Chehab if (state->current_band == band && state->current_agc != NULL)
11739a0bf528SMauro Carvalho Chehab return 0;
11749a0bf528SMauro Carvalho Chehab state->current_band = band;
11759a0bf528SMauro Carvalho Chehab
11769a0bf528SMauro Carvalho Chehab for (i = 0; i < state->cfg.agc_config_count; i++)
11779a0bf528SMauro Carvalho Chehab if (state->cfg.agc[i].band_caps & band) {
11789a0bf528SMauro Carvalho Chehab agc = &state->cfg.agc[i];
11799a0bf528SMauro Carvalho Chehab break;
11809a0bf528SMauro Carvalho Chehab }
11819a0bf528SMauro Carvalho Chehab
11829a0bf528SMauro Carvalho Chehab if (agc == NULL) {
11838af16adfSMauro Carvalho Chehab dprintk("no valid AGC configuration found for band 0x%02x\n", band);
11849a0bf528SMauro Carvalho Chehab return -EINVAL;
11859a0bf528SMauro Carvalho Chehab }
11869a0bf528SMauro Carvalho Chehab
11879a0bf528SMauro Carvalho Chehab state->current_agc = agc;
11889a0bf528SMauro Carvalho Chehab
11899a0bf528SMauro Carvalho Chehab /* AGC */
11909a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 76, agc->setup);
11919a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 77, agc->inv_gain);
11929a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 78, agc->time_stabiliz);
11939a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
11949a0bf528SMauro Carvalho Chehab
11959a0bf528SMauro Carvalho Chehab // Demod AGC loop configuration
11969a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
11979a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
11989a0bf528SMauro Carvalho Chehab
11998af16adfSMauro Carvalho Chehab dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
12009a0bf528SMauro Carvalho Chehab state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
12019a0bf528SMauro Carvalho Chehab
12029a0bf528SMauro Carvalho Chehab /* AGC continued */
12039a0bf528SMauro Carvalho Chehab if (state->wbd_ref != 0)
12049a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, state->wbd_ref);
12059a0bf528SMauro Carvalho Chehab else // use default
12069a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 106, agc->wbd_ref);
12079a0bf528SMauro Carvalho Chehab
12089a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090) {
12099a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 922) & (0x3 << 2);
12109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
12119a0bf528SMauro Carvalho Chehab }
12129a0bf528SMauro Carvalho Chehab
12139a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
12149a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 108, agc->agc1_max);
12159a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 109, agc->agc1_min);
12169a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 110, agc->agc2_max);
12179a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 111, agc->agc2_min);
12189a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
12199a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
12209a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
12219a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
12229a0bf528SMauro Carvalho Chehab
12239a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 75, agc->agc1_pt3);
12249a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
12259a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 923,
12269a0bf528SMauro Carvalho Chehab (dib8000_read_word(state, 923) & 0xffe3) |
12279a0bf528SMauro Carvalho Chehab (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
12289a0bf528SMauro Carvalho Chehab
12299a0bf528SMauro Carvalho Chehab return 0;
12309a0bf528SMauro Carvalho Chehab }
12319a0bf528SMauro Carvalho Chehab
dib8000_pwm_agc_reset(struct dvb_frontend * fe)1232d44913c1SMauro Carvalho Chehab static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
12339a0bf528SMauro Carvalho Chehab {
12349a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
12359a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON);
12369a0bf528SMauro Carvalho Chehab dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
12379a0bf528SMauro Carvalho Chehab }
12389a0bf528SMauro Carvalho Chehab
dib8000_agc_soft_split(struct dib8000_state * state)12399a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state)
12409a0bf528SMauro Carvalho Chehab {
12419a0bf528SMauro Carvalho Chehab u16 agc, split_offset;
12429a0bf528SMauro Carvalho Chehab
12439a0bf528SMauro Carvalho Chehab if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
1244d6c62b76SMauro Carvalho Chehab return 0;
12459a0bf528SMauro Carvalho Chehab
12469a0bf528SMauro Carvalho Chehab // n_agc_global
12479a0bf528SMauro Carvalho Chehab agc = dib8000_read_word(state, 390);
12489a0bf528SMauro Carvalho Chehab
12499a0bf528SMauro Carvalho Chehab if (agc > state->current_agc->split.min_thres)
12509a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.min;
12519a0bf528SMauro Carvalho Chehab else if (agc < state->current_agc->split.max_thres)
12529a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max;
12539a0bf528SMauro Carvalho Chehab else
12549a0bf528SMauro Carvalho Chehab split_offset = state->current_agc->split.max *
12559a0bf528SMauro Carvalho Chehab (agc - state->current_agc->split.min_thres) /
12569a0bf528SMauro Carvalho Chehab (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
12579a0bf528SMauro Carvalho Chehab
12588af16adfSMauro Carvalho Chehab dprintk("AGC split_offset: %d\n", split_offset);
12599a0bf528SMauro Carvalho Chehab
12609a0bf528SMauro Carvalho Chehab // P_agc_force_split and P_agc_split_offset
12619a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
12629a0bf528SMauro Carvalho Chehab return 5000;
12639a0bf528SMauro Carvalho Chehab }
12649a0bf528SMauro Carvalho Chehab
dib8000_agc_startup(struct dvb_frontend * fe)12659a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe)
12669a0bf528SMauro Carvalho Chehab {
12679a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
12689a0bf528SMauro Carvalho Chehab enum frontend_tune_state *tune_state = &state->tune_state;
12699a0bf528SMauro Carvalho Chehab int ret = 0;
1270901c4ad6SMauro Carvalho Chehab u16 reg;
1271901c4ad6SMauro Carvalho Chehab u32 upd_demod_gain_period = 0x8000;
12729a0bf528SMauro Carvalho Chehab
12739a0bf528SMauro Carvalho Chehab switch (*tune_state) {
12749a0bf528SMauro Carvalho Chehab case CT_AGC_START:
12759a0bf528SMauro Carvalho Chehab // set power-up level: interf+analog+AGC
12769a0bf528SMauro Carvalho Chehab
12779a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
12789a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON);
12799a0bf528SMauro Carvalho Chehab else {
12809a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL);
12819a0bf528SMauro Carvalho Chehab
12829a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1947)&0xff00;
12839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1946,
12849a0bf528SMauro Carvalho Chehab upd_demod_gain_period & 0xFFFF);
12859a0bf528SMauro Carvalho Chehab /* bit 14 = enDemodGain */
12869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1947, reg | (1<<14) |
12879a0bf528SMauro Carvalho Chehab ((upd_demod_gain_period >> 16) & 0xFF));
12889a0bf528SMauro Carvalho Chehab
12899a0bf528SMauro Carvalho Chehab /* enable adc i & q */
12909a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1920);
12919a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1920, (reg | 0x3) &
12929a0bf528SMauro Carvalho Chehab (~(1 << 7)));
12939a0bf528SMauro Carvalho Chehab }
12949a0bf528SMauro Carvalho Chehab
12959a0bf528SMauro Carvalho Chehab if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
12969a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP;
12979a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_TUNE_FAILED;
12989a0bf528SMauro Carvalho Chehab break;
12999a0bf528SMauro Carvalho Chehab }
13009a0bf528SMauro Carvalho Chehab
13019a0bf528SMauro Carvalho Chehab ret = 70;
13029a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_0;
13039a0bf528SMauro Carvalho Chehab break;
13049a0bf528SMauro Carvalho Chehab
13059a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_0:
13069a0bf528SMauro Carvalho Chehab //AGC initialization
13079a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control)
13089a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 1);
13099a0bf528SMauro Carvalho Chehab
13109a0bf528SMauro Carvalho Chehab dib8000_restart_agc(state);
13119a0bf528SMauro Carvalho Chehab
13129a0bf528SMauro Carvalho Chehab // wait AGC rough lock time
13139a0bf528SMauro Carvalho Chehab ret = 50;
13149a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_1;
13159a0bf528SMauro Carvalho Chehab break;
13169a0bf528SMauro Carvalho Chehab
13179a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_1:
13189a0bf528SMauro Carvalho Chehab // wait AGC accurate lock time
13199a0bf528SMauro Carvalho Chehab ret = 70;
13209a0bf528SMauro Carvalho Chehab
13219a0bf528SMauro Carvalho Chehab if (dib8000_update_lna(state))
13229a0bf528SMauro Carvalho Chehab // wait only AGC rough lock time
13239a0bf528SMauro Carvalho Chehab ret = 50;
13249a0bf528SMauro Carvalho Chehab else
13259a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STEP_2;
13269a0bf528SMauro Carvalho Chehab break;
13279a0bf528SMauro Carvalho Chehab
13289a0bf528SMauro Carvalho Chehab case CT_AGC_STEP_2:
13299a0bf528SMauro Carvalho Chehab dib8000_agc_soft_split(state);
13309a0bf528SMauro Carvalho Chehab
13319a0bf528SMauro Carvalho Chehab if (state->cfg.agc_control)
13329a0bf528SMauro Carvalho Chehab state->cfg.agc_control(fe, 0);
13339a0bf528SMauro Carvalho Chehab
13349a0bf528SMauro Carvalho Chehab *tune_state = CT_AGC_STOP;
13359a0bf528SMauro Carvalho Chehab break;
13369a0bf528SMauro Carvalho Chehab default:
13379a0bf528SMauro Carvalho Chehab ret = dib8000_agc_soft_split(state);
13389a0bf528SMauro Carvalho Chehab break;
13399a0bf528SMauro Carvalho Chehab }
13409a0bf528SMauro Carvalho Chehab return ret;
13419a0bf528SMauro Carvalho Chehab
13429a0bf528SMauro Carvalho Chehab }
13439a0bf528SMauro Carvalho Chehab
dib8096p_host_bus_drive(struct dib8000_state * state,u8 drive)13449a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
13459a0bf528SMauro Carvalho Chehab {
13469a0bf528SMauro Carvalho Chehab u16 reg;
13479a0bf528SMauro Carvalho Chehab
13489a0bf528SMauro Carvalho Chehab drive &= 0x7;
13499a0bf528SMauro Carvalho Chehab
13509a0bf528SMauro Carvalho Chehab /* drive host bus 2, 3, 4 */
13519a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1798) &
13529a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12));
13539a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive;
13549a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1798, reg);
13559a0bf528SMauro Carvalho Chehab
13569a0bf528SMauro Carvalho Chehab /* drive host bus 5,6 */
13579a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
13589a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2);
13599a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1799, reg);
13609a0bf528SMauro Carvalho Chehab
13619a0bf528SMauro Carvalho Chehab /* drive host bus 7, 8, 9 */
13629a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1800) &
13639a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12));
13649a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive;
13659a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1800, reg);
13669a0bf528SMauro Carvalho Chehab
13679a0bf528SMauro Carvalho Chehab /* drive host bus 10, 11 */
13689a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
13699a0bf528SMauro Carvalho Chehab reg |= (drive<<8) | (drive<<2);
13709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1801, reg);
13719a0bf528SMauro Carvalho Chehab
13729a0bf528SMauro Carvalho Chehab /* drive host bus 12, 13, 14 */
13739a0bf528SMauro Carvalho Chehab reg = dib8000_read_word(state, 1802) &
13749a0bf528SMauro Carvalho Chehab ~(0x7 | (0x7 << 6) | (0x7 << 12));
13759a0bf528SMauro Carvalho Chehab reg |= (drive<<12) | (drive<<6) | drive;
13769a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1802, reg);
13779a0bf528SMauro Carvalho Chehab }
13789a0bf528SMauro Carvalho Chehab
dib8096p_calcSyncFreq(u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 syncSize)13799a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
13809a0bf528SMauro Carvalho Chehab u32 insertExtSynchro, u32 syncSize)
13819a0bf528SMauro Carvalho Chehab {
13829a0bf528SMauro Carvalho Chehab u32 quantif = 3;
13839a0bf528SMauro Carvalho Chehab u32 nom = (insertExtSynchro * P_Kin+syncSize);
13849a0bf528SMauro Carvalho Chehab u32 denom = P_Kout;
13859a0bf528SMauro Carvalho Chehab u32 syncFreq = ((nom << quantif) / denom);
13869a0bf528SMauro Carvalho Chehab
13879a0bf528SMauro Carvalho Chehab if ((syncFreq & ((1 << quantif) - 1)) != 0)
13889a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif) + 1;
13899a0bf528SMauro Carvalho Chehab else
13909a0bf528SMauro Carvalho Chehab syncFreq = (syncFreq >> quantif);
13919a0bf528SMauro Carvalho Chehab
13929a0bf528SMauro Carvalho Chehab if (syncFreq != 0)
13939a0bf528SMauro Carvalho Chehab syncFreq = syncFreq - 1;
13949a0bf528SMauro Carvalho Chehab
13959a0bf528SMauro Carvalho Chehab return syncFreq;
13969a0bf528SMauro Carvalho Chehab }
13979a0bf528SMauro Carvalho Chehab
dib8096p_cfg_DibTx(struct dib8000_state * state,u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 synchroMode,u32 syncWord,u32 syncSize)13989a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
13999a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
14009a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize)
14019a0bf528SMauro Carvalho Chehab {
14028af16adfSMauro Carvalho Chehab dprintk("Configure DibStream Tx\n");
14039a0bf528SMauro Carvalho Chehab
14049a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 1);
14059a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1603, P_Kin);
14069a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1605, P_Kout);
14079a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1606, insertExtSynchro);
14089a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1608, synchroMode);
14099a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
14109a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1610, syncWord & 0xffff);
14119a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1612, syncSize);
14129a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1615, 0);
14139a0bf528SMauro Carvalho Chehab }
14149a0bf528SMauro Carvalho Chehab
dib8096p_cfg_DibRx(struct dib8000_state * state,u32 P_Kin,u32 P_Kout,u32 synchroMode,u32 insertExtSynchro,u32 syncWord,u32 syncSize,u32 dataOutRate)14159a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
14169a0bf528SMauro Carvalho Chehab u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
14179a0bf528SMauro Carvalho Chehab u32 syncWord, u32 syncSize, u32 dataOutRate)
14189a0bf528SMauro Carvalho Chehab {
14199a0bf528SMauro Carvalho Chehab u32 syncFreq;
14209a0bf528SMauro Carvalho Chehab
14218af16adfSMauro Carvalho Chehab dprintk("Configure DibStream Rx synchroMode = %d\n", synchroMode);
14229a0bf528SMauro Carvalho Chehab
14239a0bf528SMauro Carvalho Chehab if ((P_Kin != 0) && (P_Kout != 0)) {
14249a0bf528SMauro Carvalho Chehab syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
14259a0bf528SMauro Carvalho Chehab insertExtSynchro, syncSize);
14269a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1542, syncFreq);
14279a0bf528SMauro Carvalho Chehab }
14289a0bf528SMauro Carvalho Chehab
14299a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 1);
14309a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1536, P_Kin);
14319a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1537, P_Kout);
14329a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1539, synchroMode);
14339a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
14349a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1541, syncWord & 0xffff);
14359a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1543, syncSize);
14369a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1544, dataOutRate);
14379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1554, 0);
14389a0bf528SMauro Carvalho Chehab }
14399a0bf528SMauro Carvalho Chehab
dib8096p_enMpegMux(struct dib8000_state * state,int onoff)14409a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
14419a0bf528SMauro Carvalho Chehab {
14429a0bf528SMauro Carvalho Chehab u16 reg_1287;
14439a0bf528SMauro Carvalho Chehab
14449a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287);
14459a0bf528SMauro Carvalho Chehab
14469a0bf528SMauro Carvalho Chehab switch (onoff) {
14479a0bf528SMauro Carvalho Chehab case 1:
14489a0bf528SMauro Carvalho Chehab reg_1287 &= ~(1 << 8);
14499a0bf528SMauro Carvalho Chehab break;
14509a0bf528SMauro Carvalho Chehab case 0:
14519a0bf528SMauro Carvalho Chehab reg_1287 |= (1 << 8);
14529a0bf528SMauro Carvalho Chehab break;
14539a0bf528SMauro Carvalho Chehab }
14549a0bf528SMauro Carvalho Chehab
14559a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287);
14569a0bf528SMauro Carvalho Chehab }
14579a0bf528SMauro Carvalho Chehab
dib8096p_configMpegMux(struct dib8000_state * state,u16 pulseWidth,u16 enSerialMode,u16 enSerialClkDiv2)14589a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state,
14599a0bf528SMauro Carvalho Chehab u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
14609a0bf528SMauro Carvalho Chehab {
14619a0bf528SMauro Carvalho Chehab u16 reg_1287;
14629a0bf528SMauro Carvalho Chehab
14638af16adfSMauro Carvalho Chehab dprintk("Enable Mpeg mux\n");
14649a0bf528SMauro Carvalho Chehab
14659a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0);
14669a0bf528SMauro Carvalho Chehab
14679a0bf528SMauro Carvalho Chehab /* If the input mode is MPEG do not divide the serial clock */
14689a0bf528SMauro Carvalho Chehab if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
14699a0bf528SMauro Carvalho Chehab enSerialClkDiv2 = 0;
14709a0bf528SMauro Carvalho Chehab
14719a0bf528SMauro Carvalho Chehab reg_1287 = ((pulseWidth & 0x1f) << 3) |
14729a0bf528SMauro Carvalho Chehab ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
14739a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287);
14749a0bf528SMauro Carvalho Chehab
14759a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 1);
14769a0bf528SMauro Carvalho Chehab }
14779a0bf528SMauro Carvalho Chehab
dib8096p_setDibTxMux(struct dib8000_state * state,int mode)14789a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
14799a0bf528SMauro Carvalho Chehab {
14809a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
14819a0bf528SMauro Carvalho Chehab
14829a0bf528SMauro Carvalho Chehab switch (mode) {
14839a0bf528SMauro Carvalho Chehab case MPEG_ON_DIBTX:
14848af16adfSMauro Carvalho Chehab dprintk("SET MPEG ON DIBSTREAM TX\n");
14859a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
14869a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 9); break;
14879a0bf528SMauro Carvalho Chehab case DIV_ON_DIBTX:
14888af16adfSMauro Carvalho Chehab dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
14899a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
14909a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 8); break;
14919a0bf528SMauro Carvalho Chehab case ADC_ON_DIBTX:
14928af16adfSMauro Carvalho Chehab dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
14939a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
14949a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 7); break;
14959a0bf528SMauro Carvalho Chehab default:
14969a0bf528SMauro Carvalho Chehab break;
14979a0bf528SMauro Carvalho Chehab }
14989a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288);
14999a0bf528SMauro Carvalho Chehab }
15009a0bf528SMauro Carvalho Chehab
dib8096p_setHostBusMux(struct dib8000_state * state,int mode)15019a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
15029a0bf528SMauro Carvalho Chehab {
15039a0bf528SMauro Carvalho Chehab u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
15049a0bf528SMauro Carvalho Chehab
15059a0bf528SMauro Carvalho Chehab switch (mode) {
15069a0bf528SMauro Carvalho Chehab case DEMOUT_ON_HOSTBUS:
15078af16adfSMauro Carvalho Chehab dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
15089a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0);
15099a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 6);
15109a0bf528SMauro Carvalho Chehab break;
15119a0bf528SMauro Carvalho Chehab case DIBTX_ON_HOSTBUS:
15128af16adfSMauro Carvalho Chehab dprintk("SET DIBSTREAM TX ON HOST BUS\n");
15139a0bf528SMauro Carvalho Chehab dib8096p_enMpegMux(state, 0);
15149a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 5);
15159a0bf528SMauro Carvalho Chehab break;
15169a0bf528SMauro Carvalho Chehab case MPEG_ON_HOSTBUS:
15178af16adfSMauro Carvalho Chehab dprintk("SET MPEG MUX ON HOST BUS\n");
15189a0bf528SMauro Carvalho Chehab reg_1288 |= (1 << 4);
15199a0bf528SMauro Carvalho Chehab break;
15209a0bf528SMauro Carvalho Chehab default:
15219a0bf528SMauro Carvalho Chehab break;
15229a0bf528SMauro Carvalho Chehab }
15239a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1288, reg_1288);
15249a0bf528SMauro Carvalho Chehab }
15259a0bf528SMauro Carvalho Chehab
dib8096p_set_diversity_in(struct dvb_frontend * fe,int onoff)15269a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
15279a0bf528SMauro Carvalho Chehab {
15289a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
15299a0bf528SMauro Carvalho Chehab u16 reg_1287;
15309a0bf528SMauro Carvalho Chehab
15319a0bf528SMauro Carvalho Chehab switch (onoff) {
15329a0bf528SMauro Carvalho Chehab case 0: /* only use the internal way - not the diversity input */
15338af16adfSMauro Carvalho Chehab dprintk("%s mode OFF : by default Enable Mpeg INPUT\n",
15349a0bf528SMauro Carvalho Chehab __func__);
15359a0bf528SMauro Carvalho Chehab /* outputRate = 8 */
15369a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
15379a0bf528SMauro Carvalho Chehab
15389a0bf528SMauro Carvalho Chehab /* Do not divide the serial clock of MPEG MUX in
15399a0bf528SMauro Carvalho Chehab SERIAL MODE in case input mode MPEG is used */
15409a0bf528SMauro Carvalho Chehab reg_1287 = dib8000_read_word(state, 1287);
15419a0bf528SMauro Carvalho Chehab /* enSerialClkDiv2 == 1 ? */
15429a0bf528SMauro Carvalho Chehab if ((reg_1287 & 0x1) == 1) {
15439a0bf528SMauro Carvalho Chehab /* force enSerialClkDiv2 = 0 */
15449a0bf528SMauro Carvalho Chehab reg_1287 &= ~0x1;
15459a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1287, reg_1287);
15469a0bf528SMauro Carvalho Chehab }
15479a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 1;
15489a0bf528SMauro Carvalho Chehab break;
15499a0bf528SMauro Carvalho Chehab case 1: /* both ways */
15509a0bf528SMauro Carvalho Chehab case 2: /* only the diversity input */
15518af16adfSMauro Carvalho Chehab dprintk("%s ON : Enable diversity INPUT\n", __func__);
15529a0bf528SMauro Carvalho Chehab dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
15539a0bf528SMauro Carvalho Chehab state->input_mode_mpeg = 0;
15549a0bf528SMauro Carvalho Chehab break;
15559a0bf528SMauro Carvalho Chehab }
15569a0bf528SMauro Carvalho Chehab
15579a0bf528SMauro Carvalho Chehab dib8000_set_diversity_in(state->fe[0], onoff);
15589a0bf528SMauro Carvalho Chehab return 0;
15599a0bf528SMauro Carvalho Chehab }
15609a0bf528SMauro Carvalho Chehab
dib8096p_set_output_mode(struct dvb_frontend * fe,int mode)15619a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
15629a0bf528SMauro Carvalho Chehab {
15639a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
15649a0bf528SMauro Carvalho Chehab u16 outreg, smo_mode, fifo_threshold;
15659a0bf528SMauro Carvalho Chehab u8 prefer_mpeg_mux_use = 1;
15669a0bf528SMauro Carvalho Chehab int ret = 0;
15679a0bf528SMauro Carvalho Chehab
1568173a64cbSPatrick Boettcher state->output_mode = mode;
15699a0bf528SMauro Carvalho Chehab dib8096p_host_bus_drive(state, 1);
15709a0bf528SMauro Carvalho Chehab
15719a0bf528SMauro Carvalho Chehab fifo_threshold = 1792;
15729a0bf528SMauro Carvalho Chehab smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
15739a0bf528SMauro Carvalho Chehab outreg = dib8000_read_word(state, 1286) &
15749a0bf528SMauro Carvalho Chehab ~((1 << 10) | (0x7 << 6) | (1 << 1));
15759a0bf528SMauro Carvalho Chehab
15769a0bf528SMauro Carvalho Chehab switch (mode) {
15779a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z:
15789a0bf528SMauro Carvalho Chehab outreg = 0;
15799a0bf528SMauro Carvalho Chehab break;
15809a0bf528SMauro Carvalho Chehab
15819a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL:
15829a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) {
15838af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux\n");
15849a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 3, 1, 1);
15859a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15869a0bf528SMauro Carvalho Chehab } else {/* Use Smooth block */
15878af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc\n");
15889a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state,
15899a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS);
15909a0bf528SMauro Carvalho Chehab outreg |= (2 << 6) | (0 << 1);
15919a0bf528SMauro Carvalho Chehab }
15929a0bf528SMauro Carvalho Chehab break;
15939a0bf528SMauro Carvalho Chehab
15949a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK:
15959a0bf528SMauro Carvalho Chehab if (prefer_mpeg_mux_use) {
15968af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
15979a0bf528SMauro Carvalho Chehab dib8096p_configMpegMux(state, 2, 0, 0);
15989a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15999a0bf528SMauro Carvalho Chehab } else { /* Use Smooth block */
16008af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block\n");
16019a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state,
16029a0bf528SMauro Carvalho Chehab DEMOUT_ON_HOSTBUS);
16039a0bf528SMauro Carvalho Chehab outreg |= (0 << 6);
16049a0bf528SMauro Carvalho Chehab }
16059a0bf528SMauro Carvalho Chehab break;
16069a0bf528SMauro Carvalho Chehab
16079a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
16088af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block\n");
16099a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16109a0bf528SMauro Carvalho Chehab outreg |= (1 << 6);
16119a0bf528SMauro Carvalho Chehab break;
16129a0bf528SMauro Carvalho Chehab
16139a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO:
16149a0bf528SMauro Carvalho Chehab /* Using Smooth block because not supported
16159a0bf528SMauro Carvalho Chehab by new Mpeg Mux bloc */
16168af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode TS_FIFO using Smooth block\n");
16179a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16189a0bf528SMauro Carvalho Chehab outreg |= (5 << 6);
16199a0bf528SMauro Carvalho Chehab smo_mode |= (3 << 1);
16209a0bf528SMauro Carvalho Chehab fifo_threshold = 512;
16219a0bf528SMauro Carvalho Chehab break;
16229a0bf528SMauro Carvalho Chehab
16239a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY:
16248af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_DIVERSITY\n");
16259a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
16269a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16279a0bf528SMauro Carvalho Chehab break;
16289a0bf528SMauro Carvalho Chehab
16299a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC:
16308af16adfSMauro Carvalho Chehab dprintk("dib8096P setting output mode MODE_ANALOG_ADC\n");
16319a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
16329a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16339a0bf528SMauro Carvalho Chehab break;
16349a0bf528SMauro Carvalho Chehab }
16359a0bf528SMauro Carvalho Chehab
16369a0bf528SMauro Carvalho Chehab if (mode != OUTMODE_HIGH_Z)
16379a0bf528SMauro Carvalho Chehab outreg |= (1<<10);
16389a0bf528SMauro Carvalho Chehab
16398af16adfSMauro Carvalho Chehab dprintk("output_mpeg2_in_188_bytes = %d\n",
16409a0bf528SMauro Carvalho Chehab state->cfg.output_mpeg2_in_188_bytes);
16419a0bf528SMauro Carvalho Chehab if (state->cfg.output_mpeg2_in_188_bytes)
16429a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5);
16439a0bf528SMauro Carvalho Chehab
16449a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299, smo_mode);
16459a0bf528SMauro Carvalho Chehab /* synchronous fread */
16469a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
16479a0bf528SMauro Carvalho Chehab ret |= dib8000_write_word(state, 1286, outreg);
16489a0bf528SMauro Carvalho Chehab
16499a0bf528SMauro Carvalho Chehab return ret;
16509a0bf528SMauro Carvalho Chehab }
16519a0bf528SMauro Carvalho Chehab
map_addr_to_serpar_number(struct i2c_msg * msg)16529a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
16539a0bf528SMauro Carvalho Chehab {
16549a0bf528SMauro Carvalho Chehab if (msg->buf[0] <= 15)
16559a0bf528SMauro Carvalho Chehab msg->buf[0] -= 1;
16569a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 17)
16579a0bf528SMauro Carvalho Chehab msg->buf[0] = 15;
16589a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 16)
16599a0bf528SMauro Carvalho Chehab msg->buf[0] = 17;
16609a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 19)
16619a0bf528SMauro Carvalho Chehab msg->buf[0] = 16;
16629a0bf528SMauro Carvalho Chehab else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
16639a0bf528SMauro Carvalho Chehab msg->buf[0] -= 3;
16649a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 28)
16659a0bf528SMauro Carvalho Chehab msg->buf[0] = 23;
16669a0bf528SMauro Carvalho Chehab else if (msg->buf[0] == 99)
16679a0bf528SMauro Carvalho Chehab msg->buf[0] = 99;
16689a0bf528SMauro Carvalho Chehab else
16699a0bf528SMauro Carvalho Chehab return -EINVAL;
16709a0bf528SMauro Carvalho Chehab return 0;
16719a0bf528SMauro Carvalho Chehab }
16729a0bf528SMauro Carvalho Chehab
dib8096p_tuner_write_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)16739a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
16749a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num)
16759a0bf528SMauro Carvalho Chehab {
16769a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16779a0bf528SMauro Carvalho Chehab u8 n_overflow = 1;
16789a0bf528SMauro Carvalho Chehab u16 i = 1000;
16799a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0];
16809a0bf528SMauro Carvalho Chehab
16819a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) {
16829a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16839a0bf528SMauro Carvalho Chehab i--;
16849a0bf528SMauro Carvalho Chehab if (i == 0)
16858af16adfSMauro Carvalho Chehab dprintk("Tuner ITF: write busy (overflow)\n");
16869a0bf528SMauro Carvalho Chehab }
16879a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
16889a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
16899a0bf528SMauro Carvalho Chehab
16909a0bf528SMauro Carvalho Chehab return num;
16919a0bf528SMauro Carvalho Chehab }
16929a0bf528SMauro Carvalho Chehab
dib8096p_tuner_read_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)16939a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
16949a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num)
16959a0bf528SMauro Carvalho Chehab {
16969a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16979a0bf528SMauro Carvalho Chehab u8 n_overflow = 1, n_empty = 1;
16989a0bf528SMauro Carvalho Chehab u16 i = 1000;
16999a0bf528SMauro Carvalho Chehab u16 serpar_num = msg[0].buf[0];
17009a0bf528SMauro Carvalho Chehab u16 read_word;
17019a0bf528SMauro Carvalho Chehab
17029a0bf528SMauro Carvalho Chehab while (n_overflow == 1 && i) {
17039a0bf528SMauro Carvalho Chehab n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
17049a0bf528SMauro Carvalho Chehab i--;
17059a0bf528SMauro Carvalho Chehab if (i == 0)
17068af16adfSMauro Carvalho Chehab dprintk("TunerITF: read busy (overflow)\n");
17079a0bf528SMauro Carvalho Chehab }
17089a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
17099a0bf528SMauro Carvalho Chehab
17109a0bf528SMauro Carvalho Chehab i = 1000;
17119a0bf528SMauro Carvalho Chehab while (n_empty == 1 && i) {
17129a0bf528SMauro Carvalho Chehab n_empty = dib8000_read_word(state, 1984)&0x1;
17139a0bf528SMauro Carvalho Chehab i--;
17149a0bf528SMauro Carvalho Chehab if (i == 0)
17158af16adfSMauro Carvalho Chehab dprintk("TunerITF: read busy (empty)\n");
17169a0bf528SMauro Carvalho Chehab }
17179a0bf528SMauro Carvalho Chehab
17189a0bf528SMauro Carvalho Chehab read_word = dib8000_read_word(state, 1987);
17199a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (read_word >> 8) & 0xff;
17209a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (read_word) & 0xff;
17219a0bf528SMauro Carvalho Chehab
17229a0bf528SMauro Carvalho Chehab return num;
17239a0bf528SMauro Carvalho Chehab }
17249a0bf528SMauro Carvalho Chehab
dib8096p_tuner_rw_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)17259a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
17269a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num)
17279a0bf528SMauro Carvalho Chehab {
17289a0bf528SMauro Carvalho Chehab if (map_addr_to_serpar_number(&msg[0]) == 0) {
17299a0bf528SMauro Carvalho Chehab if (num == 1) /* write */
17309a0bf528SMauro Carvalho Chehab return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
17319a0bf528SMauro Carvalho Chehab else /* read */
17329a0bf528SMauro Carvalho Chehab return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
17339a0bf528SMauro Carvalho Chehab }
17349a0bf528SMauro Carvalho Chehab return num;
17359a0bf528SMauro Carvalho Chehab }
17369a0bf528SMauro Carvalho Chehab
dib8096p_rw_on_apb(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num,u16 apb_address)17379a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
17389a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num, u16 apb_address)
17399a0bf528SMauro Carvalho Chehab {
17409a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17419a0bf528SMauro Carvalho Chehab u16 word;
17429a0bf528SMauro Carvalho Chehab
17439a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */
17449a0bf528SMauro Carvalho Chehab dib8000_write_word(state, apb_address,
17459a0bf528SMauro Carvalho Chehab ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
17469a0bf528SMauro Carvalho Chehab } else {
17479a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, apb_address);
17489a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff;
17499a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff;
17509a0bf528SMauro Carvalho Chehab }
17519a0bf528SMauro Carvalho Chehab return num;
17529a0bf528SMauro Carvalho Chehab }
17539a0bf528SMauro Carvalho Chehab
dib8096p_tuner_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)17549a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
17559a0bf528SMauro Carvalho Chehab struct i2c_msg msg[], int num)
17569a0bf528SMauro Carvalho Chehab {
17579a0bf528SMauro Carvalho Chehab struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17589a0bf528SMauro Carvalho Chehab u16 apb_address = 0, word;
17599a0bf528SMauro Carvalho Chehab int i = 0;
17609a0bf528SMauro Carvalho Chehab
17619a0bf528SMauro Carvalho Chehab switch (msg[0].buf[0]) {
17629a0bf528SMauro Carvalho Chehab case 0x12:
17639a0bf528SMauro Carvalho Chehab apb_address = 1920;
17649a0bf528SMauro Carvalho Chehab break;
17659a0bf528SMauro Carvalho Chehab case 0x14:
17669a0bf528SMauro Carvalho Chehab apb_address = 1921;
17679a0bf528SMauro Carvalho Chehab break;
17689a0bf528SMauro Carvalho Chehab case 0x24:
17699a0bf528SMauro Carvalho Chehab apb_address = 1922;
17709a0bf528SMauro Carvalho Chehab break;
17719a0bf528SMauro Carvalho Chehab case 0x1a:
17729a0bf528SMauro Carvalho Chehab apb_address = 1923;
17739a0bf528SMauro Carvalho Chehab break;
17749a0bf528SMauro Carvalho Chehab case 0x22:
17759a0bf528SMauro Carvalho Chehab apb_address = 1924;
17769a0bf528SMauro Carvalho Chehab break;
17779a0bf528SMauro Carvalho Chehab case 0x33:
17789a0bf528SMauro Carvalho Chehab apb_address = 1926;
17799a0bf528SMauro Carvalho Chehab break;
17809a0bf528SMauro Carvalho Chehab case 0x34:
17819a0bf528SMauro Carvalho Chehab apb_address = 1927;
17829a0bf528SMauro Carvalho Chehab break;
17839a0bf528SMauro Carvalho Chehab case 0x35:
17849a0bf528SMauro Carvalho Chehab apb_address = 1928;
17859a0bf528SMauro Carvalho Chehab break;
17869a0bf528SMauro Carvalho Chehab case 0x36:
17879a0bf528SMauro Carvalho Chehab apb_address = 1929;
17889a0bf528SMauro Carvalho Chehab break;
17899a0bf528SMauro Carvalho Chehab case 0x37:
17909a0bf528SMauro Carvalho Chehab apb_address = 1930;
17919a0bf528SMauro Carvalho Chehab break;
17929a0bf528SMauro Carvalho Chehab case 0x38:
17939a0bf528SMauro Carvalho Chehab apb_address = 1931;
17949a0bf528SMauro Carvalho Chehab break;
17959a0bf528SMauro Carvalho Chehab case 0x39:
17969a0bf528SMauro Carvalho Chehab apb_address = 1932;
17979a0bf528SMauro Carvalho Chehab break;
17989a0bf528SMauro Carvalho Chehab case 0x2a:
17999a0bf528SMauro Carvalho Chehab apb_address = 1935;
18009a0bf528SMauro Carvalho Chehab break;
18019a0bf528SMauro Carvalho Chehab case 0x2b:
18029a0bf528SMauro Carvalho Chehab apb_address = 1936;
18039a0bf528SMauro Carvalho Chehab break;
18049a0bf528SMauro Carvalho Chehab case 0x2c:
18059a0bf528SMauro Carvalho Chehab apb_address = 1937;
18069a0bf528SMauro Carvalho Chehab break;
18079a0bf528SMauro Carvalho Chehab case 0x2d:
18089a0bf528SMauro Carvalho Chehab apb_address = 1938;
18099a0bf528SMauro Carvalho Chehab break;
18109a0bf528SMauro Carvalho Chehab case 0x2e:
18119a0bf528SMauro Carvalho Chehab apb_address = 1939;
18129a0bf528SMauro Carvalho Chehab break;
18139a0bf528SMauro Carvalho Chehab case 0x2f:
18149a0bf528SMauro Carvalho Chehab apb_address = 1940;
18159a0bf528SMauro Carvalho Chehab break;
18169a0bf528SMauro Carvalho Chehab case 0x30:
18179a0bf528SMauro Carvalho Chehab apb_address = 1941;
18189a0bf528SMauro Carvalho Chehab break;
18199a0bf528SMauro Carvalho Chehab case 0x31:
18209a0bf528SMauro Carvalho Chehab apb_address = 1942;
18219a0bf528SMauro Carvalho Chehab break;
18229a0bf528SMauro Carvalho Chehab case 0x32:
18239a0bf528SMauro Carvalho Chehab apb_address = 1943;
18249a0bf528SMauro Carvalho Chehab break;
18259a0bf528SMauro Carvalho Chehab case 0x3e:
18269a0bf528SMauro Carvalho Chehab apb_address = 1944;
18279a0bf528SMauro Carvalho Chehab break;
18289a0bf528SMauro Carvalho Chehab case 0x3f:
18299a0bf528SMauro Carvalho Chehab apb_address = 1945;
18309a0bf528SMauro Carvalho Chehab break;
18319a0bf528SMauro Carvalho Chehab case 0x40:
18329a0bf528SMauro Carvalho Chehab apb_address = 1948;
18339a0bf528SMauro Carvalho Chehab break;
18349a0bf528SMauro Carvalho Chehab case 0x25:
18359a0bf528SMauro Carvalho Chehab apb_address = 936;
18369a0bf528SMauro Carvalho Chehab break;
18379a0bf528SMauro Carvalho Chehab case 0x26:
18389a0bf528SMauro Carvalho Chehab apb_address = 937;
18399a0bf528SMauro Carvalho Chehab break;
18409a0bf528SMauro Carvalho Chehab case 0x27:
18419a0bf528SMauro Carvalho Chehab apb_address = 938;
18429a0bf528SMauro Carvalho Chehab break;
18439a0bf528SMauro Carvalho Chehab case 0x28:
18449a0bf528SMauro Carvalho Chehab apb_address = 939;
18459a0bf528SMauro Carvalho Chehab break;
18469a0bf528SMauro Carvalho Chehab case 0x1d:
18479a0bf528SMauro Carvalho Chehab /* get sad sel request */
18489a0bf528SMauro Carvalho Chehab i = ((dib8000_read_word(state, 921) >> 12)&0x3);
18499a0bf528SMauro Carvalho Chehab word = dib8000_read_word(state, 924+i);
18509a0bf528SMauro Carvalho Chehab msg[1].buf[0] = (word >> 8) & 0xff;
18519a0bf528SMauro Carvalho Chehab msg[1].buf[1] = (word) & 0xff;
18529a0bf528SMauro Carvalho Chehab return num;
18539a0bf528SMauro Carvalho Chehab case 0x1f:
18549a0bf528SMauro Carvalho Chehab if (num == 1) { /* write */
18559a0bf528SMauro Carvalho Chehab word = (u16) ((msg[0].buf[1] << 8) |
18569a0bf528SMauro Carvalho Chehab msg[0].buf[2]);
18579a0bf528SMauro Carvalho Chehab /* in the VGAMODE Sel are located on bit 0/1 */
18589a0bf528SMauro Carvalho Chehab word &= 0x3;
18599a0bf528SMauro Carvalho Chehab word = (dib8000_read_word(state, 921) &
18609a0bf528SMauro Carvalho Chehab ~(3<<12)) | (word<<12);
18619a0bf528SMauro Carvalho Chehab /* Set the proper input */
18629a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 921, word);
18639a0bf528SMauro Carvalho Chehab return num;
18649a0bf528SMauro Carvalho Chehab }
18659a0bf528SMauro Carvalho Chehab }
18669a0bf528SMauro Carvalho Chehab
1867868c9a17SMauro Carvalho Chehab if (apb_address != 0) /* R/W access via APB */
18689a0bf528SMauro Carvalho Chehab return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
18699a0bf528SMauro Carvalho Chehab else /* R/W access via SERPAR */
18709a0bf528SMauro Carvalho Chehab return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
18719a0bf528SMauro Carvalho Chehab
18729a0bf528SMauro Carvalho Chehab return 0;
18739a0bf528SMauro Carvalho Chehab }
18749a0bf528SMauro Carvalho Chehab
dib8096p_i2c_func(struct i2c_adapter * adapter)18759a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
18769a0bf528SMauro Carvalho Chehab {
18779a0bf528SMauro Carvalho Chehab return I2C_FUNC_I2C;
18789a0bf528SMauro Carvalho Chehab }
18799a0bf528SMauro Carvalho Chehab
188028e83542SGustavo A. R. Silva static const struct i2c_algorithm dib8096p_tuner_xfer_algo = {
18819a0bf528SMauro Carvalho Chehab .master_xfer = dib8096p_tuner_xfer,
18829a0bf528SMauro Carvalho Chehab .functionality = dib8096p_i2c_func,
18839a0bf528SMauro Carvalho Chehab };
18849a0bf528SMauro Carvalho Chehab
dib8096p_get_i2c_tuner(struct dvb_frontend * fe)1885d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
18869a0bf528SMauro Carvalho Chehab {
18879a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv;
18889a0bf528SMauro Carvalho Chehab return &st->dib8096p_tuner_adap;
18899a0bf528SMauro Carvalho Chehab }
18909a0bf528SMauro Carvalho Chehab
dib8096p_tuner_sleep(struct dvb_frontend * fe,int onoff)1891d44913c1SMauro Carvalho Chehab static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
18929a0bf528SMauro Carvalho Chehab {
18939a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
18949a0bf528SMauro Carvalho Chehab u16 en_cur_state;
18959a0bf528SMauro Carvalho Chehab
18968af16adfSMauro Carvalho Chehab dprintk("sleep dib8096p: %d\n", onoff);
18979a0bf528SMauro Carvalho Chehab
18989a0bf528SMauro Carvalho Chehab en_cur_state = dib8000_read_word(state, 1922);
18999a0bf528SMauro Carvalho Chehab
19009a0bf528SMauro Carvalho Chehab /* LNAs and MIX are ON and therefore it is a valid configuration */
19019a0bf528SMauro Carvalho Chehab if (en_cur_state > 0xff)
19029a0bf528SMauro Carvalho Chehab state->tuner_enable = en_cur_state ;
19039a0bf528SMauro Carvalho Chehab
19049a0bf528SMauro Carvalho Chehab if (onoff)
19059a0bf528SMauro Carvalho Chehab en_cur_state &= 0x00ff;
19069a0bf528SMauro Carvalho Chehab else {
19079a0bf528SMauro Carvalho Chehab if (state->tuner_enable != 0)
19089a0bf528SMauro Carvalho Chehab en_cur_state = state->tuner_enable;
19099a0bf528SMauro Carvalho Chehab }
19109a0bf528SMauro Carvalho Chehab
19119a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 1922, en_cur_state);
19129a0bf528SMauro Carvalho Chehab
19139a0bf528SMauro Carvalho Chehab return 0;
19149a0bf528SMauro Carvalho Chehab }
19159a0bf528SMauro Carvalho Chehab
19169a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] =
19179a0bf528SMauro Carvalho Chehab {
19189a0bf528SMauro Carvalho Chehab 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
19199a0bf528SMauro Carvalho Chehab };
19209a0bf528SMauro Carvalho Chehab
dib8000_get_adc_power(struct dvb_frontend * fe,u8 mode)1921d44913c1SMauro Carvalho Chehab static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
19229a0bf528SMauro Carvalho Chehab {
19239a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
19249a0bf528SMauro Carvalho Chehab u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
19259a0bf528SMauro Carvalho Chehab s32 val;
19269a0bf528SMauro Carvalho Chehab
19279a0bf528SMauro Carvalho Chehab val = dib8000_read32(state, 384);
19289a0bf528SMauro Carvalho Chehab if (mode) {
19299a0bf528SMauro Carvalho Chehab tmp_val = val;
19309a0bf528SMauro Carvalho Chehab while (tmp_val >>= 1)
19319a0bf528SMauro Carvalho Chehab exp++;
19329a0bf528SMauro Carvalho Chehab mant = (val * 1000 / (1<<exp));
19339a0bf528SMauro Carvalho Chehab ix = (u8)((mant-1000)/100); /* index of the LUT */
19349a0bf528SMauro Carvalho Chehab val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
19359a0bf528SMauro Carvalho Chehab val = (val*256)/1000;
19369a0bf528SMauro Carvalho Chehab }
19379a0bf528SMauro Carvalho Chehab return val;
19389a0bf528SMauro Carvalho Chehab }
19399a0bf528SMauro Carvalho Chehab
dib8090p_get_dc_power(struct dvb_frontend * fe,u8 IQ)1940d44913c1SMauro Carvalho Chehab static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
19419a0bf528SMauro Carvalho Chehab {
19429a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
19439a0bf528SMauro Carvalho Chehab int val = 0;
19449a0bf528SMauro Carvalho Chehab
19459a0bf528SMauro Carvalho Chehab switch (IQ) {
19469a0bf528SMauro Carvalho Chehab case 1:
19479a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 403);
19489a0bf528SMauro Carvalho Chehab break;
19499a0bf528SMauro Carvalho Chehab case 0:
19509a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 404);
19519a0bf528SMauro Carvalho Chehab break;
19529a0bf528SMauro Carvalho Chehab }
19539a0bf528SMauro Carvalho Chehab if (val & 0x200)
19549a0bf528SMauro Carvalho Chehab val -= 1024;
19559a0bf528SMauro Carvalho Chehab
19569a0bf528SMauro Carvalho Chehab return val;
19579a0bf528SMauro Carvalho Chehab }
19589a0bf528SMauro Carvalho Chehab
dib8000_update_timf(struct dib8000_state * state)19599a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state)
19609a0bf528SMauro Carvalho Chehab {
19619a0bf528SMauro Carvalho Chehab u32 timf = state->timf = dib8000_read32(state, 435);
19629a0bf528SMauro Carvalho Chehab
19639a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 29, (u16) (timf >> 16));
19649a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 30, (u16) (timf & 0xffff));
19658af16adfSMauro Carvalho Chehab dprintk("Updated timing frequency: %d (default: %d)\n", state->timf, state->timf_default);
19669a0bf528SMauro Carvalho Chehab }
19679a0bf528SMauro Carvalho Chehab
dib8000_ctrl_timf(struct dvb_frontend * fe,uint8_t op,uint32_t timf)1968d44913c1SMauro Carvalho Chehab static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
19699a0bf528SMauro Carvalho Chehab {
19709a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
19719a0bf528SMauro Carvalho Chehab
19729a0bf528SMauro Carvalho Chehab switch (op) {
19739a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_SET:
19749a0bf528SMauro Carvalho Chehab state->timf = timf;
19759a0bf528SMauro Carvalho Chehab break;
19769a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_UPDATE:
19779a0bf528SMauro Carvalho Chehab dib8000_update_timf(state);
19789a0bf528SMauro Carvalho Chehab break;
19799a0bf528SMauro Carvalho Chehab case DEMOD_TIMF_GET:
19809a0bf528SMauro Carvalho Chehab break;
19819a0bf528SMauro Carvalho Chehab }
19829a0bf528SMauro Carvalho Chehab dib8000_set_bandwidth(state->fe[0], 6000);
19839a0bf528SMauro Carvalho Chehab
19849a0bf528SMauro Carvalho Chehab return state->timf;
19859a0bf528SMauro Carvalho Chehab }
19869a0bf528SMauro Carvalho Chehab
19879a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = {
1988a768f90eSMauro Carvalho Chehab 7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
19899a0bf528SMauro Carvalho Chehab };
1990a768f90eSMauro Carvalho Chehab
19919a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
19929a0bf528SMauro Carvalho Chehab
dib8000_set_layer(struct dib8000_state * state,u8 layer_index,u16 max_constellation)1993173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
19949a0bf528SMauro Carvalho Chehab {
1995173a64cbSPatrick Boettcher u8 cr, constellation, time_intlv;
1996c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
19979a0bf528SMauro Carvalho Chehab
1998c82056d0SMauro Carvalho Chehab switch (c->layer[layer_index].modulation) {
19999a0bf528SMauro Carvalho Chehab case DQPSK:
20009a0bf528SMauro Carvalho Chehab constellation = 0;
20019a0bf528SMauro Carvalho Chehab break;
20029a0bf528SMauro Carvalho Chehab case QPSK:
20039a0bf528SMauro Carvalho Chehab constellation = 1;
20049a0bf528SMauro Carvalho Chehab break;
20059a0bf528SMauro Carvalho Chehab case QAM_16:
20069a0bf528SMauro Carvalho Chehab constellation = 2;
20079a0bf528SMauro Carvalho Chehab break;
20089a0bf528SMauro Carvalho Chehab case QAM_64:
20099a0bf528SMauro Carvalho Chehab default:
20109a0bf528SMauro Carvalho Chehab constellation = 3;
20119a0bf528SMauro Carvalho Chehab break;
20129a0bf528SMauro Carvalho Chehab }
20139a0bf528SMauro Carvalho Chehab
2014c82056d0SMauro Carvalho Chehab switch (c->layer[layer_index].fec) {
20159a0bf528SMauro Carvalho Chehab case FEC_1_2:
2016173a64cbSPatrick Boettcher cr = 1;
20179a0bf528SMauro Carvalho Chehab break;
20189a0bf528SMauro Carvalho Chehab case FEC_2_3:
2019173a64cbSPatrick Boettcher cr = 2;
20209a0bf528SMauro Carvalho Chehab break;
20219a0bf528SMauro Carvalho Chehab case FEC_3_4:
2022173a64cbSPatrick Boettcher cr = 3;
20239a0bf528SMauro Carvalho Chehab break;
20249a0bf528SMauro Carvalho Chehab case FEC_5_6:
2025173a64cbSPatrick Boettcher cr = 5;
20269a0bf528SMauro Carvalho Chehab break;
20279a0bf528SMauro Carvalho Chehab case FEC_7_8:
20289a0bf528SMauro Carvalho Chehab default:
2029173a64cbSPatrick Boettcher cr = 7;
20309a0bf528SMauro Carvalho Chehab break;
20319a0bf528SMauro Carvalho Chehab }
20329a0bf528SMauro Carvalho Chehab
203334ba2e65SMauro Carvalho Chehab time_intlv = fls(c->layer[layer_index].interleaving);
203434ba2e65SMauro Carvalho Chehab if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
2035173a64cbSPatrick Boettcher time_intlv = 0;
2036173a64cbSPatrick Boettcher
2037c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2038c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].segment_count > 0) {
20399a0bf528SMauro Carvalho Chehab switch (max_constellation) {
20409a0bf528SMauro Carvalho Chehab case DQPSK:
20419a0bf528SMauro Carvalho Chehab case QPSK:
2042c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2043c82056d0SMauro Carvalho Chehab max_constellation = c->layer[layer_index].modulation;
20449a0bf528SMauro Carvalho Chehab break;
20459a0bf528SMauro Carvalho Chehab case QAM_16:
2046c82056d0SMauro Carvalho Chehab if (c->layer[layer_index].modulation == QAM_64)
2047c82056d0SMauro Carvalho Chehab max_constellation = c->layer[layer_index].modulation;
20489a0bf528SMauro Carvalho Chehab break;
20499a0bf528SMauro Carvalho Chehab }
20509a0bf528SMauro Carvalho Chehab }
2051173a64cbSPatrick Boettcher
2052173a64cbSPatrick Boettcher return max_constellation;
20539a0bf528SMauro Carvalho Chehab }
20549a0bf528SMauro Carvalho Chehab
2055173a64cbSPatrick Boettcher static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */
2056173a64cbSPatrick Boettcher static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */
2057173a64cbSPatrick Boettcher static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3, P_adp_noise_cnt -0.01, P_adp_regul_ext 0.1, P_adp_noise_ext -0.002 */
dib8000_adp_fine_tune(struct dib8000_state * state,u16 max_constellation)2058173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2059173a64cbSPatrick Boettcher {
2060173a64cbSPatrick Boettcher u16 i, ana_gain = 0;
2061173a64cbSPatrick Boettcher const u16 *adp;
20629a0bf528SMauro Carvalho Chehab
2063173a64cbSPatrick Boettcher /* channel estimation fine configuration */
2064173a64cbSPatrick Boettcher switch (max_constellation) {
2065173a64cbSPatrick Boettcher case QAM_64:
2066173a64cbSPatrick Boettcher ana_gain = 0x7;
2067173a64cbSPatrick Boettcher adp = &adp_Q64[0];
2068173a64cbSPatrick Boettcher break;
2069173a64cbSPatrick Boettcher case QAM_16:
2070173a64cbSPatrick Boettcher ana_gain = 0x7;
2071173a64cbSPatrick Boettcher adp = &adp_Q16[0];
2072173a64cbSPatrick Boettcher break;
2073173a64cbSPatrick Boettcher default:
2074173a64cbSPatrick Boettcher ana_gain = 0;
2075173a64cbSPatrick Boettcher adp = &adp_Qdefault[0];
2076173a64cbSPatrick Boettcher break;
20779a0bf528SMauro Carvalho Chehab }
20789a0bf528SMauro Carvalho Chehab
2079173a64cbSPatrick Boettcher for (i = 0; i < 4; i++)
2080173a64cbSPatrick Boettcher dib8000_write_word(state, 215 + i, adp[i]);
20819a0bf528SMauro Carvalho Chehab
2082173a64cbSPatrick Boettcher return ana_gain;
2083173a64cbSPatrick Boettcher }
20849a0bf528SMauro Carvalho Chehab
dib8000_update_ana_gain(struct dib8000_state * state,u16 ana_gain)2085173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2086173a64cbSPatrick Boettcher {
2087173a64cbSPatrick Boettcher u16 i;
20889a0bf528SMauro Carvalho Chehab
2089173a64cbSPatrick Boettcher dib8000_write_word(state, 116, ana_gain);
20909a0bf528SMauro Carvalho Chehab
2091173a64cbSPatrick Boettcher /* update ADC target depending on ana_gain */
2092173a64cbSPatrick Boettcher if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2093173a64cbSPatrick Boettcher for (i = 0; i < 10; i++)
2094173a64cbSPatrick Boettcher dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2095173a64cbSPatrick Boettcher } else { /* set -22dB ADC target for ana_gain=0 */
2096173a64cbSPatrick Boettcher for (i = 0; i < 10; i++)
2097173a64cbSPatrick Boettcher dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2098173a64cbSPatrick Boettcher }
2099173a64cbSPatrick Boettcher }
21009a0bf528SMauro Carvalho Chehab
dib8000_load_ana_fe_coefs(struct dib8000_state * state,const s16 * ana_fe)2101173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2102173a64cbSPatrick Boettcher {
2103173a64cbSPatrick Boettcher u16 mode = 0;
21049a0bf528SMauro Carvalho Chehab
2105173a64cbSPatrick Boettcher if (state->isdbt_cfg_loaded == 0)
2106173a64cbSPatrick Boettcher for (mode = 0; mode < 24; mode++)
2107173a64cbSPatrick Boettcher dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2108173a64cbSPatrick Boettcher }
21099a0bf528SMauro Carvalho Chehab
21108db11aebSMauro Carvalho Chehab static const u16 lut_prbs_2k[13] = {
21118db11aebSMauro Carvalho Chehab 0x423, 0x009, 0x5C7,
21128db11aebSMauro Carvalho Chehab 0x7A6, 0x3D8, 0x527,
21138db11aebSMauro Carvalho Chehab 0x7FF, 0x79B, 0x3D6,
21148db11aebSMauro Carvalho Chehab 0x3A2, 0x53B, 0x2F4,
21158db11aebSMauro Carvalho Chehab 0x213
2116173a64cbSPatrick Boettcher };
21178db11aebSMauro Carvalho Chehab
21188db11aebSMauro Carvalho Chehab static const u16 lut_prbs_4k[13] = {
21198db11aebSMauro Carvalho Chehab 0x208, 0x0C3, 0x7B9,
21208db11aebSMauro Carvalho Chehab 0x423, 0x5C7, 0x3D8,
21218db11aebSMauro Carvalho Chehab 0x7FF, 0x3D6, 0x53B,
21228db11aebSMauro Carvalho Chehab 0x213, 0x029, 0x0D0,
21238db11aebSMauro Carvalho Chehab 0x48E
2124173a64cbSPatrick Boettcher };
21258db11aebSMauro Carvalho Chehab
21268db11aebSMauro Carvalho Chehab static const u16 lut_prbs_8k[13] = {
21278db11aebSMauro Carvalho Chehab 0x740, 0x069, 0x7DD,
21288db11aebSMauro Carvalho Chehab 0x208, 0x7B9, 0x5C7,
21298db11aebSMauro Carvalho Chehab 0x7FF, 0x53B, 0x029,
21308db11aebSMauro Carvalho Chehab 0x48E, 0x4C4, 0x367,
21318db11aebSMauro Carvalho Chehab 0x684
2132173a64cbSPatrick Boettcher };
2133173a64cbSPatrick Boettcher
dib8000_get_init_prbs(struct dib8000_state * state,u16 subchannel)2134173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2135173a64cbSPatrick Boettcher {
2136173a64cbSPatrick Boettcher int sub_channel_prbs_group = 0;
21378db11aebSMauro Carvalho Chehab int prbs_group;
2138173a64cbSPatrick Boettcher
21398db11aebSMauro Carvalho Chehab sub_channel_prbs_group = subchannel / 3;
21408db11aebSMauro Carvalho Chehab if (sub_channel_prbs_group >= ARRAY_SIZE(lut_prbs_2k))
21418db11aebSMauro Carvalho Chehab return 0;
2142173a64cbSPatrick Boettcher
21439a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) {
21449a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
21458db11aebSMauro Carvalho Chehab prbs_group = lut_prbs_2k[sub_channel_prbs_group];
21468db11aebSMauro Carvalho Chehab break;
21479a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
21488db11aebSMauro Carvalho Chehab prbs_group = lut_prbs_4k[sub_channel_prbs_group];
21498db11aebSMauro Carvalho Chehab break;
21509a0bf528SMauro Carvalho Chehab default:
2151173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K:
21528db11aebSMauro Carvalho Chehab prbs_group = lut_prbs_8k[sub_channel_prbs_group];
21539a0bf528SMauro Carvalho Chehab }
21548db11aebSMauro Carvalho Chehab
21558db11aebSMauro Carvalho Chehab dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n",
21568db11aebSMauro Carvalho Chehab sub_channel_prbs_group, subchannel, prbs_group);
21578db11aebSMauro Carvalho Chehab
21588db11aebSMauro Carvalho Chehab return prbs_group;
21599a0bf528SMauro Carvalho Chehab }
21609a0bf528SMauro Carvalho Chehab
dib8000_set_13seg_channel(struct dib8000_state * state)2161173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state)
2162173a64cbSPatrick Boettcher {
2163173a64cbSPatrick Boettcher u16 i;
2164173a64cbSPatrick Boettcher u16 coff_pow = 0x2800;
21659a0bf528SMauro Carvalho Chehab
2166173a64cbSPatrick Boettcher state->seg_mask = 0x1fff; /* All 13 segments enabled */
21679a0bf528SMauro Carvalho Chehab
2168173a64cbSPatrick Boettcher /* ---- COFF ---- Carloff, the most robust --- */
2169173a64cbSPatrick Boettcher if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
21709a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 180, (16 << 6) | 9);
21719a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
21729a0bf528SMauro Carvalho Chehab coff_pow = 0x2800;
21739a0bf528SMauro Carvalho Chehab for (i = 0; i < 6; i++)
21749a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 181+i, coff_pow);
21759a0bf528SMauro Carvalho Chehab
2176173a64cbSPatrick Boettcher /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2177173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */
21789a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
21799a0bf528SMauro Carvalho Chehab
2180173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
21819a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2182173a64cbSPatrick Boettcher /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
21839a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
21849a0bf528SMauro Carvalho Chehab
2185173a64cbSPatrick Boettcher dib8000_write_word(state, 228, 0); /* default value */
2186173a64cbSPatrick Boettcher dib8000_write_word(state, 265, 31); /* default value */
2187173a64cbSPatrick Boettcher dib8000_write_word(state, 205, 0x200f); /* init value */
2188173a64cbSPatrick Boettcher }
2189173a64cbSPatrick Boettcher
2190173a64cbSPatrick Boettcher /*
2191173a64cbSPatrick Boettcher * make the cpil_coff_lock more robust but slower p_coff_winlen
21929a0bf528SMauro Carvalho Chehab * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
21939a0bf528SMauro Carvalho Chehab */
21949a0bf528SMauro Carvalho Chehab
2195173a64cbSPatrick Boettcher if (state->cfg.pll->ifreq == 0)
2196173a64cbSPatrick Boettcher dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
21979a0bf528SMauro Carvalho Chehab
2198173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2199173a64cbSPatrick Boettcher }
22009a0bf528SMauro Carvalho Chehab
dib8000_set_subchannel_prbs(struct dib8000_state * state,u16 init_prbs)2201173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2202173a64cbSPatrick Boettcher {
2203173a64cbSPatrick Boettcher u16 reg_1;
22049a0bf528SMauro Carvalho Chehab
2205173a64cbSPatrick Boettcher reg_1 = dib8000_read_word(state, 1);
2206173a64cbSPatrick Boettcher dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2207173a64cbSPatrick Boettcher }
22089a0bf528SMauro Carvalho Chehab
dib8000_small_fine_tune(struct dib8000_state * state)2209173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state)
2210173a64cbSPatrick Boettcher {
2211173a64cbSPatrick Boettcher u16 i;
2212173a64cbSPatrick Boettcher const s16 *ncoeff;
2213c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
22149a0bf528SMauro Carvalho Chehab
2215173a64cbSPatrick Boettcher dib8000_write_word(state, 352, state->seg_diff_mask);
2216173a64cbSPatrick Boettcher dib8000_write_word(state, 353, state->seg_mask);
22179a0bf528SMauro Carvalho Chehab
2218173a64cbSPatrick Boettcher /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
2219c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
2220173a64cbSPatrick Boettcher
2221c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) {
2222173a64cbSPatrick Boettcher /* ---- SMALL ---- */
2223c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) {
2224173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K:
2225c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */
2226c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */
2227173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_1seg_dqpsk;
2228173a64cbSPatrick Boettcher else /* QPSK or QAM */
2229173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_1seg;
2230173a64cbSPatrick Boettcher } else { /* 3-segments */
2231c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2232c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2233173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2234173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */
2235173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_0dqpsk;
2236173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */
2237c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2238173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg_1dqpsk;
2239173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */
2240173a64cbSPatrick Boettcher ncoeff = coeff_2k_sb_3seg;
2241173a64cbSPatrick Boettcher }
2242173a64cbSPatrick Boettcher }
22439a0bf528SMauro Carvalho Chehab break;
22449a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
2245c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */
2246c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */
2247173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_1seg_dqpsk;
2248173a64cbSPatrick Boettcher else /* QPSK or QAM */
2249173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_1seg;
2250173a64cbSPatrick Boettcher } else { /* 3-segments */
2251c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2252c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2253173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2254173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */
2255173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_0dqpsk;
2256173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */
2257c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2258173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg_1dqpsk;
2259173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */
2260173a64cbSPatrick Boettcher ncoeff = coeff_4k_sb_3seg;
2261173a64cbSPatrick Boettcher }
2262173a64cbSPatrick Boettcher }
22639a0bf528SMauro Carvalho Chehab break;
2264173a64cbSPatrick Boettcher case TRANSMISSION_MODE_AUTO:
2265173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K:
22669a0bf528SMauro Carvalho Chehab default:
2267c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* 1-seg */
2268c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) /* DQPSK */
2269173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_1seg_dqpsk;
2270173a64cbSPatrick Boettcher else /* QPSK or QAM */
2271173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_1seg;
2272173a64cbSPatrick Boettcher } else { /* 3-segments */
2273c82056d0SMauro Carvalho Chehab if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2274c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2275173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2276173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */
2277173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_0dqpsk;
2278173a64cbSPatrick Boettcher } else { /* QPSK or QAM on central segment */
2279c82056d0SMauro Carvalho Chehab if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2280173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg_1dqpsk;
2281173a64cbSPatrick Boettcher else /* QPSK or QAM on external segments */
2282173a64cbSPatrick Boettcher ncoeff = coeff_8k_sb_3seg;
2283173a64cbSPatrick Boettcher }
2284173a64cbSPatrick Boettcher }
22859a0bf528SMauro Carvalho Chehab break;
22869a0bf528SMauro Carvalho Chehab }
2287173a64cbSPatrick Boettcher
2288173a64cbSPatrick Boettcher for (i = 0; i < 8; i++)
2289173a64cbSPatrick Boettcher dib8000_write_word(state, 343 + i, ncoeff[i]);
2290173a64cbSPatrick Boettcher }
2291173a64cbSPatrick Boettcher }
2292173a64cbSPatrick Boettcher
2293173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80};
2294173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250};
dib8000_set_sb_channel(struct dib8000_state * state)2295173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state)
2296173a64cbSPatrick Boettcher {
2297c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2298173a64cbSPatrick Boettcher const u16 *coff;
2299173a64cbSPatrick Boettcher u16 i;
2300173a64cbSPatrick Boettcher
2301c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
2302173a64cbSPatrick Boettcher dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2303173a64cbSPatrick Boettcher dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2304173a64cbSPatrick Boettcher } else {
2305173a64cbSPatrick Boettcher dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2306173a64cbSPatrick Boettcher dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2307173a64cbSPatrick Boettcher }
2308173a64cbSPatrick Boettcher
2309c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 1) /* 3-segments */
2310173a64cbSPatrick Boettcher state->seg_mask = 0x00E0;
2311173a64cbSPatrick Boettcher else /* 1-segment */
2312173a64cbSPatrick Boettcher state->seg_mask = 0x0040;
2313173a64cbSPatrick Boettcher
2314173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2315173a64cbSPatrick Boettcher
2316173a64cbSPatrick Boettcher /* ---- COFF ---- Carloff, the most robust --- */
2317173a64cbSPatrick Boettcher /* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */
2318c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
2319173a64cbSPatrick Boettcher
2320173a64cbSPatrick Boettcher dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2321173a64cbSPatrick Boettcher dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */
2322173a64cbSPatrick Boettcher
2323173a64cbSPatrick Boettcher /* Sound Broadcasting mode 1 seg */
2324c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) {
2325173a64cbSPatrick Boettcher /* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */
2326173a64cbSPatrick Boettcher if (state->mode == 3)
2327173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
23289a0bf528SMauro Carvalho Chehab else
2329173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2330173a64cbSPatrick Boettcher
2331173a64cbSPatrick Boettcher /* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */
2332173a64cbSPatrick Boettcher dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2333173a64cbSPatrick Boettcher coff = &coff_thres_1seg[0];
2334173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */
2335173a64cbSPatrick Boettcher dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2336173a64cbSPatrick Boettcher /* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */
2337173a64cbSPatrick Boettcher dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2338173a64cbSPatrick Boettcher coff = &coff_thres_3seg[0];
2339173a64cbSPatrick Boettcher }
2340173a64cbSPatrick Boettcher
2341173a64cbSPatrick Boettcher dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2342173a64cbSPatrick Boettcher dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2343173a64cbSPatrick Boettcher
2344c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
2345173a64cbSPatrick Boettcher dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2346173a64cbSPatrick Boettcher
2347173a64cbSPatrick Boettcher /* Write COFF thres */
2348173a64cbSPatrick Boettcher for (i = 0 ; i < 3; i++) {
2349173a64cbSPatrick Boettcher dib8000_write_word(state, 181+i, coff[i]);
2350173a64cbSPatrick Boettcher dib8000_write_word(state, 184+i, coff[i]);
2351173a64cbSPatrick Boettcher }
2352173a64cbSPatrick Boettcher
2353173a64cbSPatrick Boettcher /*
2354173a64cbSPatrick Boettcher * make the cpil_coff_lock more robust but slower p_coff_winlen
2355173a64cbSPatrick Boettcher * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2356173a64cbSPatrick Boettcher */
2357173a64cbSPatrick Boettcher
2358173a64cbSPatrick Boettcher dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2359173a64cbSPatrick Boettcher
2360c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0)
2361173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2362173a64cbSPatrick Boettcher else
2363173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2364173a64cbSPatrick Boettcher }
2365173a64cbSPatrick Boettcher
dib8000_set_isdbt_common_channel(struct dib8000_state * state,u8 seq,u8 autosearching)2366173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2367173a64cbSPatrick Boettcher {
2368173a64cbSPatrick Boettcher u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
2369173a64cbSPatrick Boettcher u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2370173a64cbSPatrick Boettcher u16 max_constellation = DQPSK;
2371173a64cbSPatrick Boettcher int init_prbs;
2372c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2373173a64cbSPatrick Boettcher
2374dde8e115SMauro Carvalho Chehab if (autosearching)
2375dde8e115SMauro Carvalho Chehab c->isdbt_partial_reception = 1;
2376dde8e115SMauro Carvalho Chehab
2377173a64cbSPatrick Boettcher /* P_mode */
2378173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (seq << 4));
2379173a64cbSPatrick Boettcher
2380173a64cbSPatrick Boettcher /* init mode */
2381173a64cbSPatrick Boettcher state->mode = fft_to_mode(state);
2382173a64cbSPatrick Boettcher
2383173a64cbSPatrick Boettcher /* set guard */
2384173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 1);
2385c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
2386173a64cbSPatrick Boettcher
2387c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((c->isdbt_partial_reception & 1) << 5) | ((c->isdbt_sb_mode & 1) << 4));
2388173a64cbSPatrick Boettcher
2389173a64cbSPatrick Boettcher /* signal optimization parameter */
2390c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) {
2391c82056d0SMauro Carvalho Chehab state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
2392173a64cbSPatrick Boettcher for (i = 1; i < 3; i++)
2393c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2394173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++)
2395173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i+1];
2396173a64cbSPatrick Boettcher } else {
2397173a64cbSPatrick Boettcher for (i = 0; i < 3; i++)
2398c82056d0SMauro Carvalho Chehab nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2399173a64cbSPatrick Boettcher for (i = 0; i < nbseg_diff; i++)
2400173a64cbSPatrick Boettcher state->seg_diff_mask |= 1 << permu_seg[i];
2401173a64cbSPatrick Boettcher }
2402173a64cbSPatrick Boettcher
2403173a64cbSPatrick Boettcher if (state->seg_diff_mask)
2404173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2405173a64cbSPatrick Boettcher else
2406173a64cbSPatrick Boettcher dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2407173a64cbSPatrick Boettcher
2408173a64cbSPatrick Boettcher for (i = 0; i < 3; i++)
2409173a64cbSPatrick Boettcher max_constellation = dib8000_set_layer(state, i, max_constellation);
2410173a64cbSPatrick Boettcher if (autosearching == 0) {
2411c82056d0SMauro Carvalho Chehab state->layer_b_nb_seg = c->layer[1].segment_count;
2412c82056d0SMauro Carvalho Chehab state->layer_c_nb_seg = c->layer[2].segment_count;
2413173a64cbSPatrick Boettcher }
2414173a64cbSPatrick Boettcher
2415173a64cbSPatrick Boettcher /* WRITE: Mode & Diff mask */
2416173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2417173a64cbSPatrick Boettcher
2418173a64cbSPatrick Boettcher state->differential_constellation = (state->seg_diff_mask != 0);
24199a0bf528SMauro Carvalho Chehab
24209a0bf528SMauro Carvalho Chehab /* channel estimation fine configuration */
2421173a64cbSPatrick Boettcher ana_gain = dib8000_adp_fine_tune(state, max_constellation);
24229a0bf528SMauro Carvalho Chehab
2423173a64cbSPatrick Boettcher /* update ana_gain depending on max constellation */
2424173a64cbSPatrick Boettcher dib8000_update_ana_gain(state, ana_gain);
24259a0bf528SMauro Carvalho Chehab
2426173a64cbSPatrick Boettcher /* ---- ANA_FE ---- */
2427c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception) /* 3-segments */
2428173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2429173a64cbSPatrick Boettcher else
2430173a64cbSPatrick Boettcher dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2431173a64cbSPatrick Boettcher
2432173a64cbSPatrick Boettcher /* TSB or ISDBT ? apply it now */
2433c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) {
2434173a64cbSPatrick Boettcher dib8000_set_sb_channel(state);
24358db11aebSMauro Carvalho Chehab init_prbs = dib8000_get_init_prbs(state,
24368db11aebSMauro Carvalho Chehab c->isdbt_sb_subchannel);
2437173a64cbSPatrick Boettcher } else {
2438173a64cbSPatrick Boettcher dib8000_set_13seg_channel(state);
2439173a64cbSPatrick Boettcher init_prbs = 0xfff;
2440173a64cbSPatrick Boettcher }
24419a0bf528SMauro Carvalho Chehab
2442173a64cbSPatrick Boettcher /* SMALL */
2443173a64cbSPatrick Boettcher dib8000_small_fine_tune(state);
24449a0bf528SMauro Carvalho Chehab
2445173a64cbSPatrick Boettcher dib8000_set_subchannel_prbs(state, init_prbs);
2446173a64cbSPatrick Boettcher
2447173a64cbSPatrick Boettcher /* ---- CHAN_BLK ---- */
24489a0bf528SMauro Carvalho Chehab for (i = 0; i < 13; i++) {
2449173a64cbSPatrick Boettcher if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2450173a64cbSPatrick Boettcher p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2451173a64cbSPatrick Boettcher p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
24529a0bf528SMauro Carvalho Chehab }
24539a0bf528SMauro Carvalho Chehab }
2454173a64cbSPatrick Boettcher dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2455173a64cbSPatrick Boettcher dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2456173a64cbSPatrick Boettcher /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
24579a0bf528SMauro Carvalho Chehab
2458173a64cbSPatrick Boettcher dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2459173a64cbSPatrick Boettcher dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2460173a64cbSPatrick Boettcher dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2461173a64cbSPatrick Boettcher
2462173a64cbSPatrick Boettcher if (!autosearching)
2463173a64cbSPatrick Boettcher dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2464173a64cbSPatrick Boettcher else
2465173a64cbSPatrick Boettcher dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2466173a64cbSPatrick Boettcher
2467173a64cbSPatrick Boettcher dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2468173a64cbSPatrick Boettcher dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2469173a64cbSPatrick Boettcher
2470173a64cbSPatrick Boettcher dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2471173a64cbSPatrick Boettcher
2472173a64cbSPatrick Boettcher /* ---- TMCC ---- */
24739a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++)
2474c82056d0SMauro Carvalho Chehab tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
2475173a64cbSPatrick Boettcher
2476173a64cbSPatrick Boettcher /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2477173a64cbSPatrick Boettcher /* Threshold is set at 1/4 of max power. */
24789a0bf528SMauro Carvalho Chehab tmcc_pow *= (1 << (9-2));
2479173a64cbSPatrick Boettcher dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2480173a64cbSPatrick Boettcher dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2481173a64cbSPatrick Boettcher dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2482173a64cbSPatrick Boettcher /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
24839a0bf528SMauro Carvalho Chehab
2484173a64cbSPatrick Boettcher /* ---- PHA3 ---- */
24859a0bf528SMauro Carvalho Chehab if (state->isdbt_cfg_loaded == 0)
24869a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
24879a0bf528SMauro Carvalho Chehab
24889a0bf528SMauro Carvalho Chehab state->isdbt_cfg_loaded = 0;
2489173a64cbSPatrick Boettcher }
24909a0bf528SMauro Carvalho Chehab
dib8000_wait_lock(struct dib8000_state * state,u32 internal,u32 wait0_ms,u32 wait1_ms,u32 wait2_ms)24916f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
24926f7ee06fSMauro Carvalho Chehab u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2493173a64cbSPatrick Boettcher {
249413122f98SMauro Carvalho Chehab u32 value = 0; /* P_search_end0 wait time */
2495173a64cbSPatrick Boettcher u16 reg = 11; /* P_search_end0 start addr */
2496173a64cbSPatrick Boettcher
2497173a64cbSPatrick Boettcher for (reg = 11; reg < 16; reg += 2) {
2498173a64cbSPatrick Boettcher if (reg == 11) {
2499173a64cbSPatrick Boettcher if (state->revision == 0x8090)
250013122f98SMauro Carvalho Chehab value = internal * wait1_ms;
2501173a64cbSPatrick Boettcher else
250213122f98SMauro Carvalho Chehab value = internal * wait0_ms;
2503173a64cbSPatrick Boettcher } else if (reg == 13)
250413122f98SMauro Carvalho Chehab value = internal * wait1_ms;
2505173a64cbSPatrick Boettcher else if (reg == 15)
250613122f98SMauro Carvalho Chehab value = internal * wait2_ms;
2507173a64cbSPatrick Boettcher dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2508173a64cbSPatrick Boettcher dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2509173a64cbSPatrick Boettcher }
2510173a64cbSPatrick Boettcher return value;
25119a0bf528SMauro Carvalho Chehab }
25129a0bf528SMauro Carvalho Chehab
dib8000_autosearch_start(struct dvb_frontend * fe)25139a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe)
25149a0bf528SMauro Carvalho Chehab {
25159a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
2516c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2517173a64cbSPatrick Boettcher u8 slist = 0;
2518173a64cbSPatrick Boettcher u32 value, internal = state->cfg.pll->internal;
25199a0bf528SMauro Carvalho Chehab
2520173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2521173a64cbSPatrick Boettcher internal = dib8000_read32(state, 23) / 1000;
25229a0bf528SMauro Carvalho Chehab
2523d67350f8SOlivier Grenie if ((state->revision >= 0x8002) &&
2524d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) {
2525173a64cbSPatrick Boettcher dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
2526173a64cbSPatrick Boettcher dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2527173a64cbSPatrick Boettcher
2528173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2529173a64cbSPatrick Boettcher dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2530173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2531173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2532173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2533173a64cbSPatrick Boettcher dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2534173a64cbSPatrick Boettcher
2535173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2536173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2537173a64cbSPatrick Boettcher else
2538173a64cbSPatrick Boettcher value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2539173a64cbSPatrick Boettcher
2540173a64cbSPatrick Boettcher dib8000_write_word(state, 17, 0);
2541173a64cbSPatrick Boettcher dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2542173a64cbSPatrick Boettcher dib8000_write_word(state, 19, 0);
2543173a64cbSPatrick Boettcher dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2544173a64cbSPatrick Boettcher dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2545173a64cbSPatrick Boettcher dib8000_write_word(state, 22, value & 0xffff);
2546173a64cbSPatrick Boettcher
2547173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2548173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2549173a64cbSPatrick Boettcher else
2550173a64cbSPatrick Boettcher dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2551173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2552173a64cbSPatrick Boettcher
2553173a64cbSPatrick Boettcher /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2554173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0);
2555173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0x111);
2556173a64cbSPatrick Boettcher
2557173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2558173a64cbSPatrick Boettcher dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2559173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2560d67350f8SOlivier Grenie } else if ((state->revision >= 0x8002) &&
2561d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_GUARD)) {
2562c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K;
2563c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8;
2564c82056d0SMauro Carvalho Chehab c->inversion = 0;
2565c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64;
2566c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3;
2567c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0;
2568c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13;
25699a0bf528SMauro Carvalho Chehab
2570173a64cbSPatrick Boettcher slist = 16;
2571c82056d0SMauro Carvalho Chehab c->transmission_mode = state->found_nfft;
2572173a64cbSPatrick Boettcher
2573173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1);
2574173a64cbSPatrick Boettcher
2575173a64cbSPatrick Boettcher /* set lock_mask values */
2576173a64cbSPatrick Boettcher dib8000_write_word(state, 6, 0x4);
2577173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2578173a64cbSPatrick Boettcher dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2579173a64cbSPatrick Boettcher else
2580173a64cbSPatrick Boettcher dib8000_write_word(state, 7, 0x8);
2581173a64cbSPatrick Boettcher dib8000_write_word(state, 8, 0x1000);
2582173a64cbSPatrick Boettcher
2583173a64cbSPatrick Boettcher /* set lock_mask wait time values */
2584173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2585173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2586173a64cbSPatrick Boettcher else
2587173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2588173a64cbSPatrick Boettcher
2589173a64cbSPatrick Boettcher dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2590173a64cbSPatrick Boettcher
2591173a64cbSPatrick Boettcher /* P_search_param_select = 0xf; look for the 4 different guard intervals */
2592173a64cbSPatrick Boettcher dib8000_write_word(state, 356, 0);
2593173a64cbSPatrick Boettcher dib8000_write_word(state, 357, 0xf);
2594173a64cbSPatrick Boettcher
2595173a64cbSPatrick Boettcher value = dib8000_read_word(state, 0);
2596173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2597173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2598173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (u16)value);
2599173a64cbSPatrick Boettcher } else {
2600c82056d0SMauro Carvalho Chehab c->inversion = 0;
2601c82056d0SMauro Carvalho Chehab c->layer[0].modulation = QAM_64;
2602c82056d0SMauro Carvalho Chehab c->layer[0].fec = FEC_2_3;
2603c82056d0SMauro Carvalho Chehab c->layer[0].interleaving = 0;
2604c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13;
2605c82056d0SMauro Carvalho Chehab if (!c->isdbt_sb_mode)
2606c82056d0SMauro Carvalho Chehab c->layer[0].segment_count = 13;
2607173a64cbSPatrick Boettcher
2608173a64cbSPatrick Boettcher /* choose the right list, in sb, always do everything */
2609c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) {
26109a0bf528SMauro Carvalho Chehab slist = 7;
26119a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
26129a0bf528SMauro Carvalho Chehab } else {
2613c82056d0SMauro Carvalho Chehab if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2614c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2615c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K;
2616c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8;
26179a0bf528SMauro Carvalho Chehab slist = 7;
2618173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
2619173a64cbSPatrick Boettcher } else {
2620c82056d0SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8;
26219a0bf528SMauro Carvalho Chehab slist = 3;
2622173a64cbSPatrick Boettcher }
26239a0bf528SMauro Carvalho Chehab } else {
2624c82056d0SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2625c82056d0SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K;
26269a0bf528SMauro Carvalho Chehab slist = 2;
2627173a64cbSPatrick Boettcher dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
26289a0bf528SMauro Carvalho Chehab } else
26299a0bf528SMauro Carvalho Chehab slist = 0;
26309a0bf528SMauro Carvalho Chehab }
2631173a64cbSPatrick Boettcher }
26328af16adfSMauro Carvalho Chehab dprintk("Using list for autosearch : %d\n", slist);
26339a0bf528SMauro Carvalho Chehab
2634173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, slist, 1);
26359a0bf528SMauro Carvalho Chehab
2636173a64cbSPatrick Boettcher /* set lock_mask values */
26379a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 6, 0x4);
2638173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2639173a64cbSPatrick Boettcher dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2640173a64cbSPatrick Boettcher else
26419a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 7, 0x8);
26429a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 8, 0x1000);
26439a0bf528SMauro Carvalho Chehab
2644173a64cbSPatrick Boettcher /* set lock_mask wait time values */
2645173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2646173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2647173a64cbSPatrick Boettcher else
2648173a64cbSPatrick Boettcher dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
26499a0bf528SMauro Carvalho Chehab
26509a0bf528SMauro Carvalho Chehab value = dib8000_read_word(state, 0);
26519a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2652173a64cbSPatrick Boettcher dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
26539a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 0, (u16)value);
26549a0bf528SMauro Carvalho Chehab }
26559a0bf528SMauro Carvalho Chehab return 0;
26569a0bf528SMauro Carvalho Chehab }
26579a0bf528SMauro Carvalho Chehab
dib8000_autosearch_irq(struct dvb_frontend * fe)26589a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe)
26599a0bf528SMauro Carvalho Chehab {
26609a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
26619a0bf528SMauro Carvalho Chehab u16 irq_pending = dib8000_read_word(state, 1284);
26629a0bf528SMauro Carvalho Chehab
2663d67350f8SOlivier Grenie if ((state->revision >= 0x8002) &&
2664d67350f8SOlivier Grenie (state->autosearch_state == AS_SEARCHING_FFT)) {
2665173a64cbSPatrick Boettcher if (irq_pending & 0x1) {
26668af16adfSMauro Carvalho Chehab dprintk("dib8000_autosearch_irq: max correlation result available\n");
2667173a64cbSPatrick Boettcher return 3;
2668173a64cbSPatrick Boettcher }
2669173a64cbSPatrick Boettcher } else {
2670173a64cbSPatrick Boettcher if (irq_pending & 0x1) { /* failed */
26718af16adfSMauro Carvalho Chehab dprintk("dib8000_autosearch_irq failed\n");
26729a0bf528SMauro Carvalho Chehab return 1;
26739a0bf528SMauro Carvalho Chehab }
26749a0bf528SMauro Carvalho Chehab
2675173a64cbSPatrick Boettcher if (irq_pending & 0x2) { /* succeeded */
26768af16adfSMauro Carvalho Chehab dprintk("dib8000_autosearch_irq succeeded\n");
26779a0bf528SMauro Carvalho Chehab return 2;
26789a0bf528SMauro Carvalho Chehab }
2679173a64cbSPatrick Boettcher }
26809a0bf528SMauro Carvalho Chehab
26819a0bf528SMauro Carvalho Chehab return 0; // still pending
26829a0bf528SMauro Carvalho Chehab }
26839a0bf528SMauro Carvalho Chehab
dib8000_viterbi_state(struct dib8000_state * state,u8 onoff)2684173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2685173a64cbSPatrick Boettcher {
2686173a64cbSPatrick Boettcher u16 tmp;
2687173a64cbSPatrick Boettcher
2688173a64cbSPatrick Boettcher tmp = dib8000_read_word(state, 771);
2689173a64cbSPatrick Boettcher if (onoff) /* start P_restart_chd : channel_decoder */
2690173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp & 0xfffd);
2691173a64cbSPatrick Boettcher else /* stop P_restart_chd : channel_decoder */
2692173a64cbSPatrick Boettcher dib8000_write_word(state, 771, tmp | (1<<1));
2693173a64cbSPatrick Boettcher }
2694173a64cbSPatrick Boettcher
dib8000_set_dds(struct dib8000_state * state,s32 offset_khz)2695173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2696173a64cbSPatrick Boettcher {
2697173a64cbSPatrick Boettcher s16 unit_khz_dds_val;
26987aa92c42SDan Gopstein u32 abs_offset_khz = abs(offset_khz);
2699173a64cbSPatrick Boettcher u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2700173a64cbSPatrick Boettcher u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2701173a64cbSPatrick Boettcher u8 ratio;
2702173a64cbSPatrick Boettcher
2703173a64cbSPatrick Boettcher if (state->revision == 0x8090) {
2704173a64cbSPatrick Boettcher ratio = 4;
2705173a64cbSPatrick Boettcher unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2706173a64cbSPatrick Boettcher if (offset_khz < 0)
2707173a64cbSPatrick Boettcher dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2708173a64cbSPatrick Boettcher else
2709173a64cbSPatrick Boettcher dds = (abs_offset_khz * unit_khz_dds_val);
2710173a64cbSPatrick Boettcher
2711173a64cbSPatrick Boettcher if (invert)
2712173a64cbSPatrick Boettcher dds = (1<<26) - dds;
2713173a64cbSPatrick Boettcher } else {
2714173a64cbSPatrick Boettcher ratio = 2;
2715173a64cbSPatrick Boettcher unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2716173a64cbSPatrick Boettcher
2717173a64cbSPatrick Boettcher if (offset_khz < 0)
2718173a64cbSPatrick Boettcher unit_khz_dds_val *= -1;
2719173a64cbSPatrick Boettcher
2720173a64cbSPatrick Boettcher /* IF tuner */
2721173a64cbSPatrick Boettcher if (invert)
2722173a64cbSPatrick Boettcher dds -= abs_offset_khz * unit_khz_dds_val;
2723173a64cbSPatrick Boettcher else
2724173a64cbSPatrick Boettcher dds += abs_offset_khz * unit_khz_dds_val;
2725173a64cbSPatrick Boettcher }
2726173a64cbSPatrick Boettcher
27278af16adfSMauro Carvalho Chehab dprintk("setting a DDS frequency offset of %c%dkHz\n", invert ? '-' : ' ', dds / unit_khz_dds_val);
2728173a64cbSPatrick Boettcher
2729173a64cbSPatrick Boettcher if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2730173a64cbSPatrick Boettcher /* Max dds offset is the half of the demod freq */
2731173a64cbSPatrick Boettcher dib8000_write_word(state, 26, invert);
2732173a64cbSPatrick Boettcher dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2733173a64cbSPatrick Boettcher dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2734173a64cbSPatrick Boettcher }
2735173a64cbSPatrick Boettcher }
2736173a64cbSPatrick Boettcher
dib8000_set_frequency_offset(struct dib8000_state * state)2737173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state)
2738173a64cbSPatrick Boettcher {
2739c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2740173a64cbSPatrick Boettcher int i;
2741173a64cbSPatrick Boettcher u32 current_rf;
2742173a64cbSPatrick Boettcher int total_dds_offset_khz;
2743173a64cbSPatrick Boettcher
2744173a64cbSPatrick Boettcher if (state->fe[0]->ops.tuner_ops.get_frequency)
2745173a64cbSPatrick Boettcher state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], ¤t_rf);
2746173a64cbSPatrick Boettcher else
2747c82056d0SMauro Carvalho Chehab current_rf = c->frequency;
2748173a64cbSPatrick Boettcher current_rf /= 1000;
2749c82056d0SMauro Carvalho Chehab total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
2750173a64cbSPatrick Boettcher
2751c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) {
2752c82056d0SMauro Carvalho Chehab state->subchannel = c->isdbt_sb_subchannel;
2753173a64cbSPatrick Boettcher
2754173a64cbSPatrick Boettcher i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2755c82056d0SMauro Carvalho Chehab dib8000_write_word(state, 26, c->inversion ^ i);
2756173a64cbSPatrick Boettcher
2757173a64cbSPatrick Boettcher if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2758c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0)
2759173a64cbSPatrick Boettcher dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2760173a64cbSPatrick Boettcher } else {
2761c82056d0SMauro Carvalho Chehab if ((c->inversion ^ i) == 0)
2762173a64cbSPatrick Boettcher total_dds_offset_khz *= -1;
2763173a64cbSPatrick Boettcher }
2764173a64cbSPatrick Boettcher }
2765173a64cbSPatrick Boettcher
27668af16adfSMauro Carvalho Chehab dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d\n", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz);
2767173a64cbSPatrick Boettcher
2768173a64cbSPatrick Boettcher /* apply dds offset now */
2769173a64cbSPatrick Boettcher dib8000_set_dds(state, total_dds_offset_khz);
2770173a64cbSPatrick Boettcher }
2771173a64cbSPatrick Boettcher
2772173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
27736f7ee06fSMauro Carvalho Chehab
dib8000_get_symbol_duration(struct dib8000_state * state)27746f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2775173a64cbSPatrick Boettcher {
2776c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2777173a64cbSPatrick Boettcher u16 i;
2778173a64cbSPatrick Boettcher
2779c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) {
2780173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K:
2781173a64cbSPatrick Boettcher i = 0;
2782173a64cbSPatrick Boettcher break;
2783173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K:
2784173a64cbSPatrick Boettcher i = 2;
2785173a64cbSPatrick Boettcher break;
2786173a64cbSPatrick Boettcher default:
2787173a64cbSPatrick Boettcher case TRANSMISSION_MODE_AUTO:
2788173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K:
2789173a64cbSPatrick Boettcher i = 1;
2790173a64cbSPatrick Boettcher break;
2791173a64cbSPatrick Boettcher }
2792173a64cbSPatrick Boettcher
2793c82056d0SMauro Carvalho Chehab return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
2794173a64cbSPatrick Boettcher }
2795173a64cbSPatrick Boettcher
dib8000_set_isdbt_loop_params(struct dib8000_state * state,enum param_loop_step loop_step)2796173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2797173a64cbSPatrick Boettcher {
2798c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2799173a64cbSPatrick Boettcher u16 reg_32 = 0, reg_37 = 0;
2800173a64cbSPatrick Boettcher
2801173a64cbSPatrick Boettcher switch (loop_step) {
2802173a64cbSPatrick Boettcher case LOOP_TUNE_1:
2803c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) {
2804c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) {
2805173a64cbSPatrick Boettcher reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2806173a64cbSPatrick Boettcher reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
2807173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */
2808173a64cbSPatrick Boettcher reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2809173a64cbSPatrick Boettcher reg_37 = (3 << 5) | (0 << 4) | (9 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (9-P_mode) */
2810173a64cbSPatrick Boettcher }
2811173a64cbSPatrick Boettcher } else { /* 13-seg start conf offset loop parameters */
2812173a64cbSPatrick Boettcher reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2813173a64cbSPatrick Boettcher reg_37 = (3 << 5) | (0 << 4) | (8 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
2814173a64cbSPatrick Boettcher }
2815173a64cbSPatrick Boettcher break;
2816173a64cbSPatrick Boettcher case LOOP_TUNE_2:
2817c82056d0SMauro Carvalho Chehab if (c->isdbt_sb_mode) {
2818c82056d0SMauro Carvalho Chehab if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
2819173a64cbSPatrick Boettcher reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2820173a64cbSPatrick Boettcher reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2821173a64cbSPatrick Boettcher } else { /* Sound Broadcasting mode 3 seg */
2822173a64cbSPatrick Boettcher reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2823173a64cbSPatrick Boettcher reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2824173a64cbSPatrick Boettcher }
2825173a64cbSPatrick Boettcher } else { /* 13 seg */
2826173a64cbSPatrick Boettcher reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2827173a64cbSPatrick Boettcher reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2828173a64cbSPatrick Boettcher }
2829173a64cbSPatrick Boettcher break;
2830173a64cbSPatrick Boettcher }
2831173a64cbSPatrick Boettcher dib8000_write_word(state, 32, reg_32);
2832173a64cbSPatrick Boettcher dib8000_write_word(state, 37, reg_37);
2833173a64cbSPatrick Boettcher }
2834173a64cbSPatrick Boettcher
dib8000_demod_restart(struct dib8000_state * state)2835173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state)
2836173a64cbSPatrick Boettcher {
2837173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x4000);
2838173a64cbSPatrick Boettcher dib8000_write_word(state, 770, 0x0000);
2839173a64cbSPatrick Boettcher return;
2840173a64cbSPatrick Boettcher }
2841173a64cbSPatrick Boettcher
dib8000_set_sync_wait(struct dib8000_state * state)2842173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state)
2843173a64cbSPatrick Boettcher {
2844c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2845173a64cbSPatrick Boettcher u16 sync_wait = 64;
2846173a64cbSPatrick Boettcher
2847173a64cbSPatrick Boettcher /* P_dvsy_sync_wait - reuse mode */
2848c82056d0SMauro Carvalho Chehab switch (c->transmission_mode) {
2849173a64cbSPatrick Boettcher case TRANSMISSION_MODE_8K:
2850173a64cbSPatrick Boettcher sync_wait = 256;
2851173a64cbSPatrick Boettcher break;
2852173a64cbSPatrick Boettcher case TRANSMISSION_MODE_4K:
2853173a64cbSPatrick Boettcher sync_wait = 128;
2854173a64cbSPatrick Boettcher break;
2855173a64cbSPatrick Boettcher default:
2856173a64cbSPatrick Boettcher case TRANSMISSION_MODE_2K:
2857173a64cbSPatrick Boettcher sync_wait = 64;
2858173a64cbSPatrick Boettcher break;
2859173a64cbSPatrick Boettcher }
2860173a64cbSPatrick Boettcher
2861173a64cbSPatrick Boettcher if (state->cfg.diversity_delay == 0)
2862c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2863173a64cbSPatrick Boettcher else
2864c82056d0SMauro Carvalho Chehab sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2865173a64cbSPatrick Boettcher
2866173a64cbSPatrick Boettcher dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2867173a64cbSPatrick Boettcher }
2868173a64cbSPatrick Boettcher
dib8000_get_timeout(struct dib8000_state * state,u32 delay,enum timeout_mode mode)2869d6c62b76SMauro Carvalho Chehab static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2870173a64cbSPatrick Boettcher {
2871173a64cbSPatrick Boettcher if (mode == SYMBOL_DEPENDENT_ON)
2872d6c62b76SMauro Carvalho Chehab delay *= state->symbol_duration;
2873d6c62b76SMauro Carvalho Chehab
2874d6c62b76SMauro Carvalho Chehab return jiffies + usecs_to_jiffies(delay * 100);
2875173a64cbSPatrick Boettcher }
2876173a64cbSPatrick Boettcher
dib8000_get_status(struct dvb_frontend * fe)2877173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe)
2878173a64cbSPatrick Boettcher {
2879173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv;
2880173a64cbSPatrick Boettcher return state->status;
2881173a64cbSPatrick Boettcher }
2882173a64cbSPatrick Boettcher
dib8000_get_tune_state(struct dvb_frontend * fe)2883d44913c1SMauro Carvalho Chehab static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2884173a64cbSPatrick Boettcher {
2885173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv;
2886173a64cbSPatrick Boettcher return state->tune_state;
2887173a64cbSPatrick Boettcher }
2888173a64cbSPatrick Boettcher
dib8000_set_tune_state(struct dvb_frontend * fe,enum frontend_tune_state tune_state)2889d44913c1SMauro Carvalho Chehab static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2890173a64cbSPatrick Boettcher {
2891173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv;
2892173a64cbSPatrick Boettcher
2893173a64cbSPatrick Boettcher state->tune_state = tune_state;
2894173a64cbSPatrick Boettcher return 0;
2895173a64cbSPatrick Boettcher }
2896173a64cbSPatrick Boettcher
dib8000_tune_restart_from_demod(struct dvb_frontend * fe)2897173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2898173a64cbSPatrick Boettcher {
2899173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv;
2900173a64cbSPatrick Boettcher
2901173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING;
2902173a64cbSPatrick Boettcher state->tune_state = CT_DEMOD_START;
2903173a64cbSPatrick Boettcher return 0;
2904173a64cbSPatrick Boettcher }
2905173a64cbSPatrick Boettcher
dib8000_read_lock(struct dvb_frontend * fe)2906173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe)
2907173a64cbSPatrick Boettcher {
2908173a64cbSPatrick Boettcher struct dib8000_state *state = fe->demodulator_priv;
2909173a64cbSPatrick Boettcher
2910173a64cbSPatrick Boettcher if (state->revision == 0x8090)
2911173a64cbSPatrick Boettcher return dib8000_read_word(state, 570);
2912173a64cbSPatrick Boettcher return dib8000_read_word(state, 568);
2913173a64cbSPatrick Boettcher }
2914173a64cbSPatrick Boettcher
dib8090p_init_sdram(struct dib8000_state * state)2915173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state)
2916173a64cbSPatrick Boettcher {
2917173a64cbSPatrick Boettcher u16 reg = 0;
29188af16adfSMauro Carvalho Chehab dprintk("init sdram\n");
2919173a64cbSPatrick Boettcher
2920173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 274) & 0xfff0;
2921173a64cbSPatrick Boettcher dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2922173a64cbSPatrick Boettcher
2923173a64cbSPatrick Boettcher dib8000_write_word(state, 1803, (7 << 2));
2924173a64cbSPatrick Boettcher
2925173a64cbSPatrick Boettcher reg = dib8000_read_word(state, 1280);
2926173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
2927173a64cbSPatrick Boettcher dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
2928173a64cbSPatrick Boettcher
2929173a64cbSPatrick Boettcher return 0;
2930173a64cbSPatrick Boettcher }
2931173a64cbSPatrick Boettcher
2932ad976187SMauro Carvalho Chehab /**
2933ad976187SMauro Carvalho Chehab * is_manual_mode - Check if TMCC should be used for parameters settings
2934ad976187SMauro Carvalho Chehab * @c: struct dvb_frontend_properties
2935ad976187SMauro Carvalho Chehab *
2936ad976187SMauro Carvalho Chehab * By default, TMCC table should be used for parameter settings on most
2937ad976187SMauro Carvalho Chehab * usercases. However, sometimes it is desirable to lock the demod to
2938ad976187SMauro Carvalho Chehab * use the manual parameters.
2939ad976187SMauro Carvalho Chehab *
2940ad976187SMauro Carvalho Chehab * On manual mode, the current dib8000_tune state machine is very restrict:
2941ad976187SMauro Carvalho Chehab * It requires that both per-layer and per-transponder parameters to be
2942ad976187SMauro Carvalho Chehab * properly specified, otherwise the device won't lock.
2943ad976187SMauro Carvalho Chehab *
2944ad976187SMauro Carvalho Chehab * Check if all those conditions are properly satisfied before allowing
2945ad976187SMauro Carvalho Chehab * the device to use the manual frequency lock mode.
2946ad976187SMauro Carvalho Chehab */
is_manual_mode(struct dtv_frontend_properties * c)2947ad976187SMauro Carvalho Chehab static int is_manual_mode(struct dtv_frontend_properties *c)
2948ad976187SMauro Carvalho Chehab {
2949ad976187SMauro Carvalho Chehab int i, n_segs = 0;
2950ad976187SMauro Carvalho Chehab
2951ad976187SMauro Carvalho Chehab /* Use auto mode on DVB-T compat mode */
2952ad976187SMauro Carvalho Chehab if (c->delivery_system != SYS_ISDBT)
2953ad976187SMauro Carvalho Chehab return 0;
2954ad976187SMauro Carvalho Chehab
2955ad976187SMauro Carvalho Chehab /*
2956ad976187SMauro Carvalho Chehab * Transmission mode is only detected on auto mode, currently
2957ad976187SMauro Carvalho Chehab */
2958ad976187SMauro Carvalho Chehab if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
29598af16adfSMauro Carvalho Chehab dprintk("transmission mode auto\n");
2960ad976187SMauro Carvalho Chehab return 0;
2961ad976187SMauro Carvalho Chehab }
2962ad976187SMauro Carvalho Chehab
2963ad976187SMauro Carvalho Chehab /*
2964ad976187SMauro Carvalho Chehab * Guard interval is only detected on auto mode, currently
2965ad976187SMauro Carvalho Chehab */
2966ad976187SMauro Carvalho Chehab if (c->guard_interval == GUARD_INTERVAL_AUTO) {
29678af16adfSMauro Carvalho Chehab dprintk("guard interval auto\n");
2968ad976187SMauro Carvalho Chehab return 0;
2969ad976187SMauro Carvalho Chehab }
2970ad976187SMauro Carvalho Chehab
2971ad976187SMauro Carvalho Chehab /*
2972ad976187SMauro Carvalho Chehab * If no layer is enabled, assume auto mode, as at least one
2973ad976187SMauro Carvalho Chehab * layer should be enabled
2974ad976187SMauro Carvalho Chehab */
2975ad976187SMauro Carvalho Chehab if (!c->isdbt_layer_enabled) {
29768af16adfSMauro Carvalho Chehab dprintk("no layer modulation specified\n");
2977ad976187SMauro Carvalho Chehab return 0;
2978ad976187SMauro Carvalho Chehab }
2979ad976187SMauro Carvalho Chehab
2980ad976187SMauro Carvalho Chehab /*
2981ad976187SMauro Carvalho Chehab * Check if the per-layer parameters aren't auto and
2982ad976187SMauro Carvalho Chehab * disable a layer if segment count is 0 or invalid.
2983ad976187SMauro Carvalho Chehab */
2984ad976187SMauro Carvalho Chehab for (i = 0; i < 3; i++) {
2985ad976187SMauro Carvalho Chehab if (!(c->isdbt_layer_enabled & 1 << i))
2986ad976187SMauro Carvalho Chehab continue;
2987ad976187SMauro Carvalho Chehab
2988ad976187SMauro Carvalho Chehab if ((c->layer[i].segment_count > 13) ||
2989ad976187SMauro Carvalho Chehab (c->layer[i].segment_count == 0)) {
2990ad976187SMauro Carvalho Chehab c->isdbt_layer_enabled &= ~(1 << i);
2991ad976187SMauro Carvalho Chehab continue;
2992ad976187SMauro Carvalho Chehab }
2993ad976187SMauro Carvalho Chehab
2994ad976187SMauro Carvalho Chehab n_segs += c->layer[i].segment_count;
2995ad976187SMauro Carvalho Chehab
2996ad976187SMauro Carvalho Chehab if ((c->layer[i].modulation == QAM_AUTO) ||
2997ad976187SMauro Carvalho Chehab (c->layer[i].fec == FEC_AUTO)) {
29988af16adfSMauro Carvalho Chehab dprintk("layer %c has either modulation or FEC auto\n",
2999ad976187SMauro Carvalho Chehab 'A' + i);
3000ad976187SMauro Carvalho Chehab return 0;
3001ad976187SMauro Carvalho Chehab }
3002ad976187SMauro Carvalho Chehab }
3003ad976187SMauro Carvalho Chehab
3004ad976187SMauro Carvalho Chehab /*
3005ad976187SMauro Carvalho Chehab * Userspace specified a wrong number of segments.
3006ad976187SMauro Carvalho Chehab * fallback to auto mode.
3007ad976187SMauro Carvalho Chehab */
3008ad976187SMauro Carvalho Chehab if (n_segs == 0 || n_segs > 13) {
30098af16adfSMauro Carvalho Chehab dprintk("number of segments is invalid\n");
3010ad976187SMauro Carvalho Chehab return 0;
3011ad976187SMauro Carvalho Chehab }
3012ad976187SMauro Carvalho Chehab
3013ad976187SMauro Carvalho Chehab /* Everything looks ok for manual mode */
3014ad976187SMauro Carvalho Chehab return 1;
3015ad976187SMauro Carvalho Chehab }
3016ad976187SMauro Carvalho Chehab
dib8000_tune(struct dvb_frontend * fe)30179a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe)
30189a0bf528SMauro Carvalho Chehab {
30199a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
3020c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3021173a64cbSPatrick Boettcher enum frontend_tune_state *tune_state = &state->tune_state;
30229a0bf528SMauro Carvalho Chehab
3023173a64cbSPatrick Boettcher u16 locks, deeper_interleaver = 0, i;
3024173a64cbSPatrick Boettcher int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
30259a0bf528SMauro Carvalho Chehab
3026d6c62b76SMauro Carvalho Chehab unsigned long *timeout = &state->timeout;
3027d6c62b76SMauro Carvalho Chehab unsigned long now = jiffies;
30288db11aebSMauro Carvalho Chehab u16 init_prbs;
3029173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3030173a64cbSPatrick Boettcher u16 agc1, agc2;
3031173a64cbSPatrick Boettcher #endif
30329a0bf528SMauro Carvalho Chehab
3033173a64cbSPatrick Boettcher u32 corm[4] = {0, 0, 0, 0};
3034173a64cbSPatrick Boettcher u8 find_index, max_value;
30359a0bf528SMauro Carvalho Chehab
3036173a64cbSPatrick Boettcher #if 0
3037173a64cbSPatrick Boettcher if (*tune_state < CT_DEMOD_STOP)
30388af16adfSMauro Carvalho Chehab dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu\n",
3039d6c62b76SMauro Carvalho Chehab state->channel_parameters_set, *tune_state, state->autosearch_state, now);
3040173a64cbSPatrick Boettcher #endif
30419a0bf528SMauro Carvalho Chehab
3042173a64cbSPatrick Boettcher switch (*tune_state) {
3043173a64cbSPatrick Boettcher case CT_DEMOD_START: /* 30 */
30446ef06e78SMauro Carvalho Chehab dib8000_reset_stats(fe);
30456ef06e78SMauro Carvalho Chehab
3046173a64cbSPatrick Boettcher if (state->revision == 0x8090)
3047173a64cbSPatrick Boettcher dib8090p_init_sdram(state);
3048173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_PENDING;
3049ad976187SMauro Carvalho Chehab state->channel_parameters_set = is_manual_mode(c);
3050ad976187SMauro Carvalho Chehab
30518af16adfSMauro Carvalho Chehab dprintk("Tuning channel on %s search mode\n",
3052ad976187SMauro Carvalho Chehab state->channel_parameters_set ? "manual" : "auto");
30539a0bf528SMauro Carvalho Chehab
3054173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 0); /* force chan dec in restart */
30559a0bf528SMauro Carvalho Chehab
3056ad976187SMauro Carvalho Chehab /* Layer monitor */
3057173a64cbSPatrick Boettcher dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
3058173a64cbSPatrick Boettcher
3059173a64cbSPatrick Boettcher dib8000_set_frequency_offset(state);
3060c82056d0SMauro Carvalho Chehab dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
3061173a64cbSPatrick Boettcher
3062173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
3063173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3064173a64cbSPatrick Boettcher if (state->revision != 0x8090) {
3065173a64cbSPatrick Boettcher state->agc1_max = dib8000_read_word(state, 108);
3066173a64cbSPatrick Boettcher state->agc1_min = dib8000_read_word(state, 109);
3067173a64cbSPatrick Boettcher state->agc2_max = dib8000_read_word(state, 110);
3068173a64cbSPatrick Boettcher state->agc2_min = dib8000_read_word(state, 111);
3069173a64cbSPatrick Boettcher agc1 = dib8000_read_word(state, 388);
3070173a64cbSPatrick Boettcher agc2 = dib8000_read_word(state, 389);
3071173a64cbSPatrick Boettcher dib8000_write_word(state, 108, agc1);
3072173a64cbSPatrick Boettcher dib8000_write_word(state, 109, agc1);
3073173a64cbSPatrick Boettcher dib8000_write_word(state, 110, agc2);
3074173a64cbSPatrick Boettcher dib8000_write_word(state, 111, agc2);
3075173a64cbSPatrick Boettcher }
3076173a64cbSPatrick Boettcher #endif
3077173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_FFT;
3078173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_AUTO;
3079173a64cbSPatrick Boettcher state->found_guard = GUARD_INTERVAL_AUTO;
3080173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT;
3081173a64cbSPatrick Boettcher } else { /* we already know the channel struct so TUNE only ! */
3082173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE;
3083173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3;
3084173a64cbSPatrick Boettcher }
3085173a64cbSPatrick Boettcher state->symbol_duration = dib8000_get_symbol_duration(state);
3086173a64cbSPatrick Boettcher break;
3087173a64cbSPatrick Boettcher
3088173a64cbSPatrick Boettcher case CT_DEMOD_SEARCH_NEXT: /* 51 */
3089173a64cbSPatrick Boettcher dib8000_autosearch_start(fe);
3090173a64cbSPatrick Boettcher if (state->revision == 0x8090)
3091173a64cbSPatrick Boettcher ret = 50;
3092173a64cbSPatrick Boettcher else
3093173a64cbSPatrick Boettcher ret = 15;
3094173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_1;
3095173a64cbSPatrick Boettcher break;
3096173a64cbSPatrick Boettcher
3097173a64cbSPatrick Boettcher case CT_DEMOD_STEP_1: /* 31 */
3098173a64cbSPatrick Boettcher switch (dib8000_autosearch_irq(fe)) {
3099173a64cbSPatrick Boettcher case 1: /* fail */
3100173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED;
3101173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE;
3102173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */
3103173a64cbSPatrick Boettcher break;
3104868c9a17SMauro Carvalho Chehab case 2: /* Success */
3105173a64cbSPatrick Boettcher state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3106173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3;
3107173a64cbSPatrick Boettcher if (state->autosearch_state == AS_SEARCHING_GUARD)
3108173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2;
3109173a64cbSPatrick Boettcher else
3110173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE;
3111173a64cbSPatrick Boettcher break;
3112173a64cbSPatrick Boettcher case 3: /* Autosearch FFT max correlation endded */
3113173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_2;
3114173a64cbSPatrick Boettcher break;
3115173a64cbSPatrick Boettcher }
3116173a64cbSPatrick Boettcher break;
3117173a64cbSPatrick Boettcher
3118173a64cbSPatrick Boettcher case CT_DEMOD_STEP_2:
3119173a64cbSPatrick Boettcher switch (state->autosearch_state) {
3120173a64cbSPatrick Boettcher case AS_SEARCHING_FFT:
3121173a64cbSPatrick Boettcher /* searching for the correct FFT */
3122173a64cbSPatrick Boettcher if (state->revision == 0x8090) {
3123173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3124173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3125173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3126173a64cbSPatrick Boettcher } else {
3127173a64cbSPatrick Boettcher corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3128173a64cbSPatrick Boettcher corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3129173a64cbSPatrick Boettcher corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3130173a64cbSPatrick Boettcher }
31318af16adfSMauro Carvalho Chehab /* dprintk("corm fft: %u %u %u\n", corm[0], corm[1], corm[2]); */
3132173a64cbSPatrick Boettcher
3133173a64cbSPatrick Boettcher max_value = 0;
3134173a64cbSPatrick Boettcher for (find_index = 1 ; find_index < 3 ; find_index++) {
3135173a64cbSPatrick Boettcher if (corm[max_value] < corm[find_index])
3136173a64cbSPatrick Boettcher max_value = find_index ;
31379a0bf528SMauro Carvalho Chehab }
31389a0bf528SMauro Carvalho Chehab
3139173a64cbSPatrick Boettcher switch (max_value) {
3140173a64cbSPatrick Boettcher case 0:
3141173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_2K;
3142173a64cbSPatrick Boettcher break;
3143173a64cbSPatrick Boettcher case 1:
3144173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_4K;
3145173a64cbSPatrick Boettcher break;
3146173a64cbSPatrick Boettcher case 2:
3147173a64cbSPatrick Boettcher default:
3148173a64cbSPatrick Boettcher state->found_nfft = TRANSMISSION_MODE_8K;
3149173a64cbSPatrick Boettcher break;
3150173a64cbSPatrick Boettcher }
31518af16adfSMauro Carvalho Chehab /* dprintk("Autosearch FFT has found Mode %d\n", max_value + 1); */
3152173a64cbSPatrick Boettcher
3153173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_SEARCH_NEXT;
3154173a64cbSPatrick Boettcher state->autosearch_state = AS_SEARCHING_GUARD;
3155173a64cbSPatrick Boettcher if (state->revision == 0x8090)
3156173a64cbSPatrick Boettcher ret = 50;
3157173a64cbSPatrick Boettcher else
3158173a64cbSPatrick Boettcher ret = 10;
3159173a64cbSPatrick Boettcher break;
3160173a64cbSPatrick Boettcher case AS_SEARCHING_GUARD:
3161173a64cbSPatrick Boettcher /* searching for the correct guard interval */
3162173a64cbSPatrick Boettcher if (state->revision == 0x8090)
3163173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 572) & 0x3;
3164173a64cbSPatrick Boettcher else
3165173a64cbSPatrick Boettcher state->found_guard = dib8000_read_word(state, 570) & 0x3;
31668af16adfSMauro Carvalho Chehab /* dprintk("guard interval found=%i\n", state->found_guard); */
3167173a64cbSPatrick Boettcher
3168173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_3;
3169173a64cbSPatrick Boettcher break;
3170173a64cbSPatrick Boettcher default:
3171173a64cbSPatrick Boettcher /* the demod should never be in this state */
3172173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED;
3173173a64cbSPatrick Boettcher state->autosearch_state = AS_DONE;
3174173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here */
3175173a64cbSPatrick Boettcher break;
3176173a64cbSPatrick Boettcher }
3177173a64cbSPatrick Boettcher break;
3178173a64cbSPatrick Boettcher
3179173a64cbSPatrick Boettcher case CT_DEMOD_STEP_3: /* 33 */
3180173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3181173a64cbSPatrick Boettcher dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3182173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_4;
3183173a64cbSPatrick Boettcher break;
3184173a64cbSPatrick Boettcher
3185173a64cbSPatrick Boettcher case CT_DEMOD_STEP_4: /* (34) */
3186173a64cbSPatrick Boettcher dib8000_demod_restart(state);
3187173a64cbSPatrick Boettcher
3188173a64cbSPatrick Boettcher dib8000_set_sync_wait(state);
3189173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3190173a64cbSPatrick Boettcher
3191173a64cbSPatrick Boettcher locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
319239c1cb2bSJonathan McCrohan /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3193173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3194173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_5;
3195173a64cbSPatrick Boettcher break;
3196173a64cbSPatrick Boettcher
3197173a64cbSPatrick Boettcher case CT_DEMOD_STEP_5: /* (35) */
3198173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe);
3199173a64cbSPatrick Boettcher if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3200173a64cbSPatrick Boettcher dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3201173a64cbSPatrick Boettcher if (!state->differential_constellation) {
3202173a64cbSPatrick Boettcher /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3203173a64cbSPatrick Boettcher *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3204173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_7;
3205173a64cbSPatrick Boettcher } else {
3206173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8;
3207173a64cbSPatrick Boettcher }
3208d6c62b76SMauro Carvalho Chehab } else if (time_after(now, *timeout)) {
3209173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3210173a64cbSPatrick Boettcher }
3211173a64cbSPatrick Boettcher break;
3212173a64cbSPatrick Boettcher
3213173a64cbSPatrick Boettcher case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
3214173a64cbSPatrick Boettcher if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3215d063ddfbSJason Wang /* if there is a diversity fe in input and this fe is has not already failed : wait here until this fe has succeeded or failed */
3216173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3217173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3218868c9a17SMauro Carvalho Chehab else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failed also, break the current one */
3219173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3220173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3221173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3222173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED;
3223173a64cbSPatrick Boettcher }
3224173a64cbSPatrick Boettcher } else {
3225173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3226173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3227173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3228173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED;
3229173a64cbSPatrick Boettcher }
3230173a64cbSPatrick Boettcher break;
3231173a64cbSPatrick Boettcher
3232173a64cbSPatrick Boettcher case CT_DEMOD_STEP_7: /* 37 */
3233173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe);
3234173a64cbSPatrick Boettcher if (locks & (1<<10)) { /* lmod4_lock */
3235173a64cbSPatrick Boettcher ret = 14; /* wait for 14 symbols */
3236173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_8;
3237d6c62b76SMauro Carvalho Chehab } else if (time_after(now, *timeout))
3238173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3239173a64cbSPatrick Boettcher break;
3240173a64cbSPatrick Boettcher
3241173a64cbSPatrick Boettcher case CT_DEMOD_STEP_8: /* 38 */
3242173a64cbSPatrick Boettcher dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3243173a64cbSPatrick Boettcher dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3244173a64cbSPatrick Boettcher
3245173a64cbSPatrick Boettcher /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3246746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode
3247746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14
3248746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) {
3249173a64cbSPatrick Boettcher state->subchannel = 0;
3250173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11;
3251173a64cbSPatrick Boettcher } else {
3252173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9;
3253173a64cbSPatrick Boettcher state->status = FE_STATUS_LOCKED;
3254173a64cbSPatrick Boettcher }
3255173a64cbSPatrick Boettcher break;
3256173a64cbSPatrick Boettcher
3257173a64cbSPatrick Boettcher case CT_DEMOD_STEP_9: /* 39 */
3258173a64cbSPatrick Boettcher if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
325939c1cb2bSJonathan McCrohan /* defines timeout for mpeg lock depending on interleaver length of longest layer */
3260173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) {
3261c82056d0SMauro Carvalho Chehab if (c->layer[i].interleaving >= deeper_interleaver) {
32628af16adfSMauro Carvalho Chehab dprintk("layer%i: time interleaver = %d\n", i, c->layer[i].interleaving);
3263c82056d0SMauro Carvalho Chehab if (c->layer[i].segment_count > 0) { /* valid layer */
3264c82056d0SMauro Carvalho Chehab deeper_interleaver = c->layer[0].interleaving;
3265173a64cbSPatrick Boettcher state->longest_intlv_layer = i;
3266173a64cbSPatrick Boettcher }
3267173a64cbSPatrick Boettcher }
3268173a64cbSPatrick Boettcher }
3269173a64cbSPatrick Boettcher
3270173a64cbSPatrick Boettcher if (deeper_interleaver == 0)
3271173a64cbSPatrick Boettcher locks = 2; /* locks is the tmp local variable name */
3272173a64cbSPatrick Boettcher else if (deeper_interleaver == 3)
3273173a64cbSPatrick Boettcher locks = 8;
3274173a64cbSPatrick Boettcher else
3275173a64cbSPatrick Boettcher locks = 2 * deeper_interleaver;
3276173a64cbSPatrick Boettcher
3277173a64cbSPatrick Boettcher if (state->diversity_onoff != 0) /* because of diversity sync */
3278173a64cbSPatrick Boettcher locks *= 2;
3279173a64cbSPatrick Boettcher
3280d6c62b76SMauro Carvalho Chehab *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
32818af16adfSMauro Carvalho Chehab dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld\n",
3282d6c62b76SMauro Carvalho Chehab deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3283173a64cbSPatrick Boettcher
3284173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_10;
3285173a64cbSPatrick Boettcher } else
3286173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP;
3287173a64cbSPatrick Boettcher break;
3288173a64cbSPatrick Boettcher
3289173a64cbSPatrick Boettcher case CT_DEMOD_STEP_10: /* 40 */
3290173a64cbSPatrick Boettcher locks = dib8000_read_lock(fe);
3291173a64cbSPatrick Boettcher if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
32928af16adfSMauro Carvalho Chehab dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s\n",
32933c0d394eSMauro Carvalho Chehab c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32943c0d394eSMauro Carvalho Chehab c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32953c0d394eSMauro Carvalho Chehab c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3296746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode
3297746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14
3298746f7ae0SMauro Carvalho Chehab && !state->differential_constellation)
3299173a64cbSPatrick Boettcher /* signal to the upper layer, that there was a channel found and the parameters can be read */
3300173a64cbSPatrick Boettcher state->status = FE_STATUS_DEMOD_SUCCESS;
3301173a64cbSPatrick Boettcher else
3302173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED;
3303173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP;
3304d6c62b76SMauro Carvalho Chehab } else if (time_after(now, *timeout)) {
3305746f7ae0SMauro Carvalho Chehab if (c->isdbt_sb_mode
3306746f7ae0SMauro Carvalho Chehab && c->isdbt_sb_subchannel < 14
3307746f7ae0SMauro Carvalho Chehab && !state->differential_constellation) { /* continue to try init prbs autosearch */
3308173a64cbSPatrick Boettcher state->subchannel += 3;
3309173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_11;
3310173a64cbSPatrick Boettcher } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
3311173a64cbSPatrick Boettcher if (locks & (0x7 << 5)) {
33128af16adfSMauro Carvalho Chehab dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s\n",
33133c0d394eSMauro Carvalho Chehab jiffies_to_msecs(now - *timeout),
33143c0d394eSMauro Carvalho Chehab c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
33153c0d394eSMauro Carvalho Chehab c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
33163c0d394eSMauro Carvalho Chehab c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
33173c0d394eSMauro Carvalho Chehab
3318173a64cbSPatrick Boettcher state->status = FE_STATUS_DATA_LOCKED;
3319173a64cbSPatrick Boettcher } else
3320173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED;
3321173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP;
3322173a64cbSPatrick Boettcher }
3323173a64cbSPatrick Boettcher }
3324173a64cbSPatrick Boettcher break;
3325173a64cbSPatrick Boettcher
3326173a64cbSPatrick Boettcher case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
33278db11aebSMauro Carvalho Chehab init_prbs = dib8000_get_init_prbs(state, state->subchannel);
33288db11aebSMauro Carvalho Chehab
33298db11aebSMauro Carvalho Chehab if (init_prbs) {
33308db11aebSMauro Carvalho Chehab dib8000_set_subchannel_prbs(state, init_prbs);
3331173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STEP_9;
3332173a64cbSPatrick Boettcher } else {
3333173a64cbSPatrick Boettcher *tune_state = CT_DEMOD_STOP;
3334173a64cbSPatrick Boettcher state->status = FE_STATUS_TUNE_FAILED;
3335173a64cbSPatrick Boettcher }
3336173a64cbSPatrick Boettcher break;
3337173a64cbSPatrick Boettcher
3338173a64cbSPatrick Boettcher default:
3339173a64cbSPatrick Boettcher break;
3340173a64cbSPatrick Boettcher }
3341173a64cbSPatrick Boettcher
3342173a64cbSPatrick Boettcher /* tuning is finished - cleanup the demod */
3343173a64cbSPatrick Boettcher switch (*tune_state) {
3344173a64cbSPatrick Boettcher case CT_DEMOD_STOP: /* (42) */
3345173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3346173a64cbSPatrick Boettcher if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3347173a64cbSPatrick Boettcher dib8000_write_word(state, 108, state->agc1_max);
3348173a64cbSPatrick Boettcher dib8000_write_word(state, 109, state->agc1_min);
3349173a64cbSPatrick Boettcher dib8000_write_word(state, 110, state->agc2_max);
3350173a64cbSPatrick Boettcher dib8000_write_word(state, 111, state->agc2_min);
3351173a64cbSPatrick Boettcher state->agc1_max = 0;
3352173a64cbSPatrick Boettcher state->agc1_min = 0;
3353173a64cbSPatrick Boettcher state->agc2_max = 0;
3354173a64cbSPatrick Boettcher state->agc2_min = 0;
3355173a64cbSPatrick Boettcher }
3356173a64cbSPatrick Boettcher #endif
3357d6c62b76SMauro Carvalho Chehab ret = 0;
3358173a64cbSPatrick Boettcher break;
3359173a64cbSPatrick Boettcher default:
3360173a64cbSPatrick Boettcher break;
3361173a64cbSPatrick Boettcher }
3362173a64cbSPatrick Boettcher
3363173a64cbSPatrick Boettcher if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3364173a64cbSPatrick Boettcher return ret * state->symbol_duration;
3365173a64cbSPatrick Boettcher if ((ret > 0) && (ret < state->symbol_duration))
3366173a64cbSPatrick Boettcher return state->symbol_duration; /* at least one symbol */
33679a0bf528SMauro Carvalho Chehab return ret;
33689a0bf528SMauro Carvalho Chehab }
33699a0bf528SMauro Carvalho Chehab
dib8000_wakeup(struct dvb_frontend * fe)33709a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe)
33719a0bf528SMauro Carvalho Chehab {
33729a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
33739a0bf528SMauro Carvalho Chehab u8 index_frontend;
33749a0bf528SMauro Carvalho Chehab int ret;
33759a0bf528SMauro Carvalho Chehab
33769a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_ALL);
33779a0bf528SMauro Carvalho Chehab dib8000_set_adc_state(state, DIBX000_ADC_ON);
33789a0bf528SMauro Carvalho Chehab if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
33798af16adfSMauro Carvalho Chehab dprintk("could not start Slow ADC\n");
33809a0bf528SMauro Carvalho Chehab
3381173a64cbSPatrick Boettcher if (state->revision == 0x8090)
33829a0bf528SMauro Carvalho Chehab dib8000_sad_calib(state);
33839a0bf528SMauro Carvalho Chehab
33849a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33859a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
33869a0bf528SMauro Carvalho Chehab if (ret < 0)
33879a0bf528SMauro Carvalho Chehab return ret;
33889a0bf528SMauro Carvalho Chehab }
33899a0bf528SMauro Carvalho Chehab
33909a0bf528SMauro Carvalho Chehab return 0;
33919a0bf528SMauro Carvalho Chehab }
33929a0bf528SMauro Carvalho Chehab
dib8000_sleep(struct dvb_frontend * fe)33939a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe)
33949a0bf528SMauro Carvalho Chehab {
33959a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
33969a0bf528SMauro Carvalho Chehab u8 index_frontend;
33979a0bf528SMauro Carvalho Chehab int ret;
33989a0bf528SMauro Carvalho Chehab
33999a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34009a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
34019a0bf528SMauro Carvalho Chehab if (ret < 0)
34029a0bf528SMauro Carvalho Chehab return ret;
34039a0bf528SMauro Carvalho Chehab }
34049a0bf528SMauro Carvalho Chehab
34059a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
34069a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
34079a0bf528SMauro Carvalho Chehab dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
34089a0bf528SMauro Carvalho Chehab return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
34099a0bf528SMauro Carvalho Chehab }
34109a0bf528SMauro Carvalho Chehab
34110df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat);
341270315b3eSMauro Carvalho Chehab
dib8000_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * c)34137e3e68bcSMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe,
34147e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *c)
34159a0bf528SMauro Carvalho Chehab {
34169a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
34179a0bf528SMauro Carvalho Chehab u16 i, val = 0;
34180df289a2SMauro Carvalho Chehab enum fe_status stat = 0;
34199a0bf528SMauro Carvalho Chehab u8 index_frontend, sub_index_frontend;
34209a0bf528SMauro Carvalho Chehab
34217e3e68bcSMauro Carvalho Chehab c->bandwidth_hz = 6000000;
34229a0bf528SMauro Carvalho Chehab
342370315b3eSMauro Carvalho Chehab /*
342470315b3eSMauro Carvalho Chehab * If called to early, get_frontend makes dib8000_tune to either
342570315b3eSMauro Carvalho Chehab * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
342670315b3eSMauro Carvalho Chehab * So, let's just return if frontend 0 has not locked.
342770315b3eSMauro Carvalho Chehab */
342870315b3eSMauro Carvalho Chehab dib8000_read_status(fe, &stat);
342970315b3eSMauro Carvalho Chehab if (!(stat & FE_HAS_SYNC))
343070315b3eSMauro Carvalho Chehab return 0;
343170315b3eSMauro Carvalho Chehab
34328af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: TMCC lock\n");
34339a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34349a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
34359a0bf528SMauro Carvalho Chehab if (stat&FE_HAS_SYNC) {
34368af16adfSMauro Carvalho Chehab dprintk("TMCC lock on the slave%i\n", index_frontend);
34379a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */
34387e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
34399a0bf528SMauro Carvalho Chehab for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
34409a0bf528SMauro Carvalho Chehab if (sub_index_frontend != index_frontend) {
34419a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
34429a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
34439a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
34449a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
34459a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
34469a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) {
34479a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
34489a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
34499a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
34509a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
34519a0bf528SMauro Carvalho Chehab }
34529a0bf528SMauro Carvalho Chehab }
34539a0bf528SMauro Carvalho Chehab }
34549a0bf528SMauro Carvalho Chehab return 0;
34559a0bf528SMauro Carvalho Chehab }
34569a0bf528SMauro Carvalho Chehab }
34579a0bf528SMauro Carvalho Chehab
34587e3e68bcSMauro Carvalho Chehab c->isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
34599a0bf528SMauro Carvalho Chehab
34609a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090)
34619a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 572);
34629a0bf528SMauro Carvalho Chehab else
34639a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 570);
34647e3e68bcSMauro Carvalho Chehab c->inversion = (val & 0x40) >> 6;
34659a0bf528SMauro Carvalho Chehab switch ((val & 0x30) >> 4) {
34669a0bf528SMauro Carvalho Chehab case 1:
34677e3e68bcSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_2K;
34688af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: transmission mode 2K\n");
34699a0bf528SMauro Carvalho Chehab break;
34707fec1c80SMauro Carvalho Chehab case 2:
34717e3e68bcSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_4K;
34728af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: transmission mode 4K\n");
34737fec1c80SMauro Carvalho Chehab break;
34749a0bf528SMauro Carvalho Chehab case 3:
34759a0bf528SMauro Carvalho Chehab default:
34767e3e68bcSMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K;
34778af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: transmission mode 8K\n");
34789a0bf528SMauro Carvalho Chehab break;
34799a0bf528SMauro Carvalho Chehab }
34809a0bf528SMauro Carvalho Chehab
34819a0bf528SMauro Carvalho Chehab switch (val & 0x3) {
34829a0bf528SMauro Carvalho Chehab case 0:
34837e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_32;
34848af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/32\n");
34859a0bf528SMauro Carvalho Chehab break;
34869a0bf528SMauro Carvalho Chehab case 1:
34877e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_16;
34888af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/16\n");
34899a0bf528SMauro Carvalho Chehab break;
34909a0bf528SMauro Carvalho Chehab case 2:
34918af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/8\n");
34927e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8;
34939a0bf528SMauro Carvalho Chehab break;
34949a0bf528SMauro Carvalho Chehab case 3:
34958af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Guard Interval = 1/4\n");
34967e3e68bcSMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_4;
34979a0bf528SMauro Carvalho Chehab break;
34989a0bf528SMauro Carvalho Chehab }
34999a0bf528SMauro Carvalho Chehab
35009a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 505);
35017e3e68bcSMauro Carvalho Chehab c->isdbt_partial_reception = val & 1;
35028af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: partial_reception = %d\n", c->isdbt_partial_reception);
35039a0bf528SMauro Carvalho Chehab
35049a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) {
3505ecc31d55SMauro Carvalho Chehab int show;
3506ecc31d55SMauro Carvalho Chehab
3507ecc31d55SMauro Carvalho Chehab val = dib8000_read_word(state, 493 + i) & 0x0f;
35087e3e68bcSMauro Carvalho Chehab c->layer[i].segment_count = val;
3509ecc31d55SMauro Carvalho Chehab
3510ecc31d55SMauro Carvalho Chehab if (val == 0 || val > 13)
3511ecc31d55SMauro Carvalho Chehab show = 0;
3512ecc31d55SMauro Carvalho Chehab else
3513ecc31d55SMauro Carvalho Chehab show = 1;
3514ecc31d55SMauro Carvalho Chehab
3515ecc31d55SMauro Carvalho Chehab if (show)
35168af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d segments = %d\n",
35177e3e68bcSMauro Carvalho Chehab i, c->layer[i].segment_count);
35189a0bf528SMauro Carvalho Chehab
351951fea113SMauro Carvalho Chehab val = dib8000_read_word(state, 499 + i) & 0x3;
352051fea113SMauro Carvalho Chehab /* Interleaving can be 0, 1, 2 or 4 */
352151fea113SMauro Carvalho Chehab if (val == 3)
352251fea113SMauro Carvalho Chehab val = 4;
35237e3e68bcSMauro Carvalho Chehab c->layer[i].interleaving = val;
3524ecc31d55SMauro Carvalho Chehab if (show)
35258af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d time_intlv = %d\n",
35267e3e68bcSMauro Carvalho Chehab i, c->layer[i].interleaving);
35279a0bf528SMauro Carvalho Chehab
35289a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 481 + i);
35299a0bf528SMauro Carvalho Chehab switch (val & 0x7) {
35309a0bf528SMauro Carvalho Chehab case 1:
35317e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_1_2;
3532ecc31d55SMauro Carvalho Chehab if (show)
35338af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2\n", i);
35349a0bf528SMauro Carvalho Chehab break;
35359a0bf528SMauro Carvalho Chehab case 2:
35367e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_2_3;
3537ecc31d55SMauro Carvalho Chehab if (show)
35388af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3\n", i);
35399a0bf528SMauro Carvalho Chehab break;
35409a0bf528SMauro Carvalho Chehab case 3:
35417e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_3_4;
3542ecc31d55SMauro Carvalho Chehab if (show)
35438af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4\n", i);
35449a0bf528SMauro Carvalho Chehab break;
35459a0bf528SMauro Carvalho Chehab case 5:
35467e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_5_6;
3547ecc31d55SMauro Carvalho Chehab if (show)
35488af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6\n", i);
35499a0bf528SMauro Carvalho Chehab break;
35509a0bf528SMauro Carvalho Chehab default:
35517e3e68bcSMauro Carvalho Chehab c->layer[i].fec = FEC_7_8;
3552ecc31d55SMauro Carvalho Chehab if (show)
35538af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8\n", i);
35549a0bf528SMauro Carvalho Chehab break;
35559a0bf528SMauro Carvalho Chehab }
35569a0bf528SMauro Carvalho Chehab
35579a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 487 + i);
35589a0bf528SMauro Carvalho Chehab switch (val & 0x3) {
35599a0bf528SMauro Carvalho Chehab case 0:
35607e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = DQPSK;
3561ecc31d55SMauro Carvalho Chehab if (show)
35628af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d DQPSK\n", i);
35639a0bf528SMauro Carvalho Chehab break;
35649a0bf528SMauro Carvalho Chehab case 1:
35657e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = QPSK;
3566ecc31d55SMauro Carvalho Chehab if (show)
35678af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d QPSK\n", i);
35689a0bf528SMauro Carvalho Chehab break;
35699a0bf528SMauro Carvalho Chehab case 2:
35707e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = QAM_16;
3571ecc31d55SMauro Carvalho Chehab if (show)
35728af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d QAM16\n", i);
35739a0bf528SMauro Carvalho Chehab break;
35749a0bf528SMauro Carvalho Chehab case 3:
35759a0bf528SMauro Carvalho Chehab default:
35767e3e68bcSMauro Carvalho Chehab c->layer[i].modulation = QAM_64;
3577ecc31d55SMauro Carvalho Chehab if (show)
35788af16adfSMauro Carvalho Chehab dprintk("dib8000_get_frontend: Layer %d QAM64\n", i);
35799a0bf528SMauro Carvalho Chehab break;
35809a0bf528SMauro Carvalho Chehab }
35819a0bf528SMauro Carvalho Chehab }
35829a0bf528SMauro Carvalho Chehab
35839a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */
35849a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35857e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode;
35867e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
35877e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
35887e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
35897e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception;
35909a0bf528SMauro Carvalho Chehab for (i = 0; i < 3; i++) {
35917e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count;
35927e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving;
35937e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec;
35947e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation;
35959a0bf528SMauro Carvalho Chehab }
35969a0bf528SMauro Carvalho Chehab }
35979a0bf528SMauro Carvalho Chehab return 0;
35989a0bf528SMauro Carvalho Chehab }
35999a0bf528SMauro Carvalho Chehab
dib8000_set_frontend(struct dvb_frontend * fe)36009a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe)
36019a0bf528SMauro Carvalho Chehab {
36029a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
3603c82056d0SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3604d6c62b76SMauro Carvalho Chehab int l, i, active, time, time_slave = 0;
3605173a64cbSPatrick Boettcher u8 exit_condition, index_frontend;
3606d6c62b76SMauro Carvalho Chehab unsigned long delay, callback_time;
36079a0bf528SMauro Carvalho Chehab
3608c82056d0SMauro Carvalho Chehab if (c->frequency == 0) {
36098af16adfSMauro Carvalho Chehab dprintk("dib8000: must at least specify frequency\n");
36109a0bf528SMauro Carvalho Chehab return 0;
36119a0bf528SMauro Carvalho Chehab }
36129a0bf528SMauro Carvalho Chehab
3613c82056d0SMauro Carvalho Chehab if (c->bandwidth_hz == 0) {
36148af16adfSMauro Carvalho Chehab dprintk("dib8000: no bandwidth specified, set to default\n");
3615c82056d0SMauro Carvalho Chehab c->bandwidth_hz = 6000000;
36169a0bf528SMauro Carvalho Chehab }
36179a0bf528SMauro Carvalho Chehab
36189a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36199a0bf528SMauro Carvalho Chehab /* synchronization of the cache */
36209a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
36219a0bf528SMauro Carvalho Chehab memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
36229a0bf528SMauro Carvalho Chehab
3623173a64cbSPatrick Boettcher /* set output mode and diversity input */
3624173a64cbSPatrick Boettcher if (state->revision != 0x8090) {
3625173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend], 1);
3626173a64cbSPatrick Boettcher if (index_frontend != 0)
36279a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[index_frontend],
3628173a64cbSPatrick Boettcher OUTMODE_DIVERSITY);
36299a0bf528SMauro Carvalho Chehab else
3630173a64cbSPatrick Boettcher dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3631173a64cbSPatrick Boettcher } else {
3632173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3633173a64cbSPatrick Boettcher if (index_frontend != 0)
36349a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[index_frontend],
3635173a64cbSPatrick Boettcher OUTMODE_DIVERSITY);
3636173a64cbSPatrick Boettcher else
3637173a64cbSPatrick Boettcher dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3638173a64cbSPatrick Boettcher }
3639173a64cbSPatrick Boettcher
3640173a64cbSPatrick Boettcher /* tune the tuner */
36419a0bf528SMauro Carvalho Chehab if (state->fe[index_frontend]->ops.tuner_ops.set_params)
36429a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
36439a0bf528SMauro Carvalho Chehab
36449a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
36459a0bf528SMauro Carvalho Chehab }
36469a0bf528SMauro Carvalho Chehab
3647173a64cbSPatrick Boettcher /* turn off the diversity of the last chip */
3648173a64cbSPatrick Boettcher if (state->revision != 0x8090)
3649173a64cbSPatrick Boettcher dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3650173a64cbSPatrick Boettcher else
3651173a64cbSPatrick Boettcher dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3652173a64cbSPatrick Boettcher
36539a0bf528SMauro Carvalho Chehab /* start up the AGC */
36549a0bf528SMauro Carvalho Chehab do {
36559a0bf528SMauro Carvalho Chehab time = dib8000_agc_startup(state->fe[0]);
36569a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36579a0bf528SMauro Carvalho Chehab time_slave = dib8000_agc_startup(state->fe[index_frontend]);
3658d6c62b76SMauro Carvalho Chehab if (time == 0)
36599a0bf528SMauro Carvalho Chehab time = time_slave;
3660d6c62b76SMauro Carvalho Chehab else if ((time_slave != 0) && (time_slave > time))
36619a0bf528SMauro Carvalho Chehab time = time_slave;
36629a0bf528SMauro Carvalho Chehab }
3663d6c62b76SMauro Carvalho Chehab if (time == 0)
36649a0bf528SMauro Carvalho Chehab break;
36654607bb7aSMauro Carvalho Chehab
36664607bb7aSMauro Carvalho Chehab /*
36674607bb7aSMauro Carvalho Chehab * Despite dib8000_agc_startup returns time at a 0.1 ms range,
36684607bb7aSMauro Carvalho Chehab * the actual sleep time depends on CONFIG_HZ. The worse case
36694607bb7aSMauro Carvalho Chehab * is when CONFIG_HZ=100. In such case, the minimum granularity
36704607bb7aSMauro Carvalho Chehab * is 10ms. On some real field tests, the tuner sometimes don't
36714607bb7aSMauro Carvalho Chehab * lock when this timer is lower than 10ms. So, enforce a 10ms
36724607bb7aSMauro Carvalho Chehab * granularity.
36734607bb7aSMauro Carvalho Chehab */
36744607bb7aSMauro Carvalho Chehab time = 10 * (time + 99)/100;
36754607bb7aSMauro Carvalho Chehab usleep_range(time * 1000, (time + 1) * 1000);
36769a0bf528SMauro Carvalho Chehab exit_condition = 1;
36779a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36789a0bf528SMauro Carvalho Chehab if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
36799a0bf528SMauro Carvalho Chehab exit_condition = 0;
36809a0bf528SMauro Carvalho Chehab break;
36819a0bf528SMauro Carvalho Chehab }
36829a0bf528SMauro Carvalho Chehab }
36839a0bf528SMauro Carvalho Chehab } while (exit_condition == 0);
36849a0bf528SMauro Carvalho Chehab
36859a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
36869a0bf528SMauro Carvalho Chehab dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
36879a0bf528SMauro Carvalho Chehab
3688173a64cbSPatrick Boettcher active = 1;
36899a0bf528SMauro Carvalho Chehab do {
3690d6c62b76SMauro Carvalho Chehab callback_time = 0;
36919a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3692173a64cbSPatrick Boettcher delay = dib8000_tune(state->fe[index_frontend]);
3693d6c62b76SMauro Carvalho Chehab if (delay != 0) {
3694d6c62b76SMauro Carvalho Chehab delay = jiffies + usecs_to_jiffies(100 * delay);
3695d6c62b76SMauro Carvalho Chehab if (!callback_time || delay < callback_time)
3696d6c62b76SMauro Carvalho Chehab callback_time = delay;
3697d6c62b76SMauro Carvalho Chehab }
3698173a64cbSPatrick Boettcher
3699173a64cbSPatrick Boettcher /* we are in autosearch */
3700173a64cbSPatrick Boettcher if (state->channel_parameters_set == 0) { /* searching */
3701173a64cbSPatrick Boettcher if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
37028af16adfSMauro Carvalho Chehab dprintk("autosearch succeeded on fe%i\n", index_frontend);
37037e3e68bcSMauro Carvalho Chehab dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */
3704173a64cbSPatrick Boettcher state->channel_parameters_set = 1;
3705173a64cbSPatrick Boettcher
3706173a64cbSPatrick Boettcher for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3707173a64cbSPatrick Boettcher if (l != index_frontend) { /* and for all frontend except the successful one */
3708ecc31d55SMauro Carvalho Chehab dprintk("Restarting frontend %d\n", l);
3709173a64cbSPatrick Boettcher dib8000_tune_restart_from_demod(state->fe[l]);
3710173a64cbSPatrick Boettcher
3711173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3712173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3713173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3714173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3715173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3716173a64cbSPatrick Boettcher for (i = 0; i < 3; i++) {
3717173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3718173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3719173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3720173a64cbSPatrick Boettcher state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3721173a64cbSPatrick Boettcher }
3722173a64cbSPatrick Boettcher
37239a0bf528SMauro Carvalho Chehab }
37249a0bf528SMauro Carvalho Chehab }
37259a0bf528SMauro Carvalho Chehab }
3726173a64cbSPatrick Boettcher }
3727173a64cbSPatrick Boettcher }
3728173a64cbSPatrick Boettcher /* tuning is done when the master frontend is done (failed or success) */
3729173a64cbSPatrick Boettcher if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3730173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3731173a64cbSPatrick Boettcher dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3732173a64cbSPatrick Boettcher active = 0;
3733173a64cbSPatrick Boettcher /* we need to wait for all frontends to be finished */
3734173a64cbSPatrick Boettcher for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3735173a64cbSPatrick Boettcher if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3736173a64cbSPatrick Boettcher active = 1;
3737173a64cbSPatrick Boettcher }
3738173a64cbSPatrick Boettcher if (active == 0)
37398af16adfSMauro Carvalho Chehab dprintk("tuning done with status %d\n", dib8000_get_status(state->fe[0]));
37409a0bf528SMauro Carvalho Chehab }
37419a0bf528SMauro Carvalho Chehab
3742d6c62b76SMauro Carvalho Chehab if ((active == 1) && (callback_time == 0)) {
37438af16adfSMauro Carvalho Chehab dprintk("strange callback time something went wrong\n");
3744173a64cbSPatrick Boettcher active = 0;
37459a0bf528SMauro Carvalho Chehab }
37469a0bf528SMauro Carvalho Chehab
3747d6c62b76SMauro Carvalho Chehab while ((active == 1) && (time_before(jiffies, callback_time)))
3748173a64cbSPatrick Boettcher msleep(100);
3749173a64cbSPatrick Boettcher } while (active);
37509a0bf528SMauro Carvalho Chehab
3751173a64cbSPatrick Boettcher /* set output mode */
3752173a64cbSPatrick Boettcher if (state->revision != 0x8090)
37539a0bf528SMauro Carvalho Chehab dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3754173a64cbSPatrick Boettcher else {
37559a0bf528SMauro Carvalho Chehab dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
37569a0bf528SMauro Carvalho Chehab if (state->cfg.enMpegOutput == 0) {
37579a0bf528SMauro Carvalho Chehab dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
37589a0bf528SMauro Carvalho Chehab dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
37599a0bf528SMauro Carvalho Chehab }
37609a0bf528SMauro Carvalho Chehab }
37619a0bf528SMauro Carvalho Chehab
37624d8d5d92SGeert Uytterhoeven return 0;
37639a0bf528SMauro Carvalho Chehab }
37649a0bf528SMauro Carvalho Chehab
37650df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat);
37666ef06e78SMauro Carvalho Chehab
dib8000_read_status(struct dvb_frontend * fe,enum fe_status * stat)37670df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
37689a0bf528SMauro Carvalho Chehab {
37699a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
37709a0bf528SMauro Carvalho Chehab u16 lock_slave = 0, lock;
37719a0bf528SMauro Carvalho Chehab u8 index_frontend;
37729a0bf528SMauro Carvalho Chehab
3773173a64cbSPatrick Boettcher lock = dib8000_read_lock(fe);
37749a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
37759a0bf528SMauro Carvalho Chehab lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
37769a0bf528SMauro Carvalho Chehab
37779a0bf528SMauro Carvalho Chehab *stat = 0;
37789a0bf528SMauro Carvalho Chehab
37799a0bf528SMauro Carvalho Chehab if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
37809a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SIGNAL;
37819a0bf528SMauro Carvalho Chehab
37829a0bf528SMauro Carvalho Chehab if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
37839a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_CARRIER;
37849a0bf528SMauro Carvalho Chehab
37859a0bf528SMauro Carvalho Chehab if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
37869a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SYNC;
37879a0bf528SMauro Carvalho Chehab
37889a0bf528SMauro Carvalho Chehab if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
37899a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_LOCK;
37909a0bf528SMauro Carvalho Chehab
37919a0bf528SMauro Carvalho Chehab if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
37929a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
37939a0bf528SMauro Carvalho Chehab if (lock & 0x01)
37949a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI;
37959a0bf528SMauro Carvalho Chehab
37969a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
37979a0bf528SMauro Carvalho Chehab if (lock & 0x01)
37989a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI;
37999a0bf528SMauro Carvalho Chehab
38009a0bf528SMauro Carvalho Chehab lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
38019a0bf528SMauro Carvalho Chehab if (lock & 0x01)
38029a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI;
38039a0bf528SMauro Carvalho Chehab }
38046ef06e78SMauro Carvalho Chehab dib8000_get_stats(fe, *stat);
38059a0bf528SMauro Carvalho Chehab
38069a0bf528SMauro Carvalho Chehab return 0;
38079a0bf528SMauro Carvalho Chehab }
38089a0bf528SMauro Carvalho Chehab
dib8000_read_ber(struct dvb_frontend * fe,u32 * ber)38099a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
38109a0bf528SMauro Carvalho Chehab {
38119a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
38129a0bf528SMauro Carvalho Chehab
38139a0bf528SMauro Carvalho Chehab /* 13 segments */
38149a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090)
38159a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 562) << 16) |
38169a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 563);
38179a0bf528SMauro Carvalho Chehab else
38189a0bf528SMauro Carvalho Chehab *ber = (dib8000_read_word(state, 560) << 16) |
38199a0bf528SMauro Carvalho Chehab dib8000_read_word(state, 561);
38209a0bf528SMauro Carvalho Chehab return 0;
38219a0bf528SMauro Carvalho Chehab }
38229a0bf528SMauro Carvalho Chehab
dib8000_read_unc_blocks(struct dvb_frontend * fe,u32 * unc)38239a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
38249a0bf528SMauro Carvalho Chehab {
38259a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
38269a0bf528SMauro Carvalho Chehab
38279a0bf528SMauro Carvalho Chehab /* packet error on 13 seg */
38289a0bf528SMauro Carvalho Chehab if (state->revision == 0x8090)
38299a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 567);
38309a0bf528SMauro Carvalho Chehab else
38319a0bf528SMauro Carvalho Chehab *unc = dib8000_read_word(state, 565);
38329a0bf528SMauro Carvalho Chehab return 0;
38339a0bf528SMauro Carvalho Chehab }
38349a0bf528SMauro Carvalho Chehab
dib8000_read_signal_strength(struct dvb_frontend * fe,u16 * strength)38359a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
38369a0bf528SMauro Carvalho Chehab {
38379a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
38389a0bf528SMauro Carvalho Chehab u8 index_frontend;
38399a0bf528SMauro Carvalho Chehab u16 val;
38409a0bf528SMauro Carvalho Chehab
38419a0bf528SMauro Carvalho Chehab *strength = 0;
38429a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
38439a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
38449a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength)
38459a0bf528SMauro Carvalho Chehab *strength = 65535;
38469a0bf528SMauro Carvalho Chehab else
38479a0bf528SMauro Carvalho Chehab *strength += val;
38489a0bf528SMauro Carvalho Chehab }
38499a0bf528SMauro Carvalho Chehab
38509a0bf528SMauro Carvalho Chehab val = 65535 - dib8000_read_word(state, 390);
38519a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength)
38529a0bf528SMauro Carvalho Chehab *strength = 65535;
38539a0bf528SMauro Carvalho Chehab else
38549a0bf528SMauro Carvalho Chehab *strength += val;
38559a0bf528SMauro Carvalho Chehab return 0;
38569a0bf528SMauro Carvalho Chehab }
38579a0bf528SMauro Carvalho Chehab
dib8000_get_snr(struct dvb_frontend * fe)38589a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe)
38599a0bf528SMauro Carvalho Chehab {
38609a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
38619a0bf528SMauro Carvalho Chehab u32 n, s, exp;
38629a0bf528SMauro Carvalho Chehab u16 val;
38639a0bf528SMauro Carvalho Chehab
38649a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
38659a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 542);
38669a0bf528SMauro Carvalho Chehab else
38679a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 544);
38689a0bf528SMauro Carvalho Chehab n = (val >> 6) & 0xff;
38699a0bf528SMauro Carvalho Chehab exp = (val & 0x3f);
38709a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0)
38719a0bf528SMauro Carvalho Chehab exp -= 0x40;
38729a0bf528SMauro Carvalho Chehab n <<= exp+16;
38739a0bf528SMauro Carvalho Chehab
38749a0bf528SMauro Carvalho Chehab if (state->revision != 0x8090)
38759a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 543);
38769a0bf528SMauro Carvalho Chehab else
38779a0bf528SMauro Carvalho Chehab val = dib8000_read_word(state, 545);
38789a0bf528SMauro Carvalho Chehab s = (val >> 6) & 0xff;
38799a0bf528SMauro Carvalho Chehab exp = (val & 0x3f);
38809a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0)
38819a0bf528SMauro Carvalho Chehab exp -= 0x40;
38829a0bf528SMauro Carvalho Chehab s <<= exp+16;
38839a0bf528SMauro Carvalho Chehab
38849a0bf528SMauro Carvalho Chehab if (n > 0) {
38859a0bf528SMauro Carvalho Chehab u32 t = (s/n) << 16;
38869a0bf528SMauro Carvalho Chehab return t + ((s << 16) - n*t) / n;
38879a0bf528SMauro Carvalho Chehab }
38889a0bf528SMauro Carvalho Chehab return 0xffffffff;
38899a0bf528SMauro Carvalho Chehab }
38909a0bf528SMauro Carvalho Chehab
dib8000_read_snr(struct dvb_frontend * fe,u16 * snr)38919a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
38929a0bf528SMauro Carvalho Chehab {
38939a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
38949a0bf528SMauro Carvalho Chehab u8 index_frontend;
38959a0bf528SMauro Carvalho Chehab u32 snr_master;
38969a0bf528SMauro Carvalho Chehab
38979a0bf528SMauro Carvalho Chehab snr_master = dib8000_get_snr(fe);
38989a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
38999a0bf528SMauro Carvalho Chehab snr_master += dib8000_get_snr(state->fe[index_frontend]);
39009a0bf528SMauro Carvalho Chehab
39019a0bf528SMauro Carvalho Chehab if ((snr_master >> 16) != 0) {
39029a0bf528SMauro Carvalho Chehab snr_master = 10*intlog10(snr_master>>16);
39039a0bf528SMauro Carvalho Chehab *snr = snr_master / ((1 << 24) / 10);
39049a0bf528SMauro Carvalho Chehab }
39059a0bf528SMauro Carvalho Chehab else
39069a0bf528SMauro Carvalho Chehab *snr = 0;
39079a0bf528SMauro Carvalho Chehab
39089a0bf528SMauro Carvalho Chehab return 0;
39099a0bf528SMauro Carvalho Chehab }
39109a0bf528SMauro Carvalho Chehab
39116ef06e78SMauro Carvalho Chehab struct per_layer_regs {
39126ef06e78SMauro Carvalho Chehab u16 lock, ber, per;
39136ef06e78SMauro Carvalho Chehab };
39146ef06e78SMauro Carvalho Chehab
39156ef06e78SMauro Carvalho Chehab static const struct per_layer_regs per_layer_regs[] = {
39166ef06e78SMauro Carvalho Chehab { 554, 560, 562 },
39176ef06e78SMauro Carvalho Chehab { 555, 576, 578 },
39186ef06e78SMauro Carvalho Chehab { 556, 581, 583 },
39196ef06e78SMauro Carvalho Chehab };
39206ef06e78SMauro Carvalho Chehab
392142ff76bdSMauro Carvalho Chehab struct linear_segments {
392242ff76bdSMauro Carvalho Chehab unsigned x;
392342ff76bdSMauro Carvalho Chehab signed y;
392442ff76bdSMauro Carvalho Chehab };
392542ff76bdSMauro Carvalho Chehab
392642ff76bdSMauro Carvalho Chehab /*
392742ff76bdSMauro Carvalho Chehab * Table to estimate signal strength in dBm.
392842ff76bdSMauro Carvalho Chehab * This table was empirically determinated by measuring the signal
392942ff76bdSMauro Carvalho Chehab * strength generated by a DTA-2111 RF generator directly connected into
393042ff76bdSMauro Carvalho Chehab * a dib8076 device (a PixelView PV-D231U stick), using a good quality
393142ff76bdSMauro Carvalho Chehab * 3 meters RC6 cable and good RC6 connectors.
393242ff76bdSMauro Carvalho Chehab * The real value can actually be different on other devices, depending
393342ff76bdSMauro Carvalho Chehab * on several factors, like if LNA is enabled or not, if diversity is
393442ff76bdSMauro Carvalho Chehab * enabled, type of connectors, etc.
393542ff76bdSMauro Carvalho Chehab * Yet, it is better to use this measure in dB than a random non-linear
393642ff76bdSMauro Carvalho Chehab * percentage value, especially for antenna adjustments.
393742ff76bdSMauro Carvalho Chehab * On my tests, the precision of the measure using this table is about
393842ff76bdSMauro Carvalho Chehab * 0.5 dB, with sounds reasonable enough.
393942ff76bdSMauro Carvalho Chehab */
394042ff76bdSMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
394142ff76bdSMauro Carvalho Chehab { 55953, 108500 }, /* -22.5 dBm */
394242ff76bdSMauro Carvalho Chehab { 55394, 108000 },
394342ff76bdSMauro Carvalho Chehab { 53834, 107000 },
394442ff76bdSMauro Carvalho Chehab { 52863, 106000 },
394542ff76bdSMauro Carvalho Chehab { 52239, 105000 },
394642ff76bdSMauro Carvalho Chehab { 52012, 104000 },
394742ff76bdSMauro Carvalho Chehab { 51803, 103000 },
394842ff76bdSMauro Carvalho Chehab { 51566, 102000 },
394942ff76bdSMauro Carvalho Chehab { 51356, 101000 },
395042ff76bdSMauro Carvalho Chehab { 51112, 100000 },
395142ff76bdSMauro Carvalho Chehab { 50869, 99000 },
395242ff76bdSMauro Carvalho Chehab { 50600, 98000 },
395342ff76bdSMauro Carvalho Chehab { 50363, 97000 },
395442ff76bdSMauro Carvalho Chehab { 50117, 96000 }, /* -35 dBm */
395542ff76bdSMauro Carvalho Chehab { 49889, 95000 },
395642ff76bdSMauro Carvalho Chehab { 49680, 94000 },
395742ff76bdSMauro Carvalho Chehab { 49493, 93000 },
395842ff76bdSMauro Carvalho Chehab { 49302, 92000 },
395942ff76bdSMauro Carvalho Chehab { 48929, 91000 },
396042ff76bdSMauro Carvalho Chehab { 48416, 90000 },
396142ff76bdSMauro Carvalho Chehab { 48035, 89000 },
396242ff76bdSMauro Carvalho Chehab { 47593, 88000 },
396342ff76bdSMauro Carvalho Chehab { 47282, 87000 },
396442ff76bdSMauro Carvalho Chehab { 46953, 86000 },
396542ff76bdSMauro Carvalho Chehab { 46698, 85000 },
396642ff76bdSMauro Carvalho Chehab { 45617, 84000 },
396742ff76bdSMauro Carvalho Chehab { 44773, 83000 },
396842ff76bdSMauro Carvalho Chehab { 43845, 82000 },
396942ff76bdSMauro Carvalho Chehab { 43020, 81000 },
397042ff76bdSMauro Carvalho Chehab { 42010, 80000 }, /* -51 dBm */
397142ff76bdSMauro Carvalho Chehab { 0, 0 },
397242ff76bdSMauro Carvalho Chehab };
397342ff76bdSMauro Carvalho Chehab
interpolate_value(u32 value,struct linear_segments * segments,unsigned len)397442ff76bdSMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
397542ff76bdSMauro Carvalho Chehab unsigned len)
397642ff76bdSMauro Carvalho Chehab {
397742ff76bdSMauro Carvalho Chehab u64 tmp64;
397842ff76bdSMauro Carvalho Chehab u32 dx;
397942ff76bdSMauro Carvalho Chehab s32 dy;
398042ff76bdSMauro Carvalho Chehab int i, ret;
398142ff76bdSMauro Carvalho Chehab
398242ff76bdSMauro Carvalho Chehab if (value >= segments[0].x)
398342ff76bdSMauro Carvalho Chehab return segments[0].y;
398442ff76bdSMauro Carvalho Chehab if (value < segments[len-1].x)
398542ff76bdSMauro Carvalho Chehab return segments[len-1].y;
398642ff76bdSMauro Carvalho Chehab
398742ff76bdSMauro Carvalho Chehab for (i = 1; i < len - 1; i++) {
398842ff76bdSMauro Carvalho Chehab /* If value is identical, no need to interpolate */
398942ff76bdSMauro Carvalho Chehab if (value == segments[i].x)
399042ff76bdSMauro Carvalho Chehab return segments[i].y;
399142ff76bdSMauro Carvalho Chehab if (value > segments[i].x)
399242ff76bdSMauro Carvalho Chehab break;
399342ff76bdSMauro Carvalho Chehab }
399442ff76bdSMauro Carvalho Chehab
399542ff76bdSMauro Carvalho Chehab /* Linear interpolation between the two (x,y) points */
399642ff76bdSMauro Carvalho Chehab dy = segments[i - 1].y - segments[i].y;
399742ff76bdSMauro Carvalho Chehab dx = segments[i - 1].x - segments[i].x;
399842ff76bdSMauro Carvalho Chehab
399942ff76bdSMauro Carvalho Chehab tmp64 = value - segments[i].x;
400042ff76bdSMauro Carvalho Chehab tmp64 *= dy;
400142ff76bdSMauro Carvalho Chehab do_div(tmp64, dx);
400242ff76bdSMauro Carvalho Chehab ret = segments[i].y + tmp64;
400342ff76bdSMauro Carvalho Chehab
400442ff76bdSMauro Carvalho Chehab return ret;
400542ff76bdSMauro Carvalho Chehab }
400642ff76bdSMauro Carvalho Chehab
dib8000_get_time_us(struct dvb_frontend * fe,int layer)4007704f01bbSMauro Carvalho Chehab static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
4008704f01bbSMauro Carvalho Chehab {
4009704f01bbSMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
4010704f01bbSMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4011704f01bbSMauro Carvalho Chehab int ini_layer, end_layer, i;
40124bf48150SMauro Carvalho Chehab u64 time_us, tmp64;
4013704f01bbSMauro Carvalho Chehab u32 tmp, denom;
4014e4a3bc1cSMauro Carvalho Chehab int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
4015e4a3bc1cSMauro Carvalho Chehab int interleaving = 0, fft_div;
4016704f01bbSMauro Carvalho Chehab
4017704f01bbSMauro Carvalho Chehab if (layer >= 0) {
4018704f01bbSMauro Carvalho Chehab ini_layer = layer;
4019704f01bbSMauro Carvalho Chehab end_layer = layer + 1;
4020704f01bbSMauro Carvalho Chehab } else {
4021704f01bbSMauro Carvalho Chehab ini_layer = 0;
4022704f01bbSMauro Carvalho Chehab end_layer = 3;
4023704f01bbSMauro Carvalho Chehab }
4024704f01bbSMauro Carvalho Chehab
4025704f01bbSMauro Carvalho Chehab switch (c->guard_interval) {
4026704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_4:
4027704f01bbSMauro Carvalho Chehab guard = 4;
4028704f01bbSMauro Carvalho Chehab break;
4029704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_8:
4030704f01bbSMauro Carvalho Chehab guard = 8;
4031704f01bbSMauro Carvalho Chehab break;
4032704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_16:
4033704f01bbSMauro Carvalho Chehab guard = 16;
4034704f01bbSMauro Carvalho Chehab break;
4035704f01bbSMauro Carvalho Chehab default:
4036704f01bbSMauro Carvalho Chehab case GUARD_INTERVAL_1_32:
4037704f01bbSMauro Carvalho Chehab guard = 32;
4038704f01bbSMauro Carvalho Chehab break;
4039704f01bbSMauro Carvalho Chehab }
4040704f01bbSMauro Carvalho Chehab
4041704f01bbSMauro Carvalho Chehab switch (c->transmission_mode) {
4042704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
4043704f01bbSMauro Carvalho Chehab fft_div = 4;
4044704f01bbSMauro Carvalho Chehab break;
4045704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_4K:
4046704f01bbSMauro Carvalho Chehab fft_div = 2;
4047704f01bbSMauro Carvalho Chehab break;
4048704f01bbSMauro Carvalho Chehab default:
4049704f01bbSMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
4050704f01bbSMauro Carvalho Chehab fft_div = 1;
4051704f01bbSMauro Carvalho Chehab break;
4052704f01bbSMauro Carvalho Chehab }
4053704f01bbSMauro Carvalho Chehab
4054704f01bbSMauro Carvalho Chehab denom = 0;
4055704f01bbSMauro Carvalho Chehab for (i = ini_layer; i < end_layer; i++) {
4056704f01bbSMauro Carvalho Chehab nsegs = c->layer[i].segment_count;
4057704f01bbSMauro Carvalho Chehab if (nsegs == 0 || nsegs > 13)
4058704f01bbSMauro Carvalho Chehab continue;
4059704f01bbSMauro Carvalho Chehab
4060704f01bbSMauro Carvalho Chehab switch (c->layer[i].modulation) {
4061704f01bbSMauro Carvalho Chehab case DQPSK:
4062704f01bbSMauro Carvalho Chehab case QPSK:
4063704f01bbSMauro Carvalho Chehab bits_per_symbol = 2;
4064704f01bbSMauro Carvalho Chehab break;
4065704f01bbSMauro Carvalho Chehab case QAM_16:
4066704f01bbSMauro Carvalho Chehab bits_per_symbol = 4;
4067704f01bbSMauro Carvalho Chehab break;
4068704f01bbSMauro Carvalho Chehab default:
4069704f01bbSMauro Carvalho Chehab case QAM_64:
4070704f01bbSMauro Carvalho Chehab bits_per_symbol = 6;
4071704f01bbSMauro Carvalho Chehab break;
4072704f01bbSMauro Carvalho Chehab }
4073704f01bbSMauro Carvalho Chehab
4074704f01bbSMauro Carvalho Chehab switch (c->layer[i].fec) {
4075704f01bbSMauro Carvalho Chehab case FEC_1_2:
4076704f01bbSMauro Carvalho Chehab rate_num = 1;
4077704f01bbSMauro Carvalho Chehab rate_denum = 2;
4078704f01bbSMauro Carvalho Chehab break;
4079704f01bbSMauro Carvalho Chehab case FEC_2_3:
4080704f01bbSMauro Carvalho Chehab rate_num = 2;
4081704f01bbSMauro Carvalho Chehab rate_denum = 3;
4082704f01bbSMauro Carvalho Chehab break;
4083704f01bbSMauro Carvalho Chehab case FEC_3_4:
4084704f01bbSMauro Carvalho Chehab rate_num = 3;
4085704f01bbSMauro Carvalho Chehab rate_denum = 4;
4086704f01bbSMauro Carvalho Chehab break;
4087704f01bbSMauro Carvalho Chehab case FEC_5_6:
4088704f01bbSMauro Carvalho Chehab rate_num = 5;
4089704f01bbSMauro Carvalho Chehab rate_denum = 6;
4090704f01bbSMauro Carvalho Chehab break;
4091704f01bbSMauro Carvalho Chehab default:
4092704f01bbSMauro Carvalho Chehab case FEC_7_8:
4093704f01bbSMauro Carvalho Chehab rate_num = 7;
4094704f01bbSMauro Carvalho Chehab rate_denum = 8;
4095704f01bbSMauro Carvalho Chehab break;
4096704f01bbSMauro Carvalho Chehab }
4097704f01bbSMauro Carvalho Chehab
4098704f01bbSMauro Carvalho Chehab interleaving = c->layer[i].interleaving;
4099704f01bbSMauro Carvalho Chehab
4100704f01bbSMauro Carvalho Chehab denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4101704f01bbSMauro Carvalho Chehab }
4102704f01bbSMauro Carvalho Chehab
4103704f01bbSMauro Carvalho Chehab /* If all goes wrong, wait for 1s for the next stats */
4104704f01bbSMauro Carvalho Chehab if (!denom)
4105704f01bbSMauro Carvalho Chehab return 0;
4106704f01bbSMauro Carvalho Chehab
4107704f01bbSMauro Carvalho Chehab /* Estimate the period for the total bit rate */
4108704f01bbSMauro Carvalho Chehab time_us = rate_denum * (1008 * 1562500L);
41094bf48150SMauro Carvalho Chehab tmp64 = time_us;
41104bf48150SMauro Carvalho Chehab do_div(tmp64, guard);
41114bf48150SMauro Carvalho Chehab time_us = time_us + tmp64;
4112704f01bbSMauro Carvalho Chehab time_us += denom / 2;
4113704f01bbSMauro Carvalho Chehab do_div(time_us, denom);
4114704f01bbSMauro Carvalho Chehab
4115704f01bbSMauro Carvalho Chehab tmp = 1008 * 96 * interleaving;
4116704f01bbSMauro Carvalho Chehab time_us += tmp + tmp / guard;
4117704f01bbSMauro Carvalho Chehab
4118704f01bbSMauro Carvalho Chehab return time_us;
4119704f01bbSMauro Carvalho Chehab }
4120704f01bbSMauro Carvalho Chehab
dib8000_get_stats(struct dvb_frontend * fe,enum fe_status stat)41210df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat)
41226ef06e78SMauro Carvalho Chehab {
41236ef06e78SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
41246ef06e78SMauro Carvalho Chehab struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4125704f01bbSMauro Carvalho Chehab int i;
41260400c535SMauro Carvalho Chehab int show_per_stats = 0;
41270400c535SMauro Carvalho Chehab u32 time_us = 0, snr, val;
41280400c535SMauro Carvalho Chehab u64 blocks;
412942ff76bdSMauro Carvalho Chehab s32 db;
41306ef06e78SMauro Carvalho Chehab u16 strength;
41316ef06e78SMauro Carvalho Chehab
41326ef06e78SMauro Carvalho Chehab /* Get Signal strength */
41336ef06e78SMauro Carvalho Chehab dib8000_read_signal_strength(fe, &strength);
413442ff76bdSMauro Carvalho Chehab val = strength;
413542ff76bdSMauro Carvalho Chehab db = interpolate_value(val,
413642ff76bdSMauro Carvalho Chehab strength_to_db_table,
413742ff76bdSMauro Carvalho Chehab ARRAY_SIZE(strength_to_db_table)) - 131000;
413842ff76bdSMauro Carvalho Chehab c->strength.stat[0].svalue = db;
41396ef06e78SMauro Carvalho Chehab
4140704f01bbSMauro Carvalho Chehab /* UCB/BER/CNR measures require lock */
4141704f01bbSMauro Carvalho Chehab if (!(stat & FE_HAS_LOCK)) {
4142704f01bbSMauro Carvalho Chehab c->cnr.len = 1;
41430400c535SMauro Carvalho Chehab c->block_count.len = 1;
4144704f01bbSMauro Carvalho Chehab c->block_error.len = 1;
4145704f01bbSMauro Carvalho Chehab c->post_bit_error.len = 1;
4146704f01bbSMauro Carvalho Chehab c->post_bit_count.len = 1;
4147704f01bbSMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4148704f01bbSMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4149704f01bbSMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4150704f01bbSMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
41510400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
41526ef06e78SMauro Carvalho Chehab return 0;
4153704f01bbSMauro Carvalho Chehab }
4154704f01bbSMauro Carvalho Chehab
4155704f01bbSMauro Carvalho Chehab /* Check if time for stats was elapsed */
41560400c535SMauro Carvalho Chehab if (time_after(jiffies, state->per_jiffies_stats)) {
41570400c535SMauro Carvalho Chehab state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
41586ef06e78SMauro Carvalho Chehab
41596ef06e78SMauro Carvalho Chehab /* Get SNR */
41606ef06e78SMauro Carvalho Chehab snr = dib8000_get_snr(fe);
41616ef06e78SMauro Carvalho Chehab for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
41626ef06e78SMauro Carvalho Chehab if (state->fe[i])
41636ef06e78SMauro Carvalho Chehab snr += dib8000_get_snr(state->fe[i]);
41646ef06e78SMauro Carvalho Chehab }
41656ef06e78SMauro Carvalho Chehab snr = snr >> 16;
41666ef06e78SMauro Carvalho Chehab
41676ef06e78SMauro Carvalho Chehab if (snr) {
41686ef06e78SMauro Carvalho Chehab snr = 10 * intlog10(snr);
41696ef06e78SMauro Carvalho Chehab snr = (1000L * snr) >> 24;
41706ef06e78SMauro Carvalho Chehab } else {
41716ef06e78SMauro Carvalho Chehab snr = 0;
41726ef06e78SMauro Carvalho Chehab }
41736ef06e78SMauro Carvalho Chehab c->cnr.stat[0].svalue = snr;
41746ef06e78SMauro Carvalho Chehab c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
41756ef06e78SMauro Carvalho Chehab
41760400c535SMauro Carvalho Chehab /* Get UCB measures */
41770400c535SMauro Carvalho Chehab dib8000_read_unc_blocks(fe, &val);
41780400c535SMauro Carvalho Chehab if (val < state->init_ucb)
41795dc8526bSMauro Carvalho Chehab state->init_ucb += 0x100000000LL;
41800400c535SMauro Carvalho Chehab
41810400c535SMauro Carvalho Chehab c->block_error.stat[0].scale = FE_SCALE_COUNTER;
41820400c535SMauro Carvalho Chehab c->block_error.stat[0].uvalue = val + state->init_ucb;
41830400c535SMauro Carvalho Chehab
41840400c535SMauro Carvalho Chehab /* Estimate the number of packets based on bitrate */
41850400c535SMauro Carvalho Chehab if (!time_us)
41860400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, -1);
41870400c535SMauro Carvalho Chehab
41880400c535SMauro Carvalho Chehab if (time_us) {
41895dc8526bSMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL;
41900400c535SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204);
41910400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER;
41920400c535SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks;
41930400c535SMauro Carvalho Chehab }
41940400c535SMauro Carvalho Chehab
41950400c535SMauro Carvalho Chehab show_per_stats = 1;
41960400c535SMauro Carvalho Chehab }
41970400c535SMauro Carvalho Chehab
41980400c535SMauro Carvalho Chehab /* Get post-BER measures */
41990400c535SMauro Carvalho Chehab if (time_after(jiffies, state->ber_jiffies_stats)) {
42000400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, -1);
42010400c535SMauro Carvalho Chehab state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
42020400c535SMauro Carvalho Chehab
42038af16adfSMauro Carvalho Chehab dprintk("Next all layers stats available in %u us.\n", time_us);
42046ef06e78SMauro Carvalho Chehab
42056ef06e78SMauro Carvalho Chehab dib8000_read_ber(fe, &val);
42066ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
42076ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[0].uvalue += val;
42086ef06e78SMauro Carvalho Chehab
42096ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
42106ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[0].uvalue += 100000000;
4211704f01bbSMauro Carvalho Chehab }
42126ef06e78SMauro Carvalho Chehab
42136ef06e78SMauro Carvalho Chehab if (state->revision < 0x8002)
42146ef06e78SMauro Carvalho Chehab return 0;
42156ef06e78SMauro Carvalho Chehab
42166ef06e78SMauro Carvalho Chehab c->block_error.len = 4;
42176ef06e78SMauro Carvalho Chehab c->post_bit_error.len = 4;
42186ef06e78SMauro Carvalho Chehab c->post_bit_count.len = 4;
42196ef06e78SMauro Carvalho Chehab
42206ef06e78SMauro Carvalho Chehab for (i = 0; i < 3; i++) {
42210400c535SMauro Carvalho Chehab unsigned nsegs = c->layer[i].segment_count;
42220400c535SMauro Carvalho Chehab
42230400c535SMauro Carvalho Chehab if (nsegs == 0 || nsegs > 13)
4224704f01bbSMauro Carvalho Chehab continue;
4225704f01bbSMauro Carvalho Chehab
42260400c535SMauro Carvalho Chehab time_us = 0;
42270400c535SMauro Carvalho Chehab
42280400c535SMauro Carvalho Chehab if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
42290400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, i);
42300400c535SMauro Carvalho Chehab
42310400c535SMauro Carvalho Chehab state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4232704f01bbSMauro Carvalho Chehab dprintk("Next layer %c stats will be available in %u us\n",
4233704f01bbSMauro Carvalho Chehab 'A' + i, time_us);
4234704f01bbSMauro Carvalho Chehab
42356ef06e78SMauro Carvalho Chehab val = dib8000_read_word(state, per_layer_regs[i].ber);
42366ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
42376ef06e78SMauro Carvalho Chehab c->post_bit_error.stat[1 + i].uvalue += val;
42386ef06e78SMauro Carvalho Chehab
42396ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
42406ef06e78SMauro Carvalho Chehab c->post_bit_count.stat[1 + i].uvalue += 100000000;
42410400c535SMauro Carvalho Chehab }
42426ef06e78SMauro Carvalho Chehab
42430400c535SMauro Carvalho Chehab if (show_per_stats) {
42446ef06e78SMauro Carvalho Chehab val = dib8000_read_word(state, per_layer_regs[i].per);
42456ef06e78SMauro Carvalho Chehab
42466ef06e78SMauro Carvalho Chehab c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
42476ef06e78SMauro Carvalho Chehab c->block_error.stat[1 + i].uvalue += val;
42480400c535SMauro Carvalho Chehab
42490400c535SMauro Carvalho Chehab if (!time_us)
42500400c535SMauro Carvalho Chehab time_us = dib8000_get_time_us(fe, i);
42510400c535SMauro Carvalho Chehab if (time_us) {
42525dc8526bSMauro Carvalho Chehab blocks = 1250000ULL * 1000000ULL;
42530400c535SMauro Carvalho Chehab do_div(blocks, time_us * 8 * 204);
42540400c535SMauro Carvalho Chehab c->block_count.stat[0].scale = FE_SCALE_COUNTER;
42550400c535SMauro Carvalho Chehab c->block_count.stat[0].uvalue += blocks;
42560400c535SMauro Carvalho Chehab }
42570400c535SMauro Carvalho Chehab }
42586ef06e78SMauro Carvalho Chehab }
42596ef06e78SMauro Carvalho Chehab return 0;
42606ef06e78SMauro Carvalho Chehab }
42616ef06e78SMauro Carvalho Chehab
dib8000_set_slave_frontend(struct dvb_frontend * fe,struct dvb_frontend * fe_slave)4262d44913c1SMauro Carvalho Chehab static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
42639a0bf528SMauro Carvalho Chehab {
42649a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
42659a0bf528SMauro Carvalho Chehab u8 index_frontend = 1;
42669a0bf528SMauro Carvalho Chehab
42679a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
42689a0bf528SMauro Carvalho Chehab index_frontend++;
42699a0bf528SMauro Carvalho Chehab if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
42708af16adfSMauro Carvalho Chehab dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend);
42719a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = fe_slave;
42729a0bf528SMauro Carvalho Chehab return 0;
42739a0bf528SMauro Carvalho Chehab }
42749a0bf528SMauro Carvalho Chehab
42758af16adfSMauro Carvalho Chehab dprintk("too many slave frontend\n");
42769a0bf528SMauro Carvalho Chehab return -ENOMEM;
42779a0bf528SMauro Carvalho Chehab }
42789a0bf528SMauro Carvalho Chehab
dib8000_get_slave_frontend(struct dvb_frontend * fe,int slave_index)4279d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
42809a0bf528SMauro Carvalho Chehab {
42819a0bf528SMauro Carvalho Chehab struct dib8000_state *state = fe->demodulator_priv;
42829a0bf528SMauro Carvalho Chehab
42839a0bf528SMauro Carvalho Chehab if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
42849a0bf528SMauro Carvalho Chehab return NULL;
42859a0bf528SMauro Carvalho Chehab return state->fe[slave_index];
42869a0bf528SMauro Carvalho Chehab }
42879a0bf528SMauro Carvalho Chehab
dib8000_i2c_enumeration(struct i2c_adapter * host,int no_of_demods,u8 default_addr,u8 first_addr,u8 is_dib8096p)4288d44913c1SMauro Carvalho Chehab static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
42899a0bf528SMauro Carvalho Chehab u8 default_addr, u8 first_addr, u8 is_dib8096p)
42909a0bf528SMauro Carvalho Chehab {
42919a0bf528SMauro Carvalho Chehab int k = 0, ret = 0;
42929a0bf528SMauro Carvalho Chehab u8 new_addr = 0;
42939a0bf528SMauro Carvalho Chehab struct i2c_device client = {.adap = host };
42949a0bf528SMauro Carvalho Chehab
42956396bb22SKees Cook client.i2c_write_buffer = kzalloc(4, GFP_KERNEL);
42969a0bf528SMauro Carvalho Chehab if (!client.i2c_write_buffer) {
42978af16adfSMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__);
42989a0bf528SMauro Carvalho Chehab return -ENOMEM;
42999a0bf528SMauro Carvalho Chehab }
43006396bb22SKees Cook client.i2c_read_buffer = kzalloc(4, GFP_KERNEL);
43019a0bf528SMauro Carvalho Chehab if (!client.i2c_read_buffer) {
43028af16adfSMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__);
43039a0bf528SMauro Carvalho Chehab ret = -ENOMEM;
43049a0bf528SMauro Carvalho Chehab goto error_memory_read;
43059a0bf528SMauro Carvalho Chehab }
43069a0bf528SMauro Carvalho Chehab client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
43079a0bf528SMauro Carvalho Chehab if (!client.i2c_buffer_lock) {
43088af16adfSMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__);
43099a0bf528SMauro Carvalho Chehab ret = -ENOMEM;
43109a0bf528SMauro Carvalho Chehab goto error_memory_lock;
43119a0bf528SMauro Carvalho Chehab }
43129a0bf528SMauro Carvalho Chehab mutex_init(client.i2c_buffer_lock);
43139a0bf528SMauro Carvalho Chehab
43149a0bf528SMauro Carvalho Chehab for (k = no_of_demods - 1; k >= 0; k--) {
43159a0bf528SMauro Carvalho Chehab /* designated i2c address */
43169a0bf528SMauro Carvalho Chehab new_addr = first_addr + (k << 1);
43179a0bf528SMauro Carvalho Chehab
43189a0bf528SMauro Carvalho Chehab client.addr = new_addr;
43199a0bf528SMauro Carvalho Chehab if (!is_dib8096p)
43209a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
43219a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) {
43229a0bf528SMauro Carvalho Chehab /* sram lead in, rdy */
43239a0bf528SMauro Carvalho Chehab if (!is_dib8096p)
43249a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1287, 0x0003);
43259a0bf528SMauro Carvalho Chehab client.addr = default_addr;
43269a0bf528SMauro Carvalho Chehab if (dib8000_identify(&client) == 0) {
43278af16adfSMauro Carvalho Chehab dprintk("#%d: not identified\n", k);
43289a0bf528SMauro Carvalho Chehab ret = -EINVAL;
43299a0bf528SMauro Carvalho Chehab goto error;
43309a0bf528SMauro Carvalho Chehab }
43319a0bf528SMauro Carvalho Chehab }
43329a0bf528SMauro Carvalho Chehab
43339a0bf528SMauro Carvalho Chehab /* start diversity to pull_down div_str - just for i2c-enumeration */
43349a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
43359a0bf528SMauro Carvalho Chehab
43369a0bf528SMauro Carvalho Chehab /* set new i2c address and force divstart */
43379a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
43389a0bf528SMauro Carvalho Chehab client.addr = new_addr;
43399a0bf528SMauro Carvalho Chehab dib8000_identify(&client);
43409a0bf528SMauro Carvalho Chehab
43418af16adfSMauro Carvalho Chehab dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
43429a0bf528SMauro Carvalho Chehab }
43439a0bf528SMauro Carvalho Chehab
43449a0bf528SMauro Carvalho Chehab for (k = 0; k < no_of_demods; k++) {
43459a0bf528SMauro Carvalho Chehab new_addr = first_addr | (k << 1);
43469a0bf528SMauro Carvalho Chehab client.addr = new_addr;
43479a0bf528SMauro Carvalho Chehab
43489a0bf528SMauro Carvalho Chehab // unforce divstr
43499a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1285, new_addr << 2);
43509a0bf528SMauro Carvalho Chehab
43519a0bf528SMauro Carvalho Chehab /* deactivate div - it was just for i2c-enumeration */
43529a0bf528SMauro Carvalho Chehab dib8000_i2c_write16(&client, 1286, 0);
43539a0bf528SMauro Carvalho Chehab }
43549a0bf528SMauro Carvalho Chehab
43559a0bf528SMauro Carvalho Chehab error:
43569a0bf528SMauro Carvalho Chehab kfree(client.i2c_buffer_lock);
43579a0bf528SMauro Carvalho Chehab error_memory_lock:
43589a0bf528SMauro Carvalho Chehab kfree(client.i2c_read_buffer);
43599a0bf528SMauro Carvalho Chehab error_memory_read:
43609a0bf528SMauro Carvalho Chehab kfree(client.i2c_write_buffer);
43619a0bf528SMauro Carvalho Chehab
43629a0bf528SMauro Carvalho Chehab return ret;
43639a0bf528SMauro Carvalho Chehab }
43649a0bf528SMauro Carvalho Chehab
dib8000_fe_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * tune)43659a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
43669a0bf528SMauro Carvalho Chehab {
43679a0bf528SMauro Carvalho Chehab tune->min_delay_ms = 1000;
43689a0bf528SMauro Carvalho Chehab tune->step_size = 0;
43699a0bf528SMauro Carvalho Chehab tune->max_drift = 0;
43709a0bf528SMauro Carvalho Chehab return 0;
43719a0bf528SMauro Carvalho Chehab }
43729a0bf528SMauro Carvalho Chehab
dib8000_release(struct dvb_frontend * fe)43739a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe)
43749a0bf528SMauro Carvalho Chehab {
43759a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv;
43769a0bf528SMauro Carvalho Chehab u8 index_frontend;
43779a0bf528SMauro Carvalho Chehab
43789a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
43799a0bf528SMauro Carvalho Chehab dvb_frontend_detach(st->fe[index_frontend]);
43809a0bf528SMauro Carvalho Chehab
43819a0bf528SMauro Carvalho Chehab dibx000_exit_i2c_master(&st->i2c_master);
43829a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->dib8096p_tuner_adap);
43839a0bf528SMauro Carvalho Chehab kfree(st->fe[0]);
43849a0bf528SMauro Carvalho Chehab kfree(st);
43859a0bf528SMauro Carvalho Chehab }
43869a0bf528SMauro Carvalho Chehab
dib8000_get_i2c_master(struct dvb_frontend * fe,enum dibx000_i2c_interface intf,int gating)4387d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
43889a0bf528SMauro Carvalho Chehab {
43899a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv;
43909a0bf528SMauro Carvalho Chehab return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
43919a0bf528SMauro Carvalho Chehab }
43929a0bf528SMauro Carvalho Chehab
dib8000_pid_filter_ctrl(struct dvb_frontend * fe,u8 onoff)4393d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
43949a0bf528SMauro Carvalho Chehab {
43959a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv;
43969a0bf528SMauro Carvalho Chehab u16 val = dib8000_read_word(st, 299) & 0xffef;
43979a0bf528SMauro Carvalho Chehab val |= (onoff & 0x1) << 4;
43989a0bf528SMauro Carvalho Chehab
43998af16adfSMauro Carvalho Chehab dprintk("pid filter enabled %d\n", onoff);
44009a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 299, val);
44019a0bf528SMauro Carvalho Chehab }
44029a0bf528SMauro Carvalho Chehab
dib8000_pid_filter(struct dvb_frontend * fe,u8 id,u16 pid,u8 onoff)4403d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
44049a0bf528SMauro Carvalho Chehab {
44059a0bf528SMauro Carvalho Chehab struct dib8000_state *st = fe->demodulator_priv;
44068af16adfSMauro Carvalho Chehab dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff);
44079a0bf528SMauro Carvalho Chehab return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
44089a0bf528SMauro Carvalho Chehab }
44099a0bf528SMauro Carvalho Chehab
44109a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = {
44119a0bf528SMauro Carvalho Chehab .delsys = { SYS_ISDBT },
44129a0bf528SMauro Carvalho Chehab .info = {
44139a0bf528SMauro Carvalho Chehab .name = "DiBcom 8000 ISDB-T",
4414f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 44250 * kHz,
4415f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 867250 * kHz,
4416f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 62500,
44179a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO |
44189a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
44199a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
44209a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
44219a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
44229a0bf528SMauro Carvalho Chehab },
44239a0bf528SMauro Carvalho Chehab
44249a0bf528SMauro Carvalho Chehab .release = dib8000_release,
44259a0bf528SMauro Carvalho Chehab
44269a0bf528SMauro Carvalho Chehab .init = dib8000_wakeup,
44279a0bf528SMauro Carvalho Chehab .sleep = dib8000_sleep,
44289a0bf528SMauro Carvalho Chehab
44299a0bf528SMauro Carvalho Chehab .set_frontend = dib8000_set_frontend,
44309a0bf528SMauro Carvalho Chehab .get_tune_settings = dib8000_fe_get_tune_settings,
44319a0bf528SMauro Carvalho Chehab .get_frontend = dib8000_get_frontend,
44329a0bf528SMauro Carvalho Chehab
44339a0bf528SMauro Carvalho Chehab .read_status = dib8000_read_status,
44349a0bf528SMauro Carvalho Chehab .read_ber = dib8000_read_ber,
44359a0bf528SMauro Carvalho Chehab .read_signal_strength = dib8000_read_signal_strength,
44369a0bf528SMauro Carvalho Chehab .read_snr = dib8000_read_snr,
44379a0bf528SMauro Carvalho Chehab .read_ucblocks = dib8000_read_unc_blocks,
44389a0bf528SMauro Carvalho Chehab };
44399a0bf528SMauro Carvalho Chehab
dib8000_init(struct i2c_adapter * i2c_adap,u8 i2c_addr,struct dib8000_config * cfg)4440d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
44419a0bf528SMauro Carvalho Chehab {
44429a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe;
44439a0bf528SMauro Carvalho Chehab struct dib8000_state *state;
44449a0bf528SMauro Carvalho Chehab
44458af16adfSMauro Carvalho Chehab dprintk("dib8000_init\n");
44469a0bf528SMauro Carvalho Chehab
44479a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
44489a0bf528SMauro Carvalho Chehab if (state == NULL)
44499a0bf528SMauro Carvalho Chehab return NULL;
44509a0bf528SMauro Carvalho Chehab fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
44519a0bf528SMauro Carvalho Chehab if (fe == NULL)
44529a0bf528SMauro Carvalho Chehab goto error;
44539a0bf528SMauro Carvalho Chehab
44549a0bf528SMauro Carvalho Chehab memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
44559a0bf528SMauro Carvalho Chehab state->i2c.adap = i2c_adap;
44569a0bf528SMauro Carvalho Chehab state->i2c.addr = i2c_addr;
44579a0bf528SMauro Carvalho Chehab state->i2c.i2c_write_buffer = state->i2c_write_buffer;
44589a0bf528SMauro Carvalho Chehab state->i2c.i2c_read_buffer = state->i2c_read_buffer;
44599a0bf528SMauro Carvalho Chehab mutex_init(&state->i2c_buffer_lock);
44609a0bf528SMauro Carvalho Chehab state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
44619a0bf528SMauro Carvalho Chehab state->gpio_val = cfg->gpio_val;
44629a0bf528SMauro Carvalho Chehab state->gpio_dir = cfg->gpio_dir;
44639a0bf528SMauro Carvalho Chehab
44649a0bf528SMauro Carvalho Chehab /* Ensure the output mode remains at the previous default if it's
44659a0bf528SMauro Carvalho Chehab * not specifically set by the caller.
44669a0bf528SMauro Carvalho Chehab */
44679a0bf528SMauro Carvalho Chehab if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
44689a0bf528SMauro Carvalho Chehab state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
44699a0bf528SMauro Carvalho Chehab
44709a0bf528SMauro Carvalho Chehab state->fe[0] = fe;
44719a0bf528SMauro Carvalho Chehab fe->demodulator_priv = state;
44729a0bf528SMauro Carvalho Chehab memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
44739a0bf528SMauro Carvalho Chehab
44749a0bf528SMauro Carvalho Chehab state->timf_default = cfg->pll->timf;
44759a0bf528SMauro Carvalho Chehab
44768dbdcc72SZhou Qingyang if (dib8000_identify(&state->i2c) == 0) {
44778dbdcc72SZhou Qingyang kfree(fe);
44789a0bf528SMauro Carvalho Chehab goto error;
44798dbdcc72SZhou Qingyang }
44809a0bf528SMauro Carvalho Chehab
44819a0bf528SMauro Carvalho Chehab dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
44829a0bf528SMauro Carvalho Chehab
44839a0bf528SMauro Carvalho Chehab /* init 8096p tuner adapter */
448485709cbfSMauro Carvalho Chehab strscpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
44859a0bf528SMauro Carvalho Chehab sizeof(state->dib8096p_tuner_adap.name));
44869a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
44879a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.algo_data = NULL;
44889a0bf528SMauro Carvalho Chehab state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
44899a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
44909a0bf528SMauro Carvalho Chehab i2c_add_adapter(&state->dib8096p_tuner_adap);
44919a0bf528SMauro Carvalho Chehab
44929a0bf528SMauro Carvalho Chehab dib8000_reset(fe);
44939a0bf528SMauro Carvalho Chehab
44949a0bf528SMauro Carvalho Chehab dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
4495173a64cbSPatrick Boettcher state->current_demod_bw = 6000;
44969a0bf528SMauro Carvalho Chehab
44979a0bf528SMauro Carvalho Chehab return fe;
44989a0bf528SMauro Carvalho Chehab
44999a0bf528SMauro Carvalho Chehab error:
45009a0bf528SMauro Carvalho Chehab kfree(state);
45019a0bf528SMauro Carvalho Chehab return NULL;
45029a0bf528SMauro Carvalho Chehab }
45039a0bf528SMauro Carvalho Chehab
dib8000_attach(struct dib8000_ops * ops)4504d44913c1SMauro Carvalho Chehab void *dib8000_attach(struct dib8000_ops *ops)
4505d44913c1SMauro Carvalho Chehab {
4506d44913c1SMauro Carvalho Chehab if (!ops)
4507d44913c1SMauro Carvalho Chehab return NULL;
4508d44913c1SMauro Carvalho Chehab
4509d44913c1SMauro Carvalho Chehab ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4510d44913c1SMauro Carvalho Chehab ops->get_dc_power = dib8090p_get_dc_power;
4511d44913c1SMauro Carvalho Chehab ops->set_gpio = dib8000_set_gpio;
4512d44913c1SMauro Carvalho Chehab ops->get_slave_frontend = dib8000_get_slave_frontend;
4513d44913c1SMauro Carvalho Chehab ops->set_tune_state = dib8000_set_tune_state;
4514d44913c1SMauro Carvalho Chehab ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4515d44913c1SMauro Carvalho Chehab ops->get_adc_power = dib8000_get_adc_power;
4516d44913c1SMauro Carvalho Chehab ops->update_pll = dib8000_update_pll;
4517d44913c1SMauro Carvalho Chehab ops->tuner_sleep = dib8096p_tuner_sleep;
4518d44913c1SMauro Carvalho Chehab ops->get_tune_state = dib8000_get_tune_state;
4519d44913c1SMauro Carvalho Chehab ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4520d44913c1SMauro Carvalho Chehab ops->set_slave_frontend = dib8000_set_slave_frontend;
4521d44913c1SMauro Carvalho Chehab ops->pid_filter = dib8000_pid_filter;
4522d44913c1SMauro Carvalho Chehab ops->ctrl_timf = dib8000_ctrl_timf;
4523d44913c1SMauro Carvalho Chehab ops->init = dib8000_init;
4524d44913c1SMauro Carvalho Chehab ops->get_i2c_master = dib8000_get_i2c_master;
4525d44913c1SMauro Carvalho Chehab ops->i2c_enumeration = dib8000_i2c_enumeration;
4526d44913c1SMauro Carvalho Chehab ops->set_wbd_ref = dib8000_set_wbd_ref;
4527d44913c1SMauro Carvalho Chehab
4528d44913c1SMauro Carvalho Chehab return ops;
4529d44913c1SMauro Carvalho Chehab }
4530*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(dib8000_attach);
45319a0bf528SMauro Carvalho Chehab
453299e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
45339a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
45349a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
4535