diff options
Diffstat (limited to 'firmware/src/tuner_e4k.c')
-rw-r--r-- | firmware/src/tuner_e4k.c | 499 |
1 files changed, 275 insertions, 224 deletions
diff --git a/firmware/src/tuner_e4k.c b/firmware/src/tuner_e4k.c index eabb1b9..e89cf84 100644 --- a/firmware/src/tuner_e4k.c +++ b/firmware/src/tuner_e4k.c @@ -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)) - rc = 0; - else - rc = 8; - break; - case E4K_BAND_VHF3: - if (freq < MHZ(509)) + case E4K_BAND_VHF2: + case E4K_BAND_VHF3: 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(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; + } + } - 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; + printf("Fint=%u, R=%u\n\r", intended_flo, r); - if (!three_phase_mixing) - r = r / 2; + /* flo(max) = 1700MHz, R(max) = 48, we need 64bit! */ + intended_fvco = (uint64_t)intended_flo * r; - LOGP(DTUN, LOGL_DEBUG, "Fint=%u, R=%u\n", intended_flo, r); + /* compute integral component of multiplier */ + z = intended_fvco / fosc; - /* 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; - } + /* 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 */ - 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; - } + flo = compute_flo(fosc, z, x, r); - LOGP(DTUN, LOGL_ERROR, "No valid set of PLL params found for %u\n", - intended_flo); - return -EINVAL; + 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 ? */ - - /* FIXME: initialize DC offset lookup tables */ - - /* Disable Clock output, write 0x96 into 0x7A */ - e4k_reg_write(e4k, E4K_REG_CLKOUT_PWDN, E4K_CLKOUT_DISABLE); + /* Use auto-gain as default */ + e4k_enable_manual_gain(e4k, 0); - /* 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; } |