Compare commits

...
This repository has been archived on 2022-02-18. You can view files and clone it, but cannot push or open issues or pull requests.

11 Commits

Author SHA1 Message Date
Sylvain Munaut 0297cd029b fw/tuner_e4k: Experimental new init sequence
More complete ... Tries to bring up the e4k to a usable
state all at once.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:59:18 +02:00
Sylvain Munaut b2b5d6518b fw/tuner_e4k: Add some more magic init
It comes from the kernel driver. No idea what it does really ...

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:37:29 +02:00
Sylvain Munaut 29f13b5c18 fw/sdr-test: Add command for direct e4k register manipulation R/W
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:36:37 +02:00
Sylvain Munaut b0baaab491 uart_cmd: Add support for read commands with arguments
The syntax is really not obvious, but at least the implementation
is simple ...

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:36:12 +02:00
Sylvain Munaut 1ba8c169ee fw/tuner_e4k: Add function to enable/disable the IF channel filter
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:35:32 +02:00
Sylvain Munaut 16202796ae fw/tuner_e4k: Disable auto gain adjustement during DC table gen
We need them to be fixed during that time, so disable all auto
stuff

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:34:25 +02:00
Sylvain Munaut 161ad3c469 fw/tuner_e4k: Avoid dual read of DC4 when generating DC table
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:33:25 +02:00
Sylvain Munaut 24c3a9a196 fw/tuner_e4k: DC offset table gen doc fixes
No we don't need to wait. I checked if the value ever changed after
the first read and it doesn't. Other e4k drivers don't wait either.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 21:32:24 +02:00
Sylvain Munaut 5442a0dbe1 fw/tuner_e4k: Use signed int for if1_gain in the gain combination array
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 16:19:07 +02:00
Sylvain Munaut d2f56043ef fw/tuner_e4k: Mixer gain is 4 or 12 dB, not 0/12
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-04-01 16:18:27 +02:00
Sylvain Munaut eeaa36a1fb fw/tuner_e4k: Fix the array_size of the filter fw settings.
This was causing the array length to be '1' and so we always
took the first possible setting (the widest) ...

Certainly not good when you only have a 500 kHz sample rate.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2012-03-31 23:28:31 +02:00
4 changed files with 105 additions and 29 deletions

View File

@ -198,6 +198,7 @@ int e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t
int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter);
int e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,
uint32_t bandwidth);
int e4k_if_filter_chan_enable(struct e4k_state *e4k, int on);
int e4k_rf_filter_set(struct e4k_state *e4k);
int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val);

View File

@ -335,6 +335,34 @@ static int cmd_tuner_iqofs(struct cmd_state *cs, enum cmd_op op,
return e4k_manual_dc_offset(&e4k, iofs, irange, qofs, qrange);
}
static int cmd_tuner_reg(struct cmd_state *cs, enum cmd_op op,
const char *cmd, int argc, char ** argv)
{
uint8_t reg, val;
if (argc < 1)
return -EINVAL;
reg = strtol(argv[0], NULL, 16);
switch (op) {
case CMD_OP_GET:
val = e4k_reg_read(&e4k, reg);
uart_cmd_out(cs, "%02x=%02x\n\r", reg, val);
break;
case CMD_OP_SET:
if (argc < 2)
return -EINVAL;
val = strtol(argv[1], NULL, 16);
e4k_reg_write(&e4k, reg, val);
break;
default:
return -EINVAL;
}
return 0;
}
static int cmd_dfu(struct cmd_state *cs, enum cmd_op op,
const char *cmd, int argc, char ** argv)
{
@ -363,6 +391,8 @@ static struct cmd cmds[] = {
"Switch common mode voltage" },
{ "tuner.iqofs", CMD_OP_SET, cmd_tuner_iqofs,
"Manually set I/Q offset and correction range" },
{ "tuner.reg", CMD_OP_SET|CMD_OP_GET, cmd_tuner_reg,
"Manually access a register on the E4K" },
{ "si570.freq", CMD_OP_SET|CMD_OP_GET, cmd_si570_freq,
"Change the SI570 clock frequency" },

View File

@ -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);
}

View File

@ -159,6 +159,11 @@ int uart_cmd_char(struct cmd_state *cs, uint8_t ch)
rc = handle_cb(cs, CMD_OP_SET, cs->cmd.buf, cs->arg.buf);
uart_cmd_reset(cs);
break;
case '?':
uart_cmd_out(cs, "\n\r");
rc = handle_cb(cs, CMD_OP_GET, cs->cmd.buf, cs->arg.buf);
uart_cmd_reset(cs);
break;
case ' ':
case '\t':
/* ignore any whitespace */