import modified E4000 driver from rtl-sdr

This commit is contained in:
Christian Daniel 2012-05-26 22:13:59 +02:00
parent 5b2f5902b0
commit 180193cecf
3 changed files with 290 additions and 237 deletions

View File

@ -19,6 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define E4K_CHECK_ADDR 0x02
#define E4K_CHECK_VAL 0x40
enum e4k_reg {
E4K_REG_MASTER1 = 0x00,
E4K_REG_MASTER2 = 0x01,
@ -186,6 +189,7 @@ struct e4k_state {
uint8_t i2c_addr;
enum e4k_band band;
struct e4k_pll_params vco;
void *rtl_dev;
};
int e4k_init(struct e4k_state *e4k);
@ -194,23 +198,21 @@ int e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value);
int e4k_commonmode_set(struct e4k_state *e4k, int8_t value);
int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq);
int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p);
int e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo);
uint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo);
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_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);
int e4k_reg_read(struct e4k_state *e4k, uint8_t reg);
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);
uint8_t e4k_reg_read(struct e4k_state *e4k, uint8_t reg);
int e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange);
int e4k_dc_offset_calibrate(struct e4k_state *e4k);
int e4k_dc_offset_gen_table(struct e4k_state *e4k);
int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain);
int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual);
int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain);
#endif /* _E4K_TUNER_H */

View File

@ -1,4 +1,3 @@
/* (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
@ -22,12 +21,11 @@
#include <errno.h>
#include <string.h>
#include <common.h>
#include <logging.h>
#include <reg_field.h>
#include <tuner_e4k.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/* If this is defined, the limits are somewhat relaxed compared to what the
* vendor claims is possible */
#define OUT_OF_SPEC
@ -48,7 +46,7 @@ static const uint8_t width2mask[] = {
0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
};
/***********************************************************************
/***********************************************************************
* Register Access */
#if 0
@ -132,8 +130,7 @@ static int e4k_field_read(struct e4k_state *e4k, const struct reg_field *field)
return rc;
}
/***********************************************************************
/***********************************************************************
* Filter Control */
static const uint32_t rf_filt_center_uhf[] = {
@ -152,7 +149,7 @@ static const uint32_t rf_filt_center_l[] = {
static int closest_arr_idx(const uint32_t *arr, unsigned int arr_size, uint32_t freq)
{
unsigned int i, bi;
unsigned int i, bi = 0;
uint32_t best_delta = 0xffffffff;
/* iterate over the array containing a list of the center
@ -174,31 +171,23 @@ static int choose_rf_filter(enum e4k_band band, uint32_t freq)
int rc;
switch (band) {
case E4K_BAND_VHF2:
if (freq < MHZ(268))
case E4K_BAND_VHF2:
case E4K_BAND_VHF3:
rc = 0;
else
rc = 8;
break;
case E4K_BAND_VHF3:
if (freq < MHZ(509))
rc = 0;
else
rc = 8;
break;
case E4K_BAND_UHF:
rc = closest_arr_idx(rf_filt_center_uhf,
ARRAY_SIZE(rf_filt_center_uhf),
freq);
break;
case E4K_BAND_L:
rc = closest_arr_idx(rf_filt_center_l,
ARRAY_SIZE(rf_filt_center_l),
freq);
break;
default:
rc -EINVAL;
break;
break;
case E4K_BAND_UHF:
rc = closest_arr_idx(rf_filt_center_uhf,
ARRAY_SIZE(rf_filt_center_uhf),
freq);
break;
case E4K_BAND_L:
rc = closest_arr_idx(rf_filt_center_l,
ARRAY_SIZE(rf_filt_center_l),
freq);
break;
default:
rc = -EINVAL;
break;
}
return rc;
@ -245,26 +234,26 @@ static const uint32_t ifch_filter_bw[] = {
};
static const uint32_t *if_filter_bw[] = {
[E4K_IF_FILTER_MIX] = mix_filter_bw,
[E4K_IF_FILTER_CHAN] = ifch_filter_bw,
[E4K_IF_FILTER_RC] = ifrc_filter_bw,
mix_filter_bw,
ifch_filter_bw,
ifrc_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),
ARRAY_SIZE(mix_filter_bw),
ARRAY_SIZE(ifch_filter_bw),
ARRAY_SIZE(ifrc_filter_bw),
};
static const struct reg_field if_filter_fields[] = {
[E4K_IF_FILTER_MIX] = {
.reg = E4K_REG_FILT2, .shift = 4, .width = 4,
{
E4K_REG_FILT2, 4, 4,
},
[E4K_IF_FILTER_CHAN] = {
.reg = E4K_REG_FILT3, .shift = 0, .width = 5,
{
E4K_REG_FILT3, 0, 5,
},
[E4K_IF_FILTER_RC] = {
.reg = E4K_REG_FILT2, .shift = 0, .width = 4,
{
E4K_REG_FILT2, 0, 4,
}
};
@ -287,7 +276,6 @@ int e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,
uint32_t bandwidth)
{
int bw_idx;
uint8_t mask;
const struct reg_field *field;
if (filter >= ARRAY_SIZE(if_filter_bw))
@ -332,7 +320,7 @@ int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter)
}
/***********************************************************************
/***********************************************************************
* Frequency Control */
#define E4K_FVCO_MIN_KHZ 2600000 /* 2.6 GHz */
@ -341,16 +329,29 @@ int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter)
#ifdef OUT_OF_SPEC
#define E4K_FLO_MIN_MHZ 50
#define E4K_FLO_MAX_MHZ 1900
#define E4K_FLO_MAX_MHZ 2200UL
#else
#define E4K_FLO_MIN_MHZ 64
#define E4K_FLO_MAX_MHZ 1700
#endif
/* \brief table of R dividers in case 3phase mixing is enabled,
* the values have to be halved if it's 2phase */
static const uint8_t vco_r_table_3ph[] = {
4, 8, 12, 16, 24, 32, 40, 48
struct pll_settings {
uint32_t freq;
uint8_t reg_synth7;
uint8_t mult;
};
static const struct pll_settings pll_vars[] = {
{KHZ(72400), (1 << 3) | 7, 48},
{KHZ(81200), (1 << 3) | 6, 40},
{KHZ(108300), (1 << 3) | 5, 32},
{KHZ(162500), (1 << 3) | 4, 24},
{KHZ(216600), (1 << 3) | 3, 16},
{KHZ(325000), (1 << 3) | 2, 12},
{KHZ(350000), (1 << 3) | 1, 8},
{KHZ(432000), (0 << 3) | 3, 8},
{KHZ(667000), (0 << 3) | 2, 6},
{KHZ(1200000), (0 << 3) | 1, 4}
};
static int is_fvco_valid(uint32_t fvco_z)
@ -358,7 +359,7 @@ static int is_fvco_valid(uint32_t fvco_z)
/* check if the resulting fosc is valid */
if (fvco_z/1000 < E4K_FVCO_MIN_KHZ ||
fvco_z/1000 > E4K_FVCO_MAX_KHZ) {
LOGP(DTUN, LOGL_ERROR, "Fvco %u invalid\n", fvco_z);
printf("Fvco %u invalid\n\r", fvco_z);
return 0;
}
@ -368,17 +369,7 @@ static int is_fvco_valid(uint32_t fvco_z)
static int is_fosc_valid(uint32_t fosc)
{
if (fosc < MHZ(16) || fosc > MHZ(30)) {
LOGP(DTUN, LOGL_ERROR, "Fosc %u invalid\n", fosc);
return 0;
}
return 1;
}
static int is_flo_valid(uint32_t flo)
{
if (flo < MHZ(E4K_FLO_MIN_MHZ) || flo > MHZ(E4K_FLO_MAX_MHZ)) {
LOGP(DTUN, LOGL_ERROR, "Flo %u invalid\n", flo);
printf("Fosc %u invalid\n\r", fosc);
return 0;
}
@ -388,7 +379,7 @@ static int is_flo_valid(uint32_t flo)
static int is_z_valid(uint32_t z)
{
if (z > 255) {
LOGP(DTUN, LOGL_ERROR, "Z %u invalid\n", z);
printf("Z %u invalid\n\r", z);
return 0;
}
@ -399,7 +390,7 @@ static int is_z_valid(uint32_t z)
static int use_3ph_mixing(uint32_t flo)
{
/* this is a magic number somewhre between VHF and UHF */
if (flo < MHZ(300))
if (flo < MHZ(350))
return 1;
return 0;
@ -407,7 +398,7 @@ static int use_3ph_mixing(uint32_t flo)
/* \brief compute Fvco based on Fosc, Z and X
* \returns positive value (Fvco in Hz), 0 in case of error */
static unsigned int compute_fvco(uint32_t f_osc, uint8_t z, uint16_t x)
static uint64_t compute_fvco(uint32_t f_osc, uint8_t z, uint16_t x)
{
uint64_t fvco_z, fvco_x, fvco;
@ -419,26 +410,21 @@ static unsigned int compute_fvco(uint32_t f_osc, uint8_t z, uint16_t x)
*/
fvco_z = (uint64_t)f_osc * z;
#if 0
if (!is_fvco_valid(fvco_z))
return 0;
#endif
fvco_x = ((uint64_t)f_osc * x) / E4K_PLL_Y;
fvco = fvco_z + fvco_x;
/* this shouldn't happen, but better to check explicitly for integer
* overflows before converting uint64_t to "int" */
if (fvco > UINT_MAX) {
LOGP(DTUN, LOGL_ERROR, "Fvco %llu > INT_MAX\n", fvco);
return 0;
}
return fvco;
}
static int compute_flo(uint32_t f_osc, uint8_t z, uint16_t x, uint8_t r)
static uint32_t compute_flo(uint32_t f_osc, uint8_t z, uint16_t x, uint8_t r)
{
unsigned int fvco = compute_fvco(f_osc, z, x);
uint64_t fvco = compute_fvco(f_osc, z, x);
if (fvco == 0)
return -EINVAL;
@ -467,116 +453,71 @@ static int e4k_band_set(struct e4k_state *e4k, enum e4k_band band)
return rc;
}
#if 0
static int compute_lowest_r_idx(uint32_t flo, uint32_t fosc)
{
int three_phase_mixing = use_3ph_mixing(intended_flo);
uint32_t r_ideal;
/* determine what would be the idael R divider, taking into account
* fractional remainder of the division */
r_ideal = flo / fosc;
if (flo % fosc)
r_ideal++;
/* find the next best (bigger) possible R value */
for (i = 0; i < ARRAY_SIZE(vco_r_table_3ph); i++) {
uint32_t r = vco_r_table_3ph[i];
if (!three_phase_mixing)
r = r / 2;
if (r < r_ideal)
continue;
return i;
}
/* this shouldn't happen!!! */
return 0;
}
#endif
/*! \brief Compute PLL parameters for givent target frequency
* \param[out] oscp Oscillator parameters, if computation successful
* \param[in] fosc Clock input frequency applied to the chip (Hz)
* \param[in] intended_flo target tuning frequency (Hz)
* \returns actual PLL frequency, as close as possible to intended_flo,
* negative in case of error
* 0 in case of error
*/
int e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo)
uint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo)
{
int i;
int three_phase_mixing = use_3ph_mixing(intended_flo);
uint32_t i;
uint8_t r = 2;
uint64_t intended_fvco, remainder;
uint64_t z = 0;
uint32_t x;
int flo;
int three_phase_mixing = 0;
oscp->r_idx = 0;
if (!is_fosc_valid(fosc))
return -EINVAL;
return 0;
if (!is_flo_valid(intended_flo))
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(vco_r_table_3ph); i++) {
uint8_t r = vco_r_table_3ph[i];
uint64_t intended_fvco, z, remainder;
uint32_t x;
int flo;
if (!three_phase_mixing)
r = r / 2;
LOGP(DTUN, LOGL_DEBUG, "Fint=%u, R=%u\n", intended_flo, r);
/* flo(max) = 1700MHz, R(max) = 48, we need 64bit! */
intended_fvco = (uint64_t)intended_flo * r;
/* check if fvco is in range, if not continue */
if (intended_fvco > UINT_MAX) {
LOGP(DTUN, LOGL_DEBUG, "intended_fvco > UINT_MAX\n");
continue;
for(i = 0; i < ARRAY_SIZE(pll_vars); ++i) {
if(intended_flo < pll_vars[i].freq) {
three_phase_mixing = (pll_vars[i].reg_synth7 & 0x08) ? 1 : 0;
oscp->r_idx = pll_vars[i].reg_synth7;
r = pll_vars[i].mult;
break;
}
if (!is_fvco_valid(intended_fvco))
continue;
/* compute integral component of multiplier */
z = intended_fvco / fosc;
if (!is_z_valid(z))
continue;
/* compute fractional part. this will not overflow,
* as fosc(max) = 30MHz and z(max) = 255 */
remainder = intended_fvco - (fosc * z);
/* remainder(max) = 30MHz, E4K_PLL_Y = 65536 -> 64bit! */
x = (remainder * E4K_PLL_Y) / fosc;
/* x(max) as result of this computation is 65536 */
flo = compute_flo(fosc, z, x, r);
if (flo < 0)
continue;
oscp->fosc = fosc;
oscp->flo = flo;
oscp->intended_flo = intended_flo;
oscp->r = r;
oscp->r_idx = i;
oscp->threephase = three_phase_mixing;
oscp->x = x;
oscp->z = z;
return flo;
}
LOGP(DTUN, LOGL_ERROR, "No valid set of PLL params found for %u\n",
intended_flo);
return -EINVAL;
printf("Fint=%u, R=%u\n\r", intended_flo, r);
/* flo(max) = 1700MHz, R(max) = 48, we need 64bit! */
intended_fvco = (uint64_t)intended_flo * r;
/* compute integral component of multiplier */
z = intended_fvco / fosc;
/* compute fractional part. this will not overflow,
* as fosc(max) = 30MHz and z(max) = 255 */
remainder = intended_fvco - (fosc * z);
/* remainder(max) = 30MHz, E4K_PLL_Y = 65536 -> 64bit! */
x = (remainder * E4K_PLL_Y) / fosc;
/* x(max) as result of this computation is 65536 */
flo = compute_flo(fosc, z, x, r);
oscp->fosc = fosc;
oscp->flo = flo;
oscp->intended_flo = intended_flo;
oscp->r = r;
// oscp->r_idx = pll_vars[i].reg_synth7 & 0x0;
oscp->threephase = three_phase_mixing;
oscp->x = x;
oscp->z = z;
return flo;
}
int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p)
{
uint8_t val;
/* program R index + 3phase/2phase */
val = (p->r_idx & 0x7) | ((p->threephase & 0x1) << 3);
e4k_reg_write(e4k, E4K_REG_SYNTH7, val);
/* program R + 3phase/2phase */
e4k_reg_write(e4k, E4K_REG_SYNTH7, p->r_idx);
/* program Z */
e4k_reg_write(e4k, E4K_REG_SYNTH3, p->z);
/* program X */
@ -588,7 +529,7 @@ int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p)
memcpy(&e4k->vco, p, sizeof(e4k->vco));
/* set the band */
if (e4k->vco.flo < MHZ(139))
if (e4k->vco.flo < MHZ(140))
e4k_band_set(e4k, E4K_BAND_VHF2);
else if (e4k->vco.flo < MHZ(350))
e4k_band_set(e4k, E4K_BAND_VHF3);
@ -614,19 +555,28 @@ int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p)
*/
int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq)
{
int rc;
uint32_t rc;
struct e4k_pll_params p;
/* determine PLL parameters */
rc = e4k_compute_pll_params(&p, e4k->vco.fosc, freq);
if (rc < 0)
return rc;
if (!rc)
return -EINVAL;
/* actually tune to those parameters */
return e4k_tune_params(e4k, &p);
rc = e4k_tune_params(e4k, &p);
/* check PLL lock */
rc = e4k_reg_read(e4k, E4K_REG_SYNTH1);
if (!(rc & 0x01)) {
printf("[E4K] PLL not locked!\n\r");
return -1;
}
return 0;
}
/***********************************************************************
/***********************************************************************
* Gain Control */
static const int8_t if_stage1_gain[] = {
@ -646,33 +596,105 @@ static const int8_t if_stage56_gain[] = {
};
static const int8_t *if_stage_gain[] = {
[1] = if_stage1_gain,
[2] = if_stage23_gain,
[3] = if_stage23_gain,
[4] = if_stage4_gain,
[5] = if_stage56_gain,
[6] = if_stage56_gain
0,
if_stage1_gain,
if_stage23_gain,
if_stage23_gain,
if_stage4_gain,
if_stage56_gain,
if_stage56_gain
};
static const uint8_t if_stage_gain_len[] = {
[0] = 0,
[1] = ARRAY_SIZE(if_stage1_gain),
[2] = ARRAY_SIZE(if_stage23_gain),
[3] = ARRAY_SIZE(if_stage23_gain),
[4] = ARRAY_SIZE(if_stage4_gain),
[5] = ARRAY_SIZE(if_stage56_gain),
[6] = ARRAY_SIZE(if_stage56_gain)
0,
ARRAY_SIZE(if_stage1_gain),
ARRAY_SIZE(if_stage23_gain),
ARRAY_SIZE(if_stage23_gain),
ARRAY_SIZE(if_stage4_gain),
ARRAY_SIZE(if_stage56_gain),
ARRAY_SIZE(if_stage56_gain)
};
static const struct reg_field if_stage_gain_regs[] = {
[1] = { .reg = E4K_REG_GAIN3, .shift = 0, .width = 1 },
[2] = { .reg = E4K_REG_GAIN3, .shift = 1, .width = 2 },
[3] = { .reg = E4K_REG_GAIN3, .shift = 3, .width = 2 },
[4] = { .reg = E4K_REG_GAIN3, .shift = 5, .width = 2 },
[5] = { .reg = E4K_REG_GAIN4, .shift = 0, .width = 3 },
[6] = { .reg = E4K_REG_GAIN4, .shift = 3, .width = 3 }
{ 0, 0, 0 },
{ E4K_REG_GAIN3, 0, 1 },
{ E4K_REG_GAIN3, 1, 2 },
{ E4K_REG_GAIN3, 3, 2 },
{ E4K_REG_GAIN3, 5, 2 },
{ E4K_REG_GAIN4, 0, 3 },
{ E4K_REG_GAIN4, 3, 3 }
};
static const int32_t lnagain[] = {
-50, 0,
-25, 1,
0, 4,
25, 5,
50, 6,
75, 7,
100, 8,
125, 9,
150, 10,
175, 11,
200, 12,
250, 13,
300, 14,
};
static const int32_t enhgain[] = {
10, 30, 50, 70
};
int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain)
{
uint32_t i;
for(i = 0; i < ARRAY_SIZE(lnagain)/2; ++i) {
if(lnagain[i*2] == gain) {
e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, lnagain[i*2+1]);
return gain;
}
}
return -EINVAL;
}
int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain)
{
uint32_t i;
for(i = 0; i < ARRAY_SIZE(enhgain); ++i) {
if(enhgain[i] == gain) {
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, E4K_AGC11_LNA_GAIN_ENH | (i << 1));
return gain;
}
}
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0);
/* special case: 0 = off*/
if(0 == gain)
return 0;
else
return -EINVAL;
}
int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual)
{
if (manual) {
/* Set LNA mode to manual */
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_SERIAL);
/* Set Mixer Gain Control to manual */
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);
} else {
/* Set LNA mode to auto */
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_IF_SERIAL_LNA_AUTON);
/* Set Mixer Gain Control to auto */
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 1);
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0);
}
return 0;
}
static int find_stage_gain(uint8_t stage, int8_t val)
{
const int8_t *arr;
@ -741,7 +763,7 @@ int e4k_commonmode_set(struct e4k_state *e4k, int8_t value)
return e4k_reg_set_mask(e4k, E4K_REG_DC7, 7, value);
}
/***********************************************************************
/***********************************************************************
* DC Offset */
int e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange)
@ -792,17 +814,17 @@ struct gain_comb {
};
static const struct gain_comb dc_gain_comb[] = {
{ 4, -3, 0x50 },
{ 4, 6, 0x51 },
{ 4, -3, 0x50 },
{ 4, 6, 0x51 },
{ 12, -3, 0x52 },
{ 12, 6, 0x53 },
{ 12, 6, 0x53 },
};
#define TO_LUT(offset, range) (offset | (range << 6))
int e4k_dc_offset_gen_table(struct e4k_state *e4k)
{
int i;
uint32_t i;
/* FIXME: read ont current gain values and write them back
* before returning to the caller */
@ -830,27 +852,26 @@ int e4k_dc_offset_gen_table(struct e4k_state *e4k)
e4k_dc_offset_calibrate(e4k);
/* 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;
offs_i = e4k_reg_read(e4k, E4K_REG_DC2) & 0x3f;
offs_q = e4k_reg_read(e4k, E4K_REG_DC3) & 0x3f;
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",
/*
fprintf(stderr, "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));
e4k_reg_write(e4k, dc_gain_comb[i].reg+0x10,
e4k_reg_write(e4k, dc_gain_comb[i].reg + 0x10,
TO_LUT(offs_i, range_i));
}
return 0;
}
/***********************************************************************
/***********************************************************************
* Initialization */
static int magic_init(struct e4k_state *e4k)
@ -874,45 +895,75 @@ 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);
#if 0
/* 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);
#endif
/* Set LNA mode to manual */
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 */
/* Set LNA mode to autnonmous */
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK,
E4K_AGC_MOD_IF_SERIAL_LNA_AUTON);
E4K_AGC_MOD_SERIAL);
/* Set Miser Gain Control to autonomous */
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO,
E4K_AGC7_MIX_GAIN_AUTO);
/* Set Mixer Gain Control to manual */
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);
#if 0
/* Enable LNA Gain enhancement */
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7,
E4K_AGC11_LNA_GAIN_ENH | (2 << 1));
/* Enable automatic IF gain mode switching */
e4k_reg_set_mask(e4k, E4K_REG_AGC8, 0x1, E4K_AGC8_SENS_LIN_AUTO);
#endif
/* FIXME: do we need to program Output Common Mode voltage ? */
/* Use auto-gain as default */
e4k_enable_manual_gain(e4k, 0);
/* 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);
/* Select moderate gain levels */
e4k_if_gain_set(e4k, 1, 6);
e4k_if_gain_set(e4k, 2, 0);
e4k_if_gain_set(e4k, 3, 0);
e4k_if_gain_set(e4k, 4, 0);
e4k_if_gain_set(e4k, 5, 9);
e4k_if_gain_set(e4k, 6, 9);
/* 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);
e4k_if_gain_set(e4k, 3, 3);
e4k_if_gain_set(e4k, 4, 1);
e4k_if_gain_set(e4k, 5, 9);
e4k_if_gain_set(e4k, 6, 9);
#endif
e4k_if_filter_chan_enable(e4k, 1);
/* Disable time variant DC correction and LUT */
e4k_reg_set_mask(e4k, E4K_REG_DC5, 0x03, 0);
e4k_reg_set_mask(e4k, E4K_REG_DCTIME1, 0x03, 0);
e4k_reg_set_mask(e4k, E4K_REG_DCTIME2, 0x03, 0);
return 0;
}

View File

@ -44,7 +44,7 @@ int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val)
return 0;
}
int e4k_reg_read(struct e4k_state *e4k, uint8_t reg)
uint8_t e4k_reg_read(struct e4k_state *e4k, uint8_t reg)
{
unsigned char rc;
uint8_t val;