summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2012-03-05 18:24:28 +0100
committerHarald Welte <laforge@gnumonks.org>2012-03-05 18:25:11 +0100
commitc4c7c6add58f5989b4626d9e84ae6d0993f88eb0 (patch)
tree8c724fcdff209e5a7ce31d99c7cb25b45e08ec1b
parent5a23c521203d0c833babb9967c189bd42a378421 (diff)
e4k: add dc offset calibration code
-rw-r--r--firmware/include/tuner_e4k.h3
-rw-r--r--firmware/src/tuner_e4k.c75
2 files changed, 78 insertions, 0 deletions
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