|
|
|
@ -251,9 +251,9 @@ static const uint32_t *if_filter_bw[] = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const uint32_t if_filter_bw_len[] = {
|
|
|
|
|
[E4K_IF_FILTER_MIX] = ARRAY_SIZE(&mix_filter_bw),
|
|
|
|
|
[E4K_IF_FILTER_CHAN] = ARRAY_SIZE(&ifch_filter_bw),
|
|
|
|
|
[E4K_IF_FILTER_RC] = ARRAY_SIZE(&ifrc_filter_bw),
|
|
|
|
|
[E4K_IF_FILTER_MIX] = ARRAY_SIZE(mix_filter_bw),
|
|
|
|
|
[E4K_IF_FILTER_CHAN] = ARRAY_SIZE(ifch_filter_bw),
|
|
|
|
|
[E4K_IF_FILTER_RC] = ARRAY_SIZE(ifrc_filter_bw),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct reg_field if_filter_fields[] = {
|
|
|
|
@ -300,6 +300,17 @@ int e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,
|
|
|
|
|
return e4k_field_write(e4k, field, bw_idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief Enables / Disables the channel filter
|
|
|
|
|
* \param[in] e4k reference to the tuner chip
|
|
|
|
|
* \param[in] on 1=filter enabled, 0=filter disabled
|
|
|
|
|
* \returns 0 success, negative errors
|
|
|
|
|
*/
|
|
|
|
|
int e4k_if_filter_chan_enable(struct e4k_state *e4k, int on)
|
|
|
|
|
{
|
|
|
|
|
return e4k_reg_set_mask(e4k, E4K_REG_FILT3, E4K_FILT3_DISABLE,
|
|
|
|
|
on ? 0 : E4K_FILT3_DISABLE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter)
|
|
|
|
|
{
|
|
|
|
|
const uint32_t *arr;
|
|
|
|
@ -707,7 +718,7 @@ int e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value)
|
|
|
|
|
uint8_t bit;
|
|
|
|
|
|
|
|
|
|
switch (value) {
|
|
|
|
|
case 0:
|
|
|
|
|
case 4:
|
|
|
|
|
bit = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 12:
|
|
|
|
@ -776,13 +787,13 @@ static const int8_t if_gains_max[] = {
|
|
|
|
|
|
|
|
|
|
struct gain_comb {
|
|
|
|
|
int8_t mixer_gain;
|
|
|
|
|
uint8_t if1_gain;
|
|
|
|
|
int8_t if1_gain;
|
|
|
|
|
uint8_t reg;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct gain_comb dc_gain_comb[] = {
|
|
|
|
|
{ 0, -3, 0x50 },
|
|
|
|
|
{ 0, 6, 0x51 },
|
|
|
|
|
{ 4, -3, 0x50 },
|
|
|
|
|
{ 4, 6, 0x51 },
|
|
|
|
|
{ 12, -3, 0x52 },
|
|
|
|
|
{ 12, 6, 0x53 },
|
|
|
|
|
};
|
|
|
|
@ -796,13 +807,20 @@ int e4k_dc_offset_gen_table(struct e4k_state *e4k)
|
|
|
|
|
/* FIXME: read ont current gain values and write them back
|
|
|
|
|
* before returning to the caller */
|
|
|
|
|
|
|
|
|
|
/* disable auto mixer gain */
|
|
|
|
|
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);
|
|
|
|
|
|
|
|
|
|
/* set LNA/IF gain to full manual */
|
|
|
|
|
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK,
|
|
|
|
|
E4K_AGC_MOD_SERIAL);
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
uint8_t offs_i, offs_q, range, range_i, range_q;
|
|
|
|
|
|
|
|
|
|
/* set the combination of mixer / if1 gain */
|
|
|
|
|
e4k_mixer_gain_set(e4k, dc_gain_comb[i].mixer_gain);
|
|
|
|
@ -810,16 +828,17 @@ int e4k_dc_offset_gen_table(struct e4k_state *e4k)
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
range = e4k_reg_read(e4k, E4K_REG_DC4);
|
|
|
|
|
range_i = range & 0x3;
|
|
|
|
|
range_q = (range >> 4) & 0x3;
|
|
|
|
|
|
|
|
|
|
LOGP(DTUN, LOGL_DEBUG, "Table %u I=%u/%u, Q=%u/%u\n",
|
|
|
|
|
i, range_i, offs_i, range_q, offs_q);
|
|
|
|
|
|
|
|
|
|
/* write into the table */
|
|
|
|
|
e4k_reg_write(e4k, dc_gain_comb[i].reg,
|
|
|
|
|
TO_LUT(offs_q, range_q));
|
|
|
|
@ -838,6 +857,7 @@ static int magic_init(struct e4k_state *e4k)
|
|
|
|
|
{
|
|
|
|
|
e4k_reg_write(e4k, 0x7e, 0x01);
|
|
|
|
|
e4k_reg_write(e4k, 0x7f, 0xfe);
|
|
|
|
|
e4k_reg_write(e4k, 0x82, 0x00);
|
|
|
|
|
e4k_reg_write(e4k, 0x86, 0x50); /* polarity A */
|
|
|
|
|
e4k_reg_write(e4k, 0x87, 0x20);
|
|
|
|
|
e4k_reg_write(e4k, 0x88, 0x01);
|
|
|
|
@ -854,39 +874,54 @@ int e4k_init(struct e4k_state *e4k)
|
|
|
|
|
/* make a dummy i2c read or write command, will not be ACKed! */
|
|
|
|
|
e4k_reg_read(e4k, 0);
|
|
|
|
|
|
|
|
|
|
/* write some magic values into registers */
|
|
|
|
|
/* Make sure we reset everything and clear POR indicator */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_MASTER1,
|
|
|
|
|
E4K_MASTER1_RESET |
|
|
|
|
|
E4K_MASTER1_NORM_STBY |
|
|
|
|
|
E4K_MASTER1_POR_DET
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Configure clock input */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_CLK_INP, 0x00);
|
|
|
|
|
|
|
|
|
|
/* Disable clock output */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_REF_CLK, 0x00);
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_CLKOUT_PWDN, 0x96);
|
|
|
|
|
|
|
|
|
|
/* Write some magic values into registers */
|
|
|
|
|
magic_init(e4k);
|
|
|
|
|
|
|
|
|
|
/* Set common mode voltage a bit higher for more margin 850 mv */
|
|
|
|
|
e4k_commonmode_set(e4k, 4);
|
|
|
|
|
|
|
|
|
|
/* Initialize DC offset lookup tables */
|
|
|
|
|
e4k_dc_offset_gen_table(e4k);
|
|
|
|
|
|
|
|
|
|
/* Enable time variant DC correction */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_DCTIME1, 0x01);
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_DCTIME2, 0x01);
|
|
|
|
|
|
|
|
|
|
/* Set LNA mode to autnonmous */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_AGC4, 0x10); /* High threshold */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_AGC5, 0x04); /* Low threshold */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_AGC6, 0x1a); /* LNA calib + loop rate */
|
|
|
|
|
|
|
|
|
|
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK,
|
|
|
|
|
E4K_AGC_MOD_IF_SERIAL_LNA_AUTON);
|
|
|
|
|
|
|
|
|
|
/* Set Miser Gain Control to autonomous */
|
|
|
|
|
/* Set Mixer Gain Control to autonomous */
|
|
|
|
|
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO,
|
|
|
|
|
E4K_AGC7_MIX_GAIN_AUTO);
|
|
|
|
|
|
|
|
|
|
/* Enable LNA Gain enhancement */
|
|
|
|
|
#if 0
|
|
|
|
|
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7,
|
|
|
|
|
E4K_AGC11_LNA_GAIN_ENH | (2 << 1));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Enable automatic IF gain mode switching */
|
|
|
|
|
e4k_reg_set_mask(e4k, E4K_REG_AGC8, 0x1, E4K_AGC8_SENS_LIN_AUTO);
|
|
|
|
|
|
|
|
|
|
/* FIXME: do we need to program Output Common Mode voltage ? */
|
|
|
|
|
|
|
|
|
|
/* FIXME: initialize DC offset lookup tables */
|
|
|
|
|
|
|
|
|
|
/* Disable Clock output, write 0x96 into 0x7A */
|
|
|
|
|
e4k_reg_write(e4k, E4K_REG_CLKOUT_PWDN, E4K_CLKOUT_DISABLE);
|
|
|
|
|
|
|
|
|
|
/* Clear the reset-detect register */
|
|
|
|
|
e4k_reg_set_mask(e4k, E4K_REG_MASTER1, E4K_MASTER1_POR_DET, E4K_MASTER1_POR_DET);
|
|
|
|
|
|
|
|
|
|
/* Set the most narrow filter we can possibly use */
|
|
|
|
|
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_MIX, KHZ(1900));
|
|
|
|
|
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_RC, KHZ(1000));
|
|
|
|
|
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_CHAN, KHZ(2150));
|
|
|
|
|
#if 0
|
|
|
|
|
/* Select moderate gain levels */
|
|
|
|
|
e4k_if_gain_set(e4k, 1, 6);
|
|
|
|
|
e4k_if_gain_set(e4k, 2, 3);
|
|
|
|
@ -894,5 +929,10 @@ int e4k_init(struct e4k_state *e4k)
|
|
|
|
|
e4k_if_gain_set(e4k, 4, 1);
|
|
|
|
|
e4k_if_gain_set(e4k, 5, 9);
|
|
|
|
|
e4k_if_gain_set(e4k, 6, 9);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Set the most narrow filter we can possibly use */
|
|
|
|
|
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_MIX, KHZ(1900));
|
|
|
|
|
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_RC, KHZ(1000));
|
|
|
|
|
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_CHAN, KHZ(2150));
|
|
|
|
|
e4k_if_filter_chan_enable(e4k, 1);
|
|
|
|
|
}
|
|
|
|
|