1 /* Driver for RF Transceiver Circuit (TRF6151) */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <osmocom/gsm/gsm_utils.h>
31 #include <calypso/tpu.h>
32 #include <calypso/tsp.h>
33 #include <layer1/agc.h>
36 #include <rf/trf6151.h>
38 /* #define WARN_OUT_OF_SPEC 1 */
41 REG_RX = 0, /* RF general settings */
42 REG_PLL = 1, /* PLL settings */
43 REG_PWR = 2, /* Power on/off functional blocks */
44 REG_CFG = 3, /* Transceiver and PA controller settings */
53 #define RX_READ_EN (1 << 7)
54 #define RX_CAL_MODE (1 << 8)
55 #define RX_RF_GAIN_HIGH (3 << 9)
56 #define RX_VGA_GAIN_SHIFT 11
59 #define PWR_BANDGAP_SHIFT 3
60 #define PWR_BANDGAP_OFF (0 << PWR_BANDGAP_SHIFT)
61 #define PWR_BANDGAP_ON_SPEEDUP (2 << PWR_BANDGAP_SHIFT)
62 #define PWR_BANDGAP_ON (3 << PWR_BANDGAP_SHIFT)
63 #define PWR_REGUL_ON (1 << 5)
64 #define PWR_SYNTHE_OFF (0)
65 #define PWR_SYNTHE_RX_ON (1 << 9)
66 #define PWR_SYNTHE_TX_ON (1 << 10)
67 #define PWR_RX_MODE (1 << 11)
68 #define PWR_TX_MODE (1 << 13)
69 #define PWR_PACTRL_APC (1 << 14)
70 #define PWR_PACTRL_APCEN (1 << 15)
73 #define CFG_TX_LOOP_MANU (1 << 3)
74 #define CFG_PACTLR_IDIOD_30uA (0 << 4)
75 #define CFG_PACTLR_IDIOD_300uA (1 << 4)
76 #define CFG_PACTLR_RES_OPEN (0 << 10)
77 #define CFG_PACTLR_RES_150k (1 << 10)
78 #define CFG_PACTLR_RES_300k (2 << 10)
79 #define CFG_PACTLR_CAP_0pF (0 << 12)
80 #define CFG_PACTLR_CAP_12p5F (1 << 12)
81 #define CFG_PACTLR_CAP_25pF (3 << 12)
82 #define CFG_PACTLR_CAP_50pF (2 << 12)
83 #define CFG_TEMP_SENSOR (1 << 14)
84 #define CFG_ILOGIC_INIT_DIS (1 << 15)
86 /* FIXME: This must be defined in the RFFE configuration */
87 #define TRF6151_TSP_UID 2
88 #define TRF6151_PACTRL_CFG (CFG_PACTLR_RES_OPEN|CFG_PACTLR_CAP_0pF|CFG_PACTLR_IDIOD_30uA)
90 #define PLL_VAL(a, b) ((a << 3) | (((b)-64) << 9))
92 /* All values in qbits unless otherwise specified */
93 #define TRF6151_LDO_DELAY_TS 6 /* six TDMA frames (at least 25ms) */
94 #define TRF6151_RX_PLL_DELAY 184 /* 170 us */
95 #define TRF6151_TX_PLL_DELAY 260 /* 240 us */
98 enum trf6151_pwr_unit {
100 TRF6151_PACTRL_APCEN,
105 enum trf6151_gsm_band {
114 uint16_t rf_arfcn = 871; /* TODO: this needs to be private */
115 static uint16_t rf_band;
117 static uint8_t trf6151_tsp_uid;
118 static uint8_t trf6151_vga_dbm = 40;
119 static int trf6151_gain_high = 1;
121 static uint16_t trf6151_reg_cache[_MAX_REG] = {
128 /* Write to a TRF6151 register (4 TPU instructions) */
129 static void trf6151_reg_write(uint16_t reg, uint16_t val)
131 printd("trf6151_reg_write(reg=%u, val=0x%04x)\n", reg, val);
132 /* each TSP write takes 4 TPU instructions */
133 tsp_write(trf6151_tsp_uid, 16, (reg | val));
134 trf6151_reg_cache[reg] = val;
137 /* Frontend gain can be switched high or low (dB) */
138 #define TRF6151_FE_GAIN_LOW 7
139 #define TRF6151_FE_GAIN_HIGH 27
141 /* VGA at baseband can be adjusted in this range (dB) */
142 #define TRF6151_VGA_GAIN_MIN 14
143 #define TRF6151_VGA_GAIN_MAX 40
145 /* put current set (or computed) gain to register */
146 int trf6151_set_gain_reg(uint8_t dbm, int high)
148 uint16_t reg = trf6151_reg_cache[REG_RX] & 0x07ff;
149 printd("trf6151_set_gain_reg(%u, %d)\n", dbm, high);
151 if (dbm < TRF6151_VGA_GAIN_MIN || dbm > TRF6151_VGA_GAIN_MAX)
154 /* clear the gain bits first */
155 reg &= ~((0x1F) << RX_VGA_GAIN_SHIFT);
156 /* OR-in the new gain value */
157 reg |= (6 + (dbm-TRF6151_VGA_GAIN_MIN)/2) << RX_VGA_GAIN_SHIFT;
160 reg |= RX_RF_GAIN_HIGH;
162 reg &= ~RX_RF_GAIN_HIGH;
164 trf6151_reg_write(REG_RX, reg);
169 int trf6151_set_gain(uint8_t dbm)
173 printd("trf6151_set_gain(%u, %d)\n", dbm);
174 /* If this is negative or less than TRF6151_GAIN_MIN, we are pretty
175 * much lost as we cannot reduce the system inherent gain. If it is
176 * positive, it corresponds to the gain that we need to configure */
177 if (dbm < TRF6151_FE_GAIN_LOW + TRF6151_VGA_GAIN_MIN) {
178 printd("AGC Input level overflow\n");
179 trf6151_vga_dbm = TRF6151_VGA_GAIN_MIN;
180 trf6151_gain_high = 0;
182 } else if (dbm >= TRF6151_FE_GAIN_HIGH + TRF6151_VGA_GAIN_MIN) {
184 dbm -= TRF6151_FE_GAIN_HIGH;
186 dbm -= TRF6151_FE_GAIN_LOW;
187 if (dbm > TRF6151_VGA_GAIN_MAX)
188 dbm = TRF6151_VGA_GAIN_MAX;
190 /* update the static global variables which are used when programming
192 trf6151_vga_dbm = dbm;
193 trf6151_gain_high = high;
198 #define SCALE_100KHZ 100
200 /* Compute TRF6151 PLL valuese */
201 static void trf6151_pll_rx(uint32_t freq_khz,
202 uint16_t *pll_config, enum trf6151_gsm_band *band)
204 const uint32_t p=64, r=65;
205 uint32_t freq_100khz, vco_freq_100khz;
209 /* Scale into 100kHz unit (avoid overflow in intermediates) */
210 freq_100khz = freq_khz / SCALE_100KHZ;
212 /* L selects hi/lo band */
213 l = (freq_khz > 1350000) ? 2 : 4; /* cut at mid point :) */
216 vco_freq_100khz = freq_100khz * l;
218 /* vco_freq = 26MHz / R * N with R=65 and N=B*P+A */
219 n = (vco_freq_100khz * r) / 260;
223 *pll_config = PLL_VAL(a, b);
225 /* Out-of-spec tuning warning */
226 #ifdef WARN_OUT_OF_SPEC
227 if ((l == 4 && (b < 135 || b > 150)) ||
228 (l == 2 && (b < 141 || b > 155)))
229 printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz);
234 /* If in the low band, same port for both GSM850/GSM900, so we
235 * choose the best VCO (VCOMAIN1=3.37GHz, VCOMAIN2=3.8GHz) */
236 if (vco_freq_100khz < 35850) /* midpoint */
241 /* Out-of-spec freq check */
242 #ifdef WARN_OUT_OF_SPEC
243 if (!(freq_khz >= 869000 && freq_khz <= 894000) &&
244 !(freq_khz >= 921000 && freq_khz <= 960000)) /* include GSM-R */
245 printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz);
248 /* In the high band, different ports for DCS/PCS, so
249 * take what's best and available */
250 /* We're stuck to VCOMAIN2=3.8GHz though ... */
251 uint32_t rx_ports = rffe_get_rx_ports();
255 port = (freq_khz < 1905000) ? (1 << PORT_DCS1800) : (1 << PORT_PCS1900);
256 port = (port & rx_ports) ? port : rx_ports;
259 *band = (port & (1 << PORT_DCS1800)) ? GSM1800 : GSM1900;
261 /* Out-of-spec freq check */
262 #ifdef WARN_OUT_OF_SPEC
263 if ((*band == GSM1800 && (freq_khz < 1805000 || freq_khz > 1880000)) ||
264 (*band == GSM1900 && (freq_khz < 1930000 || freq_khz > 1990000)))
265 printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz);
270 printd("RX Freq %u kHz => A = %u, B = %u, band = %d, vco_freq = %u kHz\n", freq_khz, a, b, *band, vco_freq_100khz*100);
276 /* Compute TRF6151 PLL TX values */
277 static void trf6151_pll_tx(uint32_t freq_khz,
278 uint16_t *pll_config, enum trf6151_gsm_band *band)
281 uint32_t r, l, m, m_op_l; /* m_op_l = m +/- l depending on mode */
282 uint32_t freq_100khz;
283 uint32_t n, a, b, b_min, b_max;
285 /* Scale into 100kHz unit (avoid overflow in intermediates) */
286 freq_100khz = freq_khz / SCALE_100KHZ;
288 /* Select band (and PLL mode) */
289 if (freq_khz > 1350000) {
290 /* High band, so only 1 real PLL mode. band doesn't matter
291 * that much (or at all) but we still do it :p */
292 *band = (freq_khz < 1817500) ? GSM1800 : GSM1900;
300 /* Low band. We have 3 possible PLL modes that output on
301 * the right port: GSM900, GSM850_HIGH, GSM850_LOW.
303 * The transistion points have been chosen looking at the VCO
304 * and IF frequencies for various frequencies for theses modes
306 if (freq_khz < 837100) {
315 } else if (freq_khz < 850000) {
336 /* vco_freq = f * M * L / (M +- L) */
337 /* = 26MHz / R * N with R=65 and N=B*P+A */
338 n = (freq_100khz * m * l * r) / (m_op_l * 260);
342 *pll_config = PLL_VAL(a, b);
345 printd("TX Freq %u kHz => A = %u, B = %u, band = %d\n", freq_khz, a, b, *band);
347 /* Out-of-spec tuning warning */
348 #ifdef WARN_OUT_OF_SPEC
349 if (b < b_min || b > b_max)
350 printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz);
357 static inline void trf6151_reset(uint16_t reset_id)
359 /* pull the nRESET line low */
360 tsp_act_disable(reset_id);
363 tsp_act_enable(reset_id);
366 void trf6151_init(uint8_t tsp_uid, uint16_t tsp_reset_id)
368 trf6151_tsp_uid = tsp_uid;
370 /* Configure the TSPEN which is connected to TRF6151 STROBE */
371 tsp_setup(trf6151_tsp_uid, 0, 1, 1);
373 trf6151_reset(tsp_reset_id);
375 /* configure TRF6151 for operation */
377 trf6151_reg_write(REG_CFG, TRF6151_PACTRL_CFG | CFG_ILOGIC_INIT_DIS);
379 /* FIXME: Uplink / Downlink Calibration */
382 void trf6151_power(int on)
385 trf6151_reg_write(REG_PWR, PWR_REGUL_ON | PWR_BANDGAP_ON);
386 /* wait until regulators are stable (25ms == 27100 qbits) */
394 trf6151_reg_write(REG_PWR, PWR_BANDGAP_ON);
397 /* Set the operational mode of the TRF6151 chip */
398 void trf6151_set_mode(enum trf6151_mode mode)
400 uint16_t pwr = (PWR_REGUL_ON | PWR_BANDGAP_ON | (rf_band<<6));
404 /* should we switch of the RF gain for power saving? */
407 pwr |= (PWR_SYNTHE_RX_ON | PWR_RX_MODE);
411 pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE);
412 #else // Dieter: we should turn power control on (for TPU: check timing and order !)
413 pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE | PWR_PACTRL_APC | PWR_PACTRL_APCEN); // Dieter: TODO
417 trf6151_reg_write(REG_PWR, pwr);
420 static void trf6151_band_select(enum trf6151_gsm_band band)
422 uint16_t pwr = trf6151_reg_cache[REG_PWR];
427 trf6151_reg_write(REG_PWR, pwr);
430 /* Set ARFCN. Takes 2 reg_write, i.e. 8 TPU instructions */
431 void trf6151_set_arfcn(uint16_t arfcn, int uplink)
435 enum trf6151_gsm_band pll_band;
437 switch (gsm_arfcn2band(arfcn)) {
448 printf("Unsupported band ! YMMV.\n");
452 freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100;
453 printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz);
456 trf6151_pll_rx(freq_khz, &pll_config, &pll_band);
458 trf6151_pll_tx(freq_khz, &pll_config, &pll_band);
460 trf6151_band_select(pll_band);
461 trf6151_reg_write(REG_PLL, pll_config);
464 rf_arfcn = arfcn; // TODO: arfcn is referenced at other places
467 void trf6151_calib_dc_offs(void)
469 uint16_t rx = trf6151_reg_cache[REG_RX];
471 /* Set RX CAL Mode bit, it will re-set automatically */
472 trf6151_reg_write(REG_RX, rx | RX_CAL_MODE);
473 /* DC offset calibration can take up to 50us, i.e. 54.16 * 923ns*/
477 uint8_t trf6151_get_gain_reg(void)
479 uint16_t vga, reg_rx = trf6151_reg_cache[REG_RX];
482 switch ((reg_rx >> 9) & 3) {
484 gain += TRF6151_FE_GAIN_LOW;
487 gain += TRF6151_FE_GAIN_HIGH;
491 vga = (reg_rx >> RX_VGA_GAIN_SHIFT) & 0x1f;
495 gain += TRF6151_VGA_GAIN_MIN + (vga - 6) * 2;
500 uint8_t trf6151_get_gain(void)
504 gain = trf6151_vga_dbm;
505 if (trf6151_gain_high)
506 gain += TRF6151_FE_GAIN_HIGH;
508 gain += TRF6151_FE_GAIN_LOW;
513 void trf6151_test(uint16_t arfcn)
515 /* Select ARFCN 871 downlink */
516 trf6151_set_arfcn(arfcn, 0);
518 trf6151_set_mode(TRF6151_RX);
519 //trf6151_reg_write(REG_PWR, (PWR_SYNTHE_RX_ON | PWR_RX_MODE | PWR_REGUL_ON | (rf_band<<6) | PWR_BANDGAP_ON));
520 /* Wait for PLL stabilization (170us max) */
521 tpu_enq_wait(TRF6151_RX_PLL_DELAY);
523 /* Use DC offset calibration after RX mode has been switched on
524 * (might not be needed) */
525 trf6151_calib_dc_offs();
532 void trf6151_tx_test(uint16_t arfcn)
534 /* Select ARFCN uplink */
535 trf6151_set_arfcn(arfcn, 1);
537 trf6151_set_mode(TRF6151_TX);
538 tpu_enq_wait(TRF6151_RX_PLL_DELAY);
545 #define TRF6151_REGWR_QBITS 8 /* 4 GSM qbits + 4 TPU instructions */
546 #define TRF6151_RX_TPU_INSTR 4 /* set_gain_reg(1), set_arfcn(2), set_mode(1) */
548 /* delay caused by this driver programming the TPU for RX mode */
549 #define TRF6151_RX_TPU_DELAY (TRF6151_RX_TPU_INSTR * TRF6151_REGWR_QBITS)
551 /* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
552 void trf6151_rx_window(int16_t start_qbits, uint16_t arfcn)
554 int16_t start_pll_qbits;
556 /* power up at the right time _before_ the 'start_qbits' point in time */
557 start_pll_qbits = add_mod5000(start_qbits, -(TRF6151_RX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
558 tpu_enq_at(start_pll_qbits);
560 /* Set the AGC and PLL registers */
561 trf6151_set_arfcn(arfcn, 0);
562 trf6151_set_gain_reg(trf6151_vga_dbm, trf6151_gain_high);
563 trf6151_set_mode(TRF6151_RX);
565 /* FIXME: power down at the right time again */
568 /* prepare a Tx window with the TRF6151 finished at time 'start' (in qbits) */
569 void trf6151_tx_window(int16_t start_qbits, uint16_t arfcn)
571 #ifdef CONFIG_TX_ENABLE
572 int16_t start_pll_qbits;
574 /* power up at the right time _before_ the 'start_qbits' point in time */
575 start_pll_qbits = add_mod5000(start_qbits, -(TRF6151_TX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
576 tpu_enq_at(start_pll_qbits);
578 trf6151_set_arfcn(arfcn, 1);
579 trf6151_set_mode(TRF6151_TX);
581 /* FIXME: power down at the right time again */
585 /* Given the expected input level of exp_inp dBm and the target of target_bb
586 * dBm, configure the RF Frontend with the respective gain */
587 void trf6151_compute_gain(int16_t exp_inp, int16_t target_bb)
589 /* TRF6151 VGA gain between 14 to 40 dB, plus 20db high/low */
590 int16_t exp_bb, delta;
592 /* calculate the dBm8 that we expect at the baseband */
593 exp_bb = exp_inp + system_inherent_gain;
595 /* calculate the error that we expect. */
596 delta = target_bb - exp_bb;
598 printd("computed gain %d\n", delta);
599 trf6151_set_gain(delta);