From b6884a17fc70e979ef34e4b5560988b522bb50a0 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 27 Jul 2007 10:08:51 -0300 Subject: [PATCH] V4L/DVB (5954): Sync with DiBcom Driver Release 2.1.3 + some improvements This changesets syncs the OpenSource driver for DiBcom demodulators with version 2.1.3 of DiBcom reference driver. There were some improvements since the last release for linux-dvb, e.g.: - stepped AGC startup - less space for initialization - diversity synchronization Furthermore this changeset contains the following things: - latest AGC settings for MT2266-based devices (namely Nova-TD and other) will improve the sensitivity - support for STK7700D reference design in dib0700-devices - remove some line-breaks when debugging is enabled - getting rid of layer between frontend_parameters and ofdm_channel used in dib*-drivers Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 148 +++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/frontends/dib3000mc.c | 170 ++-- drivers/media/dvb/frontends/dib7000m.c | 723 ++++++++++------ drivers/media/dvb/frontends/dib7000p.c | 860 +++++++++++++------ drivers/media/dvb/frontends/dib7000p.h | 7 +- drivers/media/dvb/frontends/dibx000_common.h | 57 +- drivers/media/dvb/frontends/mt2266.c | 4 +- 8 files changed, 1277 insertions(+), 693 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 122d9d4b4baa..04b66f6e659f 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -4,7 +4,7 @@ * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 2. * - * Copyright (C) 2005-6 DiBcom, SA + * Copyright (C) 2005-7 DiBcom, SA */ #include "dib0700.h" @@ -99,41 +99,87 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) /* STK7700D: Pinnacle Dual DVB-T Diversity */ -static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = { - BAND_UHF/* | BAND_VHF*/, - 0xE64, // setup - 2372, // inv_gain - 21, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 0, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha - - 65535, // agc1_max - 0, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - 0, // agc1_pt1 - 128, // agc1_pt2 - 128, // agc1_pt3 - 128, // agc1_slope1 - 0, // agc1_slope2 - 128, // agc2_pt1 - 253, // agc2_pt2 - 81, // agc2_slope1 - 0, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - - 23, // beta_mant - 51, // beta_exp - - 0, // perform_agc_softsplit : 1 en vrai! +/* MT226x */ +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { + { + BAND_UHF, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + 1130, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 33770, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 62, // agc1_pt2 + 255, // agc1_pt3 + 64, // agc1_slope1 + 64, // agc1_slope2 + 132, // agc2_pt1 + 192, // agc2_pt2 + 80, // agc2_slope1 + 80, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + }, { + BAND_VHF | BAND_LBAND, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + } }; static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { @@ -150,23 +196,25 @@ static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, }, { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, } }; @@ -211,7 +259,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[4]; int i; @@ -241,7 +289,7 @@ int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) #define KEY_MAP_SIZE (25+48) -struct dvb_usb_rc_key stk7700d_rc_keys[] = { +static struct dvb_usb_rc_key stk7700d_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, { 0x07, 0x01, KEY_MENU }, // Pinnacle logo @@ -436,6 +484,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = { static struct dib7000p_config stk7700p_dib7000p_config = { .output_mpeg2_in_188_bytes = 1, + .agc_config_count = 1, .agc = &stk7700p_7000p_mt2060_agc_config, .bw = &stk7700p_pll_config, @@ -506,6 +555,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -615,7 +665,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "Pinnacle PCTV 2000e", { &dib0700_usb_id_table[11], NULL }, @@ -629,6 +679,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[13], NULL }, { NULL }, }, + { "DiBcom STK7700D", + { &dib0700_usb_id_table[14], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = stk7700d_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2e38be3aa45b..5657ad8beaac 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -67,6 +67,7 @@ #define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 +#define USB_PID_DIBCOM_STK7700D 0x1ef0 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 054d7e6d9662..cbbe2c2f05dc 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -1,7 +1,7 @@ /* * Driver for DiBcom DiB3000MC/P-demodulator. * - * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * This code is partially based on the previous dib3000mc.c . @@ -26,7 +26,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { struct dvb_frontend demod; @@ -71,7 +71,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } - static int dib3000mc_identify(struct dib3000mc_state *state) { u16 value; @@ -92,7 +91,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state) return 0; } -static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset) +static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) { u32 timf; @@ -103,7 +102,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, } else timf = state->timf; - timf *= (BW_INDEX_TO_KHZ(bw) / 1000); + timf *= (bw / 1000); if (update_offset) { s16 tim_offs = dib3000mc_read_word(state, 416); @@ -111,17 +110,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, if (tim_offs & 0x2000) tim_offs -= 0x4000; - if (nfft == 0) + if (nfft == TRANSMISSION_MODE_2K) tim_offs *= 4; timf += tim_offs; - state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000); + state->timf = timf / (bw / 1000); } dprintk("timf: %d\n", timf); - dib3000mc_write_word(state, 23, timf >> 16); - dib3000mc_write_word(state, 24, timf & 0xffff); + dib3000mc_write_word(state, 23, (u16) (timf >> 16)); + dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); return 0; } @@ -209,31 +208,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) return ret; } -static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) +static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) { - struct dib3000mc_state *state = demod->demodulator_priv; u16 bw_cfg[6] = { 0 }; u16 imp_bw_cfg[3] = { 0 }; u16 reg; /* settings here are for 27.7MHz */ switch (bw) { - case BANDWIDTH_8_MHZ: + case 8000: bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; break; - case BANDWIDTH_7_MHZ: + case 7000: bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; break; - case BANDWIDTH_6_MHZ: + case 6000: bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; break; - case 255 /* BANDWIDTH_5_MHZ */: + case 5000: bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; break; @@ -257,7 +255,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); // Timing configuration - dib3000mc_set_timing(state, 0, bw, 0); + dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); return 0; } @@ -276,7 +274,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, for (i = 58; i < 87; i++) dib3000mc_write_word(state, i, impulse_noise_val[i-58]); - if (nfft == 1) { + if (nfft == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 58, 0x3b); dib3000mc_write_word(state, 84, 0x00); dib3000mc_write_word(state, 85, 0x8200); @@ -376,7 +374,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) // P_search_maxtrial=1 dib3000mc_write_word(state, 5, 1); - dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib3000mc_set_bandwidth(state, 8000); // div_lock_mask dib3000mc_write_word(state, 4, 0x814); @@ -397,7 +395,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) dib3000mc_write_word(state, 180, 0x2FF0); // Impulse noise configuration - dib3000mc_set_impulse_noise(state, 0, 1); + dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); // output mode set-up dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); @@ -423,13 +421,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) { u16 cfg[4] = { 0 },reg; switch (qam) { - case 0: + case QPSK: cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; break; - case 1: + case QAM_16: cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; break; - case 2: + case QAM_64: cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; break; } @@ -437,11 +435,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) dib3000mc_write_word(state, reg, cfg[reg - 129]); } -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq) +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) { - u16 tmp; - - dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0); + u16 value; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); // if (boost) // dib3000mc_write_word(state, 100, (11 << 6) + 6); @@ -455,7 +453,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 26, 0x6680); dib3000mc_write_word(state, 29, 0x1273); dib3000mc_write_word(state, 33, 5); - dib3000mc_set_adp_cfg(state, 1); + dib3000mc_set_adp_cfg(state, QAM_16); dib3000mc_write_word(state, 133, 15564); dib3000mc_write_word(state, 12 , 0x0); @@ -470,52 +468,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); - dib3000mc_set_impulse_noise(state, 0, chan->nfft); - - tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha; - dib3000mc_write_word(state, 0, tmp); + dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib3000mc_write_word(state, 0, value); dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); - tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp); - if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp)) - tmp |= chan->vit_code_rate_hp << 1; - else - tmp |= chan->vit_code_rate_lp << 1; - dib3000mc_write_word(state, 181, tmp); + value = 0; + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib3000mc_write_word(state, 181, value); - // diversity synchro delay - tmp = dib3000mc_read_word(state, 180) & 0x000f; - tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin - dib3000mc_write_word(state, 180, tmp); + // diversity synchro delay add 50% SFN margin + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + value <<= 4; + value |= dib3000mc_read_word(state, 180) & 0x000f; + dib3000mc_write_word(state, 180, value); // restart demod - tmp = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, tmp | (1 << 9)); - dib3000mc_write_word(state, 0, tmp); + value = dib3000mc_read_word(state, 0); + dib3000mc_write_word(state, 0, value | (1 << 9)); + dib3000mc_write_word(state, 0, value); msleep(30); - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft); + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); } -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan) +static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) { struct dib3000mc_state *state = demod->demodulator_priv; u16 reg; // u32 val; - struct dibx000_ofdm_channel fchan; + struct dvb_frontend_parameters schan; - INIT_OFDM_CHANNEL(&fchan); - fchan = *chan; + schan = *chan; + /* TODO what is that ? */ /* a channel for autosearch */ - fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2; - fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2; - fchan.vit_hrch = 0; fchan.vit_select_hp = 1; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_2_3; + schan.u.ofdm.hierarchy_information = 0; - dib3000mc_set_channel_cfg(state, &fchan, 11); + dib3000mc_set_channel_cfg(state, &schan, 11); reg = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, reg | (1 << 8)); @@ -539,7 +583,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib3000mc_state *state = demod->demodulator_priv; @@ -549,9 +593,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe // activates isi dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_set_adp_cfg(state, (u8)ch->nqam); - - if (ch->nfft == 1) { + dib3000mc_set_adp_cfg(state, (uint8_t)ch->u.ofdm.constellation); + if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { @@ -560,7 +603,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe } if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); return 0; } @@ -632,13 +675,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); @@ -651,7 +690,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 100, found; - dib3000mc_autosearch_start(fe, &ch); + dib3000mc_autosearch_start(fe, fep); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); @@ -662,13 +701,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, return 0; // no channel found dib3000mc_get_frontend(fe, fep); - FEP2DIB(fep,&ch); } /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib3000mc_tune(fe, &ch); + return dib3000mc_tune(fe, fep); } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index f64546c6aeb5..608156a691de 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -2,7 +2,7 @@ * Linux-DVB Driver for DiBcom's DiB7000M and * first generation DiB7000P-demodulator-family. * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,7 +19,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) struct dib7000m_state { struct dvb_frontend demod; @@ -39,8 +39,16 @@ struct dib7000m_state { fe_bandwidth_t current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; + u32 timf_default; + u32 internal_clk; + + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; u16 revision; + + u8 agc_state; }; enum dib7000m_power_mode { @@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC + r++; + + do { + dib7000m_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) { int ret = 0; @@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", - &state->demod, mode); + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } @@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) ret |= dib7000m_write_word(state, 1795, outreg); ret |= dib7000m_write_word(state, 1805, sram); + if (state->revision == 0x4003) { + u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; + if (mode == OUTMODE_DIVERSITY) + clk_cfg1 |= (1 << 1); // P_O_CLK_en + dib7000m_write_word(state, 909, clk_cfg1); + } return ret; } -static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) +static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) { /* by default everything is going to be powered off */ u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; + u8 offset = 0; /* now, depending on the requested mode, we power on */ switch (mode) { @@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p if (!state->cfg.mobile_mode) reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); - /* P_sdio_select_clk = 0 on MC */ + /* P_sdio_select_clk = 0 on MC and after*/ if (state->revision != 0x4000) reg_906 <<= 1; - dib7000m_write_word(state, 903, reg_903); - dib7000m_write_word(state, 904, reg_904); - dib7000m_write_word(state, 905, reg_905); - dib7000m_write_word(state, 906, reg_906); + if (state->revision == 0x4003) + offset = 1; - return 0; + dib7000m_write_word(state, 903 + offset, reg_903); + dib7000m_write_word(state, 904 + offset, reg_904); + dib7000m_write_word(state, 905 + offset, reg_905); + dib7000m_write_word(state, 906 + offset, reg_906); } static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) @@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc break; } -// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914); - +// dprintk( "913: %x, 914: %x", reg_913, reg_914); ret |= dib7000m_write_word(state, 913, reg_913); ret |= dib7000m_write_word(state, 914, reg_914); return ret; } -static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx) +static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) { - struct dib7000m_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = bw_idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); - timf = state->cfg.bw->timf; + dprintk( "using default timf"); + timf = state->timf_default; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dib7000m_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000m_write_word(state, 24, (timf ) & 0xffff); + dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); + + return 0; +} + +static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000m_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000m_write_word(state, 263 + state->reg_offs, 6); + dib7000m_write_word(state, 264 + state->reg_offs, 6); + dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000m_write_word(state, 263 + state->reg_offs, 1); + dib7000m_write_word(state, 264 + state->reg_offs, 0); + dib7000m_write_word(state, 266 + state->reg_offs, 0); + } return 0; } @@ -266,7 +321,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) { /* internal */ -// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 @@ -281,10 +336,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) { - dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff); - dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000m_write_word(state, 22, bw->ifreq & 0xffff); + dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); + dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); dib7000m_write_word(state, 928, bw->sad_cfg); } @@ -325,15 +380,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state) static void dib7000mc_reset_pll(struct dib7000m_state *state) { const struct dibx000_bandwidth_config *bw = state->cfg.bw; + u16 clk_cfg1; // clk_cfg0 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); // clk_cfg1 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | - dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) | + clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | - (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0)); + (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); + dib7000m_write_word(state, 908, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); + dib7000m_write_word(state, 908, clk_cfg1); // smpl_cfg dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); @@ -344,9 +403,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state) static int dib7000m_reset_gpio(struct dib7000m_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n", - st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos); - dib7000m_write_word(st, 773, st->cfg.gpio_dir); dib7000m_write_word(st, 774, st->cfg.gpio_val); @@ -358,6 +414,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st) return 0; } +static u16 dib7000m_defaults_common[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_corm_thres Lock algorithms configuration + + 1, 170, + 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on + + 8, 173, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 182, + 8192, // P_fft_nb_to_cut + + 2, 195, + 0x0ccd, // P_pha3_thres + 0, // P_cti_use_cpe, P_cti_use_prog + + 1, 205, + 0x200f, // P_cspu_regul, P_cspu_win_cut + + 5, 214, + 0x023d, // P_adp_regul_cnt + 0x00a4, // P_adp_noise_cnt + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 226, + 0, // P_2d_byp_ti_num + + 1, 255, + 0x800, // P_equal_thres_wgn + + 1, 263, + 0x0001, + + 1, 281, + 0x0010, // P_fec_* + + 1, 294, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 0 +}; + +static u16 dib7000m_defaults[] = + +{ + /* set ADC level to -16 */ + 11, 76, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + // Tuner IO bank: max drive (14mA) + 1, 912, + 0x2c8a, + + 1, 1817, + 1, + + 0, +}; + static int dib7000m_demod_reset(struct dib7000m_state *state) { dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); @@ -382,22 +539,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state) dib7000mc_reset_pll(state); if (dib7000m_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); - dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib7000m_set_bandwidth(state, 8000); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib7000m_sad_calib(state); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + if (state->cfg.dvbt_mode) + dib7000m_write_word(state, 1796, 0x0); // select DVB-T output + + if (state->cfg.mobile_mode) + dib7000m_write_word(state, 261 + state->reg_offs, 2); + else + dib7000m_write_word(state, 224 + state->reg_offs, 1); + + // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000m_write_word(state, 36, 0x0755); + else + dib7000m_write_word(state, 36, 0x1f55); + + // P_divclksel=3 P_divbitsel=1 + if (state->revision == 0x4000) + dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); + else + dib7000m_write_word(state, 909, (3 << 4) | 1); + + dib7000m_write_tab(state, dib7000m_defaults_common); + dib7000m_write_tab(state, dib7000m_defaults); + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); + state->internal_clk = state->cfg.bw->internal; + return 0; } @@ -427,7 +609,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - dprintk("AGC split_offset: %d\n",split_offset); + dprintk( "AGC split_offset: %d",split_offset); // P_agc_force_split and P_agc_split_offset return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); @@ -435,35 +617,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) static int dib7000m_update_lna(struct dib7000m_state *state) { - int i; u16 dyn_gain; - // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return 0; - - msleep(60); - for (i = 0; i < 20; i++) { + if (state->cfg.update_lna) { // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib7000m_read_word(state, 390); - dprintk("agc global: %d\n", dyn_gain); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000m_restart_agc(state); - msleep(60); - } else - break; + return 1; + } } return 0; } -static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) +static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) { struct dibx000_agc_config *agc = NULL; int i; - if (state->current_band == band) - return; + if (state->current_band == band && state->current_agc != NULL) + return 0; state->current_band = band; for (i = 0; i < state->cfg.agc_config_count; i++) @@ -473,8 +646,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) } if (agc == NULL) { - dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band); - return; + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } state->current_agc = agc; @@ -489,7 +662,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); /* AGC continued */ @@ -510,7 +683,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) if (state->revision > 0x4000) { // settings for the MC dib7000m_write_word(state, 71, agc->agc1_pt3); -// dprintk("-D- 929: %x %d %d\n", +// dprintk( "929: %x %d %d", // (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); } else { @@ -519,33 +692,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) for (i = 0; i < 9; i++) dib7000m_write_word(state, 88 + i, b[i]); } + return 0; } -static void dib7000m_update_timf_freq(struct dib7000m_state *state) +static void dib7000m_update_timf(struct dib7000m_state *state) { u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000m_write_word(state, 23, (u16) (timf >> 16)); dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); } -static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + u16 cfg_72 = dib7000m_read_word(state, 72); + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); + dib7000m_set_adc_state(state, DIBX000_ADC_ON); + + if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; /* ADC power up */ + (*agc_state)++; + break; + + case 1: + /* AGC initialization */ + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000m_write_word(state, 75, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000m_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ + dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000m_read_word(state, 392); /* store the split value for the next time */ + dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ + + dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ + dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000m_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + /* wait AGC accurate lock time */ + ret = 7; + + if (dib7000m_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else + (*agc_state)++; + break; + + case 5: + dib7000m_agc_soft_split(state); + + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + + (*agc_state)++; + break; + + default: + break; + } + return ret; +} + +static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) { u16 value, est[4]; - dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000m_write_word(state, 0, value); dib7000m_write_word(state, 5, (seq << 4)); - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - value |= (ch->vit_code_rate_hp << 1); - else - value |= (ch->vit_code_rate_lp << 1); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } dib7000m_write_word(state, 267 + state->reg_offs, value); /* offset loop parameters */ @@ -563,32 +863,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of dib7000m_write_word(state, 33, (0 << 4) | 0x5); /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: value = 256; break; - case 2: value = 128; break; - case 0: + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: default: value = 64; break; } - value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - value <<= 4; + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || state->revision > 0x4000) - value |= (1 << 2) | (2 << 0); + if (1 == 1 || state->revision > 0x4000) + state->div_force_off = 0; else - value |= 0; - dib7000m_write_word(state, 266 + state->reg_offs, value); + state->div_force_off = 1; + dib7000m_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -604,70 +910,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of for (value = 0; value < 4; value++) dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); - // set power-up level: interf+analog+AGC - dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); - dib7000m_set_adc_state(state, DIBX000_ADC_ON); - - msleep(7); - - //AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000m_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000m_update_lna(state); - dib7000m_agc_soft_split(state); - - // wait AGC accurate lock time - msleep(7); - - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); - // set power-up level: autosearch dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); } -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; + struct dvb_frontend_parameters schan; int ret = 0; - u32 value; - - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; - - dib7000m_set_channel(state, &auto_ch, 7); + u32 value, factor; + + schan = *ch; + + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000m_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time // start search value = dib7000m_read_word(state, 0); - ret |= dib7000m_write_word(state, 0, value | (1 << 9)); + ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); /* clear n_irq_pending */ if (state->revision == 0x4000) @@ -685,12 +969,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) u16 irq_pending = dib7000m_read_word(state, reg); if (irq_pending & 0x1) { // failed - dprintk("#\n"); + dprintk( "autosearch failed"); return 1; } if (irq_pending & 0x2) { // succeeded - dprintk("!\n"); + dprintk( "autosearch succeeded"); return 2; } return 0; // still pending @@ -705,7 +989,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) return dib7000m_autosearch_irq(state, 537); } -static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; @@ -722,182 +1006,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel ret |= dib7000m_write_word(state, 898, 0x0000); msleep(45); - ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); + dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); - // never achieved a lock with that bandwidth so far - wait for timfreq to update + // never achieved a lock before - wait for timfreq to update if (state->timf == 0) msleep(200); //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: value |= (7 << 12); break; - case 1: value |= (9 << 12); break; - case 2: value |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (7 << 12); break; + case /* 4K MODE */ 255: value |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: value |= (9 << 12); break; } ret |= dib7000m_write_word(state, 26, value); /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 32, value); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 33, value); - // we achieved a lock - it's time to update the osc freq + // we achieved a lock - it's time to update the timf freq if ((dib7000m_read_word(state, 535) >> 6) & 0x1) - dib7000m_update_timf_freq(state); + dib7000m_update_timf(state); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return ret; } -static int dib7000m_init(struct dvb_frontend *demod) +static int dib7000m_wakeup(struct dvb_frontend *demod) { struct dib7000m_state *state = demod->demodulator_priv; - int ret = 0; - u8 o = state->reg_offs; dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk("-E- could not start Slow ADC\n"); - - if (state->cfg.dvbt_mode) - dib7000m_write_word(state, 1796, 0x0); // select DVB-T output - - if (state->cfg.mobile_mode) - ret |= dib7000m_write_word(state, 261 + o, 2); - else - ret |= dib7000m_write_word(state, 224 + o, 1); - - ret |= dib7000m_write_word(state, 173 + o, 0); - ret |= dib7000m_write_word(state, 174 + o, 0); - ret |= dib7000m_write_word(state, 175 + o, 0); - ret |= dib7000m_write_word(state, 176 + o, 0); - ret |= dib7000m_write_word(state, 177 + o, 0); - ret |= dib7000m_write_word(state, 178 + o, 0); - ret |= dib7000m_write_word(state, 179 + o, 0); - ret |= dib7000m_write_word(state, 180 + o, 0); - - // P_corm_thres Lock algorithms configuration - ret |= dib7000m_write_word(state, 26, 0x6680); - - // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on - ret |= dib7000m_write_word(state, 170 + o, 0x0410); - // P_fft_nb_to_cut - ret |= dib7000m_write_word(state, 182 + o, 8192); - // P_pha3_thres - ret |= dib7000m_write_word(state, 195 + o, 0x0ccd); - // P_cti_use_cpe, P_cti_use_prog - ret |= dib7000m_write_word(state, 196 + o, 0); - // P_cspu_regul, P_cspu_win_cut - ret |= dib7000m_write_word(state, 205 + o, 0x200f); - // P_adp_regul_cnt - ret |= dib7000m_write_word(state, 214 + o, 0x023d); - // P_adp_noise_cnt - ret |= dib7000m_write_word(state, 215 + o, 0x00a4); - // P_adp_regul_ext - ret |= dib7000m_write_word(state, 216 + o, 0x00a4); - // P_adp_noise_ext - ret |= dib7000m_write_word(state, 217 + o, 0x7ff0); - // P_adp_fil - ret |= dib7000m_write_word(state, 218 + o, 0x3ccc); - - // P_2d_byp_ti_num - ret |= dib7000m_write_word(state, 226 + o, 0); - - // P_fec_* - ret |= dib7000m_write_word(state, 281 + o, 0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000m_write_word(state, 294 + o,0x0062); + dprintk( "could not start Slow ADC"); - // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000m_write_word(state, 36, 0x0755); - else - ret |= dib7000m_write_word(state, 36, 0x1f55); - - // auto search configuration - ret |= dib7000m_write_word(state, 2, 0x0004); - ret |= dib7000m_write_word(state, 3, 0x1000); - ret |= dib7000m_write_word(state, 4, 0x0814); - ret |= dib7000m_write_word(state, 6, 0x001b); - ret |= dib7000m_write_word(state, 7, 0x7740); - ret |= dib7000m_write_word(state, 8, 0x005b); - ret |= dib7000m_write_word(state, 9, 0x8d80); - ret |= dib7000m_write_word(state, 10, 0x01c9); - ret |= dib7000m_write_word(state, 11, 0xc380); - ret |= dib7000m_write_word(state, 12, 0x0000); - ret |= dib7000m_write_word(state, 13, 0x0080); - ret |= dib7000m_write_word(state, 14, 0x0000); - ret |= dib7000m_write_word(state, 15, 0x0090); - ret |= dib7000m_write_word(state, 16, 0x0001); - ret |= dib7000m_write_word(state, 17, 0xd4c0); - ret |= dib7000m_write_word(state, 263 + o,0x0001); - - // P_divclksel=3 P_divbitsel=1 - if (state->revision == 0x4000) - dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); - else - dib7000m_write_word(state, 909, (3 << 4) | 1); - - // Tuner IO bank: max drive (14mA) - ret |= dib7000m_write_word(state, 912 ,0x2c8a); - - ret |= dib7000m_write_word(state, 1817, 1); - - return ret; + return 0; } static int dib7000m_sleep(struct dvb_frontend *demod) { struct dib7000m_state *st = demod->demodulator_priv; dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); - return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) | - dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | + dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); + return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib7000m_set_adc_state(st, DIBX000_ADC_OFF); } static int dib7000m_identify(struct dib7000m_state *state) { u16 value; + if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { - dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (0x%x)",value); return -EREMOTEIO; } state->revision = dib7000m_read_word(state, 897); if (state->revision != 0x4000 && state->revision != 0x4001 && - state->revision != 0x4002) { - dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value); + state->revision != 0x4002 && + state->revision != 0x4003) { + dprintk( "wrong Device ID (0x%x)",value); return -EREMOTEIO; } /* protect this driver to be used with 7000PC */ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { - dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n"); + dprintk( "this driver does not work with DiB7000PC"); return -EREMOTEIO; } switch (state->revision) { - case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break; - case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break; - case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break; + case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; + case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; + case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; + case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; } return 0; @@ -966,41 +1171,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000m_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000m_autosearch_start(fe, &ch); + dib7000m_autosearch_start(fe, fep); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000m_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000m_tune(fe, &ch); + return dib7000m_tune(fe, fep); } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -1087,7 +1296,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau if (dib7000m_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib7000m_identify(&st) != 0) { - dprintk("DiB7000M #%d: not identified\n", k); + dprintk("DiB7000M #%d: not identified", k); return -EIO; } } @@ -1100,7 +1309,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1172,7 +1381,7 @@ static struct dvb_frontend_ops dib7000m_ops = { .release = dib7000m_release, - .init = dib7000m_init, + .init = dib7000m_wakeup, .sleep = dib7000m_sleep, .set_frontend = dib7000m_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index c24189fcbc89..156c53ab56db 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1,7 +1,7 @@ /* * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,7 +18,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { struct dvb_frontend demod; @@ -36,12 +36,19 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; + + u8 agc_state; + u16 gpio_dir; u16 gpio_val; }; enum dib7000p_power_mode { DIB7000P_POWER_ALL = 0, + DIB7000P_POWER_ANALOG_ADC, DIB7000P_POWER_INTERFACE_ONLY, }; @@ -55,7 +62,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -71,6 +78,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + do { + dib7000p_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) { int ret = 0; @@ -80,7 +103,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { @@ -104,19 +127,17 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 512; outreg = (1 << 10) | (5 << 6); break; + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + break; case OUTMODE_HIGH_Z: // disable outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } - if (state->cfg.hostbus_diversity) { - ret |= dib7000p_write_word(state, 204, 1); // Diversity ? - ret |= dib7000p_write_word(state, 205, 0); // Diversity ? - } - if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; @@ -127,6 +148,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) return ret; } +static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000p_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000p_write_word(state, 204, 6); + dib7000p_write_word(state, 205, 16); + /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ + dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000p_write_word(state, 204, 1); + dib7000p_write_word(state, 205, 0); + dib7000p_write_word(state, 207, 0); + } + + return 0; +} + static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) { /* by default everything is powered off */ @@ -139,10 +184,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p case DIB7000P_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff; break; + + case DIB7000P_POWER_ANALOG_ADC: + /* dem, cfg, iqc, sad, agc */ + reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); + /* nud */ + reg_776 &= ~((1 << 0)); + /* Dout */ + reg_1280 &= ~((1 << 11)); + /* fall through wanted to enable the interfaces */ + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); break; + /* TODO following stuff is just converted from the dib7000-driver - check when is used what */ } @@ -193,34 +249,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad break; } -// dprintk("908: %x, 909: %x\n", reg_908, reg_909); +// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); dib7000p_write_word(state, 908, reg_908); dib7000p_write_word(state, 909, reg_909); } -static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) +static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) { - struct dib7000p_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = BW_Idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); + dprintk( "using default timf"); timf = state->cfg.bw->timf; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dprintk("timf: %d\n",timf); - - dib7000p_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000p_write_word(state, 24, (timf ) & 0xffff); + dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff)); return 0; } @@ -228,7 +281,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) static int dib7000p_sad_calib(struct dib7000p_state *state) { /* internal */ -// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096 @@ -244,15 +297,24 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; + u16 clk_cfg0; + + /* force PLL bypass */ + clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | + (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | + (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); + dib7000p_write_word(state, 900, clk_cfg0); + + /* P_pll_cfg */ dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); - dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) | - (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0)); + clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); + dib7000p_write_word(state, 900, clk_cfg0); - dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff); - dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff); + dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff)); + dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff)); dib7000p_write_word(state, 72, bw->sad_cfg); } @@ -260,7 +322,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state) static int dib7000p_reset_gpio(struct dib7000p_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); + dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); @@ -273,6 +335,98 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static u16 dib7000p_defaults[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, /* Equal Lock */ + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 + + /* set ADC level to -16 */ + 11, 79, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + 1, 142, + 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 + + /* disable power smoothing */ + 8, 145, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 154, + 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 + + 1, 168, + 0x0ccd, // P_pha3_thres, default 0x3000 + +// 1, 169, +// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 + + 1, 183, + 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + + 5, 187, + 0x023d, // P_adp_regul_cnt=573, default: 410 + 0x00a4, // P_adp_noise_cnt= + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 198, + 0x800, // P_equal_thres_wgn + + 1, 222, + 0x0010, // P_fec_ber_rs_len=2 + + 1, 235, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 2, 901, + 0x0006, // P_clk_cfg1 + (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 + + 1, 905, + 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive + + 0, +}; + static int dib7000p_demod_reset(struct dib7000p_state *state) { dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); @@ -297,111 +451,307 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_reset_pll(state); if (dib7000p_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) ); + dib7000p_set_bandwidth(state, 8000); + + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib7000p_sad_calib(state); + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000p_write_word(state, 36,0x0755); + else + dib7000p_write_word(state, 36,0x1f55); + + dib7000p_write_tab(state, dib7000p_defaults); + dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return 0; } +static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) +{ + u16 tmp = 0; + tmp = dib7000p_read_word(state, 903); + dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll + tmp = dib7000p_read_word(state, 900); + dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock +} + static void dib7000p_restart_agc(struct dib7000p_state *state) { // P_restart_iqc & P_restart_agc - dib7000p_write_word(state, 770, 0x0c00); + dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); dib7000p_write_word(state, 770, 0x0000); } -static void dib7000p_update_lna(struct dib7000p_state *state) +static int dib7000p_update_lna(struct dib7000p_state *state) { - int i; u16 dyn_gain; // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return; - - for (i = 0; i < 5; i++) { + if (state->cfg.update_lna) { // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib7000p_read_word(state, 394); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000p_restart_agc(state); - msleep(5); - } else + return 1; + } + } + + return 0; +} + +static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; break; + } + + if (agc == NULL) { + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } + + state->current_agc = agc; + + /* AGC */ + dib7000p_write_word(state, 75 , agc->setup ); + dib7000p_write_word(state, 76 , agc->inv_gain ); + dib7000p_write_word(state, 77 , agc->time_stabiliz ); + dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); + dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); + + /* AGC continued */ + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + if (state->wbd_ref != 0) + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); + else + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); + + dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); + + dib7000p_write_word(state, 107, agc->agc1_max); + dib7000p_write_word(state, 108, agc->agc1_min); + dib7000p_write_word(state, 109, agc->agc2_max); + dib7000p_write_word(state, 110, agc->agc2_min); + dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib7000p_write_word(state, 112, agc->agc1_pt3); + dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + return 0; } -static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) +static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { - u16 tmp = 0; - tmp = dib7000p_read_word(state, 903); - dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll - tmp = dib7000p_read_word(state, 900); - dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock + struct dib7000p_state *state = demod->demodulator_priv; + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + dib7000p_set_adc_state(state, DIBX000_ADC_ON); + dib7000p_pll_clk_cfg(state); + + if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; + (*agc_state)++; + break; + + case 1: + // AGC initialization + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000p_write_word(state, 78, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + /* force 0 split on WBD and restart AGC */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000p_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000p_read_word(state, 396); /* store the split value for the next time */ + dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ + + dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000p_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + // wait AGC accurate lock time + ret = 7; + + if (dib7000p_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else // nothing was done, go to the next state + (*agc_state)++; + break; + + case 5: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + (*agc_state)++; + break; + default: + break; + } + return ret; } -static void dib7000p_update_timf_freq(struct dib7000p_state *state) +static void dib7000p_update_timf(struct dib7000p_state *state) { u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000p_write_word(state, 23, (u16) (timf >> 16)); dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf); + } -static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) { - u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208; + u16 value, est[4]; + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000p_write_word(state, 0, value); dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - tmp |= (ch->vit_code_rate_hp << 1); - else - tmp |= (ch->vit_code_rate_lp << 1); - dib7000p_write_word(state, 208, tmp); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib7000p_write_word(state, 208, value); + + /* offset loop parameters */ + dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) + dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 + dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: tmp = 256; break; - case 2: tmp = 128; break; - case 0: - default: tmp = 64; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; } - tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - tmp <<= 4; - - /* deactive the possibility of diversity reception if extended interleave */ - /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || ch->nfft == 1) - tmp |= (1 << 2) | (2 << 0); - dib7000p_write_word(state, 207, tmp); + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO - dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 - dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) - dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) + /* deactive the possibility of diversity reception if extended interleaver */ + state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + dib7000p_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -414,66 +764,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ break; } - for (tmp = 0; tmp < 4; tmp++) - dib7000p_write_word(state, 187 + tmp, est[tmp]); - - // set power-up level: interf+analog+AGC - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - dib7000p_set_adc_state(state, DIBX000_ADC_ON); - dib7000p_pll_clk_cfg(state); - msleep(7); - - // AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000p_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000p_update_lna(state); - - // wait AGC accurate lock time - msleep(7); - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); + for (value = 0; value < 4; value++) + dib7000p_write_word(state, 187 + value, est[value]); } -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; - u32 value; - - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; - - dib7000p_set_channel(state, &auto_ch, 7); + struct dvb_frontend_parameters schan; + u32 value, factor; + + schan = *ch; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000p_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time value = dib7000p_read_word(state, 0); - dib7000p_write_word(state, 0, (1 << 9) | value); + dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); dib7000p_read_word(state, 1284); dib7000p_write_word(state, 0, (u16) value); @@ -494,7 +823,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) +{ + static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392}; + static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, + 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, + 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, + 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, + 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, + 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, + 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, + 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, + 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, + 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, + 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, + 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255}; + + u32 xtal = state->cfg.bw->xtal_hz / 1000; + int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz; + int k; + int coef_re[8],coef_im[8]; + int bw_khz = bw; + u32 pha; + + dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + + + if (f_rel < -bw_khz/2 || f_rel > bw_khz/2) + return; + + bw_khz /= 100; + + dib7000p_write_word(state, 142 ,0x0610); + + for (k = 0; k < 8; k++) { + pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff; + + if (pha==0) { + coef_re[k] = 256; + coef_im[k] = 0; + } else if(pha < 256) { + coef_re[k] = sine[256-(pha&0xff)]; + coef_im[k] = sine[pha&0xff]; + } else if (pha == 256) { + coef_re[k] = 0; + coef_im[k] = 256; + } else if (pha < 512) { + coef_re[k] = -sine[pha&0xff]; + coef_im[k] = sine[256 - (pha&0xff)]; + } else if (pha == 512) { + coef_re[k] = -256; + coef_im[k] = 0; + } else if (pha < 768) { + coef_re[k] = -sine[256-(pha&0xff)]; + coef_im[k] = -sine[pha&0xff]; + } else if (pha == 768) { + coef_re[k] = 0; + coef_im[k] = -256; + } else { + coef_re[k] = sine[pha&0xff]; + coef_im[k] = -sine[256 - (pha&0xff)]; + } + + coef_re[k] *= notch[k]; + coef_re[k] += (1<<14); + if (coef_re[k] >= (1<<24)) + coef_re[k] = (1<<24) - 1; + coef_re[k] /= (1<<15); + + coef_im[k] *= notch[k]; + coef_im[k] += (1<<14); + if (coef_im[k] >= (1<<24)) + coef_im[k] = (1<<24)-1; + coef_im[k] /= (1<<15); + + dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + + dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); + dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + } + dib7000p_write_word(state,143 ,0); +} + +static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; u16 tmp = 0; @@ -520,28 +937,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: tmp |= (7 << 12); break; - case 1: tmp |= (9 << 12); break; - case 2: tmp |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break; + case /* 4K MODE */ 255: tmp |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break; } dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 32, tmp); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 33, tmp); @@ -557,131 +977,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel // we achieved a lock - it's time to update the osc freq if ((tmp >> 6) & 0x1) - dib7000p_update_timf_freq(state); + dib7000p_update_timf(state); + + if (state->cfg.spur_protect) + dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return 0; } -static int dib7000p_init(struct dvb_frontend *demod) +static int dib7000p_wakeup(struct dvb_frontend *demod) { - struct dibx000_agc_config *agc; struct dib7000p_state *state = demod->demodulator_priv; - int ret = 0; - - // Demodulator default configuration - agc = state->cfg.agc; - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); - - /* AGC */ - ret |= dib7000p_write_word(state, 75 , agc->setup ); - ret |= dib7000p_write_word(state, 76 , agc->inv_gain ); - ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz ); - ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); - ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); - - /* AGC continued */ - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - if (state->wbd_ref != 0) - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); - else - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); - - ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); - - ret |= dib7000p_write_word(state, 107, agc->agc1_max); - ret |= dib7000p_write_word(state, 108, agc->agc1_min); - ret |= dib7000p_write_word(state, 109, agc->agc2_max); - ret |= dib7000p_write_word(state, 110, agc->agc2_min); - ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); - ret |= dib7000p_write_word(state, 112, agc->agc1_pt3); - ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - - /* disable power smoothing */ - ret |= dib7000p_write_word(state, 145, 0); - ret |= dib7000p_write_word(state, 146, 0); - ret |= dib7000p_write_word(state, 147, 0); - ret |= dib7000p_write_word(state, 148, 0); - ret |= dib7000p_write_word(state, 149, 0); - ret |= dib7000p_write_word(state, 150, 0); - ret |= dib7000p_write_word(state, 151, 0); - ret |= dib7000p_write_word(state, 152, 0); - - // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 - ret |= dib7000p_write_word(state, 26 ,0x6680); - - // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 - ret |= dib7000p_write_word(state, 142,0x0410); - // P_fft_freq_dir=1, P_fft_nb_to_cut=0 - ret |= dib7000p_write_word(state, 154,1 << 13); - // P_pha3_thres, default 0x3000 - ret |= dib7000p_write_word(state, 168,0x0ccd); - // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 - //ret |= dib7000p_write_word(state, 169,0x0010); - // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 - ret |= dib7000p_write_word(state, 183,0x200f); - // P_adp_regul_cnt=573, default: 410 - ret |= dib7000p_write_word(state, 187,0x023d); - // P_adp_noise_cnt= - ret |= dib7000p_write_word(state, 188,0x00a4); - // P_adp_regul_ext - ret |= dib7000p_write_word(state, 189,0x00a4); - // P_adp_noise_ext - ret |= dib7000p_write_word(state, 190,0x7ff0); - // P_adp_fil - ret |= dib7000p_write_word(state, 191,0x3ccc); - - ret |= dib7000p_write_word(state, 222,0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000p_write_word(state, 235,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000p_write_word(state, 36,0x0755); - else - ret |= dib7000p_write_word(state, 36,0x1f55); - - // auto search configuration - ret |= dib7000p_write_word(state, 2 ,0x0004); - ret |= dib7000p_write_word(state, 3 ,0x1000); - - /* Equal Lock */ - ret |= dib7000p_write_word(state, 4 ,0x0814); - - ret |= dib7000p_write_word(state, 6 ,0x001b); - ret |= dib7000p_write_word(state, 7 ,0x7740); - ret |= dib7000p_write_word(state, 8 ,0x005b); - ret |= dib7000p_write_word(state, 9 ,0x8d80); - ret |= dib7000p_write_word(state, 10 ,0x01c9); - ret |= dib7000p_write_word(state, 11 ,0xc380); - ret |= dib7000p_write_word(state, 12 ,0x0000); - ret |= dib7000p_write_word(state, 13 ,0x0080); - ret |= dib7000p_write_word(state, 14 ,0x0000); - ret |= dib7000p_write_word(state, 15 ,0x0090); - ret |= dib7000p_write_word(state, 16 ,0x0001); - ret |= dib7000p_write_word(state, 17 ,0xd4c0); - - // P_clk_cfg1 - ret |= dib7000p_write_word(state, 901, 0x0006); - - // P_divclksel=3 P_divbitsel=1 - ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); - - // Tuner IO bank: max drive (14mA) + divout pads max drive - ret |= dib7000p_write_word(state, 905, 0x2c8e); - - ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); - dib7000p_sad_calib(state); - - return ret; + return 0; } static int dib7000p_sleep(struct dvb_frontend *demod) @@ -693,16 +1003,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod) static int dib7000p_identify(struct dib7000p_state *st) { u16 value; - dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n", + dprintk( "checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (read=0x%x)",value); return -EREMOTEIO; } if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value); + dprintk( "wrong Device ID (%x)",value); return -EREMOTEIO; } @@ -772,41 +1082,45 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000p_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000p_autosearch_start(fe, &ch); + dib7000p_autosearch_start(fe, fep); do { msleep(1); found = dib7000p_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000p_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000p_tune(fe, &ch); + return dib7000p_tune(fe, fep); } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -884,7 +1198,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } @@ -892,11 +1206,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } - dprintk("-D- DiB7000PC not detected\n"); + dprintk("-D- DiB7000PC not detected"); return 0; } EXPORT_SYMBOL(dib7000pc_detection); @@ -934,7 +1248,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1005,7 +1319,7 @@ static struct dvb_frontend_ops dib7000p_ops = { .release = dib7000p_release, - .init = dib7000p_init, + .init = dib7000p_wakeup, .sleep = dib7000p_sleep, .set_frontend = dib7000p_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 94829c1ed054..e7769e7cd92a 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -9,6 +9,7 @@ struct dib7000p_config { u8 tuner_is_baseband; int (*update_lna) (struct dvb_frontend *, u16 agc_global); + u8 agc_config_count; struct dibx000_agc_config *agc; struct dibx000_bandwidth_config *bw; @@ -27,15 +28,19 @@ struct dib7000p_config { u8 quartz_direct; + u8 spur_protect; + int (*agc_control) (struct dvb_frontend *, u8 before); }; #define DEFAULT_DIB7000P_I2C_ADDRESS 18 extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + /* TODO extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index a1df604366c3..5e17275afd25 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -111,6 +111,8 @@ struct dibx000_bandwidth_config { u32 ifreq; u32 timf; + + u32 xtal_hz; }; enum dibx000_adc_states { @@ -122,56 +124,17 @@ enum dibx000_adc_states { DIBX000_VBG_DISABLE, }; -#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ +#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) /* Chip output mode. */ -#define OUTMODE_HIGH_Z 0 -#define OUTMODE_MPEG2_PAR_GATED_CLK 1 -#define OUTMODE_MPEG2_PAR_CONT_CLK 2 -#define OUTMODE_MPEG2_SERIAL 7 -#define OUTMODE_DIVERSITY 4 -#define OUTMODE_MPEG2_FIFO 5 - -/* I hope I can get rid of the following kludge in the near future */ -struct dibx000_ofdm_channel { - u32 RF_kHz; - u8 Bw; - s16 nfft; - s16 guard; - s16 nqam; - s16 vit_hrch; - s16 vit_select_hp; - s16 vit_alpha; - s16 vit_code_rate_hp; - s16 vit_code_rate_lp; - u8 intlv_native; -}; - -#define FEP2DIB(fep,ch) \ - (ch)->RF_kHz = (fep)->frequency / 1000; \ - (ch)->Bw = (fep)->u.ofdm.bandwidth; \ - (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \ - (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \ - (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \ - (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \ - (ch)->vit_select_hp = 1; \ - (ch)->vit_alpha = 1; \ - (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \ - (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \ - (ch)->intlv_native = 1; - -#define INIT_OFDM_CHANNEL(ch) do {\ - (ch)->Bw = 0; \ - (ch)->nfft = -1; \ - (ch)->guard = -1; \ - (ch)->nqam = -1; \ - (ch)->vit_hrch = -1; \ - (ch)->vit_select_hp = -1; \ - (ch)->vit_alpha = -1; \ - (ch)->vit_code_rate_hp = -1; \ - (ch)->vit_code_rate_lp = -1; \ -} while (0) +#define OUTMODE_HIGH_Z 0 +#define OUTMODE_MPEG2_PAR_GATED_CLK 1 +#define OUTMODE_MPEG2_PAR_CONT_CLK 2 +#define OUTMODE_MPEG2_SERIAL 7 +#define OUTMODE_DIVERSITY 4 +#define OUTMODE_MPEG2_FIFO 5 +#define OUTMODE_ANALOG_ADC 6 #endif diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 145135778bce..33b388e8f7b8 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -159,7 +159,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband); + dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); b[0] = 0x05; @@ -176,7 +176,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame msleep(10); i++; } while (i<10); - dprintk("Lock when i=%i\n",(int)i); + dprintk("Lock when i=%i",(int)i); return ret; } -- GitLab