From c4c7c6add58f5989b4626d9e84ae6d0993f88eb0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 5 Mar 2012 18:24:28 +0100 Subject: [PATCH] e4k: add dc offset calibration code --- firmware/include/tuner_e4k.h | 3 ++ firmware/src/tuner_e4k.c | 75 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/firmware/include/tuner_e4k.h b/firmware/include/tuner_e4k.h index df060eb..98ea889 100644 --- a/firmware/include/tuner_e4k.h +++ b/firmware/include/tuner_e4k.h @@ -205,4 +205,7 @@ int sam3u_e4k_init(struct e4k_state *e4k, void *i2c, uint8_t slave_addr); void sam3u_e4k_power(struct e4k_state *e4k, int on); void sam3u_e4k_stby(struct e4k_state *e4k, int on); +int e4k_dc_offset_calibrate(struct e4k_state *e4k); +int e4k_dc_offset_gen_table(struct e4k_state *e4k); + #endif /* _E4K_TUNER_H */ diff --git a/firmware/src/tuner_e4k.c b/firmware/src/tuner_e4k.c index 5246273..029a66c 100644 --- a/firmware/src/tuner_e4k.c +++ b/firmware/src/tuner_e4k.c @@ -684,6 +684,79 @@ int e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value) return e4k_reg_set_mask(e4k, field->reg, mask, rc << field->shift); } +/*********************************************************************** + * DC Offset */ + +/*! \brief Perform a DC offset calibration right now + * \param[e4k] handle to the tuner chip + */ +int e4k_dc_offset_calibrate(struct e4k_state *e4k) +{ + /* make sure the DC range detector is enabled */ + e4k_reg_set_mask(e4k, E4K_REG_DC5, E4K_DC5_RANGE_DET_EN, E4K_DC5_RANGE_DET_EN); + + return e4k_reg_write(e4k, E4K_REG_DC1, 0x01); +} + + +static const int8_t if_gains_max[] = { + 0, 6, 9, 9, 2, 15, 15 +}; + +struct gain_comb { + int8_t mixer_gain; + uint8_t if1_gain; + uint8_t reg; +}; + +static const struct gain_comb dc_gain_comb[] = { + { 0, -3, 0x50 }, + { 0, 6, 0x51 }, + { 12, -3, 0x52 }, + { 12, 6, 0x53 }, +}; + +#define TO_LUT(offset, range) (offset | (range << 6)) + +int e4k_dc_offset_gen_table(struct e4k_state *e4k) +{ + int i; + + /* FIXME: read ont current gain values and write them back + * before returning to the caller */ + + /* set all 'other' gains to maximum */ + for (i = 2; i <= 6; i++) + e4k_if_gain_set(e4k, i, if_gains_max[i]); + + /* iterate over all mixer + if_stage_1 gain combinations */ + for (i = 0; i < ARRAY_SIZE(dc_gain_comb); i++) { + uint8_t offs_i, offs_q, range_i, range_q; + + /* set the combination of mixer / if1 gain */ + e3k_mixer_gain_set(e4k, dc_gain_comb[i].mixer_gain); + e4k_if_gain_set(e4k, 1, dc_gain_comb[i].if1_gain); + + /* perform actual calibration */ + e4k_dc_offset_calibrate(e4k); + /* FIXME: do we have to wait? */ + + /* extract I/Q offset and range values */ + offs_i = e4k_reg_read(e4k, E4K_REG_DC2) & 0x3F; + offs_q = e4k_reg_read(e4k, E4K_REG_DC3) & 0x3F; + range_i = e4k_reg_read(e4k, E4K_REG_DC4) & 0x3; + range_q = (e4k_reg_read(e4k, E4K_REG_DC4) >> 4) & 0x3; + + /* write into the table */ + e4k_reg_write(e4k, dc_gain_comb[i].reg, + TO_LUT(offs_q, range_q)); + e4k_reg_write(e4k, dc_gain_comb[i].reg+0x10, + TO_LUT(offs_i, range_i)); + } + + return 0; +} + /*********************************************************************** * Initialization */ @@ -697,6 +770,8 @@ static int magic_init(struct e4k_state *e4k) e4k_reg_write(e4k, 0x88, 0x01); e4k_reg_write(e4k, 0x9f, 0x7f); e4k_reg_write(e4k, 0xa0, 0x07); + + return 0; } /*! \brief Initialize the E4K tuner