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>
39 REG_RX = 0, /* RF general settings */
40 REG_PLL = 1, /* PLL settings */
41 REG_PWR = 2, /* Power on/off functional blocks */
42 REG_CFG = 3, /* Transceiver and PA controller settings */
51 #define RX_READ_EN (1 << 7)
52 #define RX_CAL_MODE (1 << 8)
53 #define RX_RF_GAIN_HIGH (3 << 9)
54 #define RX_VGA_GAIN_SHIFT 11
57 #define PWR_BANDGAP_SHIFT 3
58 #define PWR_BANDGAP_OFF (0 << PWR_BANDGAP_SHIFT)
59 #define PWR_BANDGAP_ON_SPEEDUP (2 << PWR_BANDGAP_SHIFT)
60 #define PWR_BANDGAP_ON (3 << PWR_BANDGAP_SHIFT)
61 #define PWR_REGUL_ON (1 << 5)
62 #define PWR_SYNTHE_OFF (0)
63 #define PWR_SYNTHE_RX_ON (1 << 9)
64 #define PWR_SYNTHE_TX_ON (1 << 10)
65 #define PWR_RX_MODE (1 << 11)
66 #define PWR_TX_MODE (1 << 13)
67 #define PWR_PACTRL_APC (1 << 14)
68 #define PWR_PACTRL_APCEN (1 << 15)
71 #define CFG_TX_LOOP_MANU (1 << 3)
72 #define CFG_PACTLR_IDIOD_30uA (0 << 4)
73 #define CFG_PACTLR_IDIOD_300uA (1 << 4)
74 #define CFG_PACTLR_RES_OPEN (0 << 10)
75 #define CFG_PACTLR_RES_150k (1 << 10)
76 #define CFG_PACTLR_RES_300k (2 << 10)
77 #define CFG_PACTLR_CAP_0pF (0 << 12)
78 #define CFG_PACTLR_CAP_12p5F (1 << 12)
79 #define CFG_PACTLR_CAP_25pF (3 << 12)
80 #define CFG_PACTLR_CAP_50pF (2 << 12)
81 #define CFG_TEMP_SENSOR (1 << 14)
82 #define CFG_ILOGIC_INIT_DIS (1 << 15)
84 /* FIXME: This must be defined in the RFFE configuration */
85 #define TRF6151_TSP_UID 2
86 #define TRF6151_PACTRL_CFG (CFG_PACTLR_RES_OPEN|CFG_PACTLR_CAP_0pF|CFG_PACTLR_IDIOD_30uA)
88 #define PLL_VAL(a, b) ((a << 3) | (((b)-64) << 9))
90 /* All values in qbits unless otherwise specified */
91 #define TRF6151_LDO_DELAY_TS 6 /* six TDMA frames (at least 25ms) */
92 #define TRF6151_RX_PLL_DELAY 184 /* 170 us */
93 #define TRF6151_TX_PLL_DELAY 260 /* 240 us */
95 uint16_t rf_arfcn = 871; /* TODO: this needs to be private */
96 static uint16_t rf_band;
98 static uint8_t trf6151_tsp_uid;
99 static uint8_t trf6151_vga_dbm = 40;
100 static int trf6151_gain_high = 1;
102 static uint16_t trf6151_reg_cache[_MAX_REG] = {
109 /* Write to a TRF6151 register (4 TPU instructions) */
110 static void trf6151_reg_write(uint16_t reg, uint16_t val)
112 printd("trf6151_reg_write(reg=%u, val=0x%04x)\n", reg, val);
113 /* each TSP write takes 4 TPU instructions */
114 tsp_write(trf6151_tsp_uid, 16, (reg | val));
115 trf6151_reg_cache[reg] = val;
118 int trf6151_set_gain(uint8_t dbm, int high)
120 uint16_t reg = trf6151_reg_cache[REG_RX] & 0x07ff;
121 printd("trf6151_set_gain(%u, %d)\n", dbm, high);
123 if (dbm < 14 || dbm > 40)
126 /* clear the gain bits first */
127 reg &= ~((0x1F) << RX_VGA_GAIN_SHIFT);
128 /* OR-in the new gain value */
129 reg |= (6 + (dbm-14)/2) << RX_VGA_GAIN_SHIFT;
132 reg |= RX_RF_GAIN_HIGH;
134 reg &= ~RX_RF_GAIN_HIGH;
136 trf6151_reg_write(REG_RX, reg);
141 #define SCALE_100KHZ 100
143 /* Compute TRF6151 PLL valuese for all 4 RX bands */
144 static uint16_t trf6151_pll_rx(uint32_t freq_khz)
146 uint32_t freq_100khz = freq_khz / SCALE_100KHZ; /* Scale from *1000 (k) to *100000 (0.1M) */
147 uint32_t fb_100khz; /* frequency of B alone, without A (units of 100kHz) */
149 uint32_t a, b; /* The PLL multipliers we want to compute */
151 /* L = 4 for low band, 2 for high band */
152 if (freq_khz < 1000000)
157 /* To compute B, we assume A is zero */
158 b = (freq_100khz * 65 * l) / (64 * 26 * 10);
160 if ((l == 4 && (b < 135 || b > 150)) ||
161 (l == 2 && (b < 141 || b > 155)))
162 printf("Frequency %u kHz is out of spec\n", freq_khz);
164 /* Compute PLL frequency assuming A == 0 */
165 fb_100khz = (b * 64 * 26 * 10) / (65 * l);
167 /* Compute how many 100kHz units A needs to add */
168 a = freq_100khz - fb_100khz;
173 /* since all frequencies are expanded a factor of 10, we don't need to multiply A */
174 printd("Freq %u kHz => A = %u, B = %u\n", freq_khz, a, b);
176 /* return value in trf6151 register layout form */
177 return PLL_VAL(a, b);
180 /* Compute TRF6151 PLL TX values for GSM900 and GSM1800 only! */
181 static uint16_t trf6151_pll_tx(uint32_t freq_khz)
183 uint32_t freq_100khz = freq_khz / SCALE_100KHZ; /* Scale from *1000 (k) to *100000 (0.1M) */
184 uint32_t fb_100khz; /* frequency of B alone, without A (units of 100kHz) */
186 uint32_t a, b; /* The PLL multipliers we want to compute */
188 /* L = 4 for low band, 2 for high band */
189 if (freq_khz < 1000000) {
199 /* To compute B, we assume A is zero */
200 b = (freq_100khz * r * l * m) / (64 * 26 * 10 * (m + l));
202 if ((l == 4 && (b < 68 || b > 71)) ||
203 (l == 2 && (b < 133 || b > 149)))
204 printf("Frequency %u kHz is out of spec\n", freq_khz);
206 /* Compute PLL frequency assuming A == 0 */
207 fb_100khz = (b * 64 * 26 * 10 * (m + l)) / (r * l * m);
209 /* Compute how many 100kHz units A needs to add */
210 a = freq_100khz - fb_100khz;
214 /* since all frequencies are expanded a factor of 10, we don't need to multiply A */
215 printd("Freq %u kHz => A = %u, B = %u\n", freq_khz, a, b);
217 /* return value in trf6151 register layout form */
218 return PLL_VAL(a, b);
221 enum trf6151_pwr_unit {
223 TRF6151_PACTRL_APCEN,
228 enum trf6151_gsm_band {
236 static inline void trf6151_reset(uint16_t reset_id)
238 /* pull the nRESET line low */
239 tsp_act_disable(reset_id);
242 tsp_act_enable(reset_id);
245 void trf6151_init(uint8_t tsp_uid, uint16_t tsp_reset_id)
247 trf6151_tsp_uid = tsp_uid;
249 /* Configure the TSPEN which is connected to TRF6151 STROBE */
250 tsp_setup(trf6151_tsp_uid, 0, 1, 1);
252 trf6151_reset(tsp_reset_id);
254 /* configure TRF6151 for operation */
256 trf6151_reg_write(REG_CFG, TRF6151_PACTRL_CFG | CFG_ILOGIC_INIT_DIS);
258 /* FIXME: Uplink / Downlink Calibration */
261 void trf6151_power(int on)
264 trf6151_reg_write(REG_PWR, PWR_REGUL_ON | PWR_BANDGAP_ON);
265 /* wait until regulators are stable (25ms == 27100 qbits) */
273 trf6151_reg_write(REG_PWR, PWR_BANDGAP_ON);
276 /* Set the operational mode of the TRF6151 chip */
277 void trf6151_set_mode(enum trf6151_mode mode)
279 uint16_t pwr = (PWR_REGUL_ON | PWR_BANDGAP_ON | (rf_band<<6));
283 /* should we switch of the RF gain for power saving? */
286 pwr |= (PWR_SYNTHE_RX_ON | PWR_RX_MODE);
290 pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE);
291 #else // Dieter: we should turn power control on (for TPU: check timing and order !)
292 pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE | PWR_PACTRL_APC | PWR_PACTRL_APCEN); // Dieter: TODO
296 trf6151_reg_write(REG_PWR, pwr);
299 static void trf6151_band_select(enum trf6151_gsm_band band)
301 uint16_t pwr = trf6151_reg_cache[REG_PWR];
306 trf6151_reg_write(REG_PWR, pwr);
309 /* Set ARFCN. Takes 2 reg_write, i.e. 8 TPU instructions */
310 void trf6151_set_arfcn(uint16_t arfcn, int uplink)
314 switch (gsm_arfcn2band(arfcn)) {
316 rf_band = GSM850_LOW; /* FIXME: what about HIGH */
331 printf("Unsupported rf_band.\n");
335 trf6151_band_select(rf_band);
337 freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100;
338 printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz);
341 trf6151_reg_write(REG_PLL, trf6151_pll_rx(freq_khz));
343 if (rf_band != GSM900 && rf_band != GSM1800) {
344 printf("TX only supports GSM900/1800\n");
347 trf6151_reg_write(REG_PLL, trf6151_pll_tx(freq_khz));
350 rf_arfcn = arfcn; // TODO: arfcn is referenced at other places
353 void trf6151_calib_dc_offs(void)
355 uint16_t rx = trf6151_reg_cache[REG_RX];
357 /* Set RX CAL Mode bit, it will re-set automatically */
358 trf6151_reg_write(REG_RX, rx | RX_CAL_MODE);
359 /* DC offset calibration can take up to 50us, i.e. 54.16 * 923ns*/
363 /* Frontend gain can be switched high or low (dB) */
364 #define TRF6151_FE_GAIN_LOW 7
365 #define TRF6151_FE_GAIN_HIGH 27
367 /* VGA at baseband can be adjusted in this range (dB) */
368 #define TRF6151_VGA_GAIN_MIN 14
369 #define TRF6151_VGA_GAIN_MAX 40
371 uint8_t trf6151_get_gain(void)
373 uint16_t vga, reg_rx = trf6151_reg_cache[REG_RX];
376 switch ((reg_rx >> 9) & 3) {
378 gain += TRF6151_FE_GAIN_LOW;
381 gain += TRF6151_FE_GAIN_HIGH;
385 vga = (reg_rx >> RX_VGA_GAIN_SHIFT) & 0x1f;
389 gain += TRF6151_VGA_GAIN_MIN + (vga - 6) * 2;
394 void trf6151_test(uint16_t arfcn)
396 /* Select ARFCN 871 downlink */
397 trf6151_set_arfcn(arfcn, 0);
399 trf6151_set_mode(TRF6151_RX);
400 //trf6151_reg_write(REG_PWR, (PWR_SYNTHE_RX_ON | PWR_RX_MODE | PWR_REGUL_ON | (rf_band<<6) | PWR_BANDGAP_ON));
401 /* Wait for PLL stabilization (170us max) */
402 tpu_enq_wait(TRF6151_RX_PLL_DELAY);
404 /* Use DC offset calibration after RX mode has been switched on
405 * (might not be needed) */
406 trf6151_calib_dc_offs();
413 void trf6151_tx_test(uint16_t arfcn)
415 /* Select ARFCN uplink */
416 trf6151_set_arfcn(arfcn, 1);
418 trf6151_set_mode(TRF6151_TX);
419 tpu_enq_wait(TRF6151_RX_PLL_DELAY);
426 #define TRF6151_REGWR_QBITS 8 /* 4 GSM qbits + 4 TPU instructions */
427 #define TRF6151_RX_TPU_INSTR 4 /* set_gain(1), set_arfcn(2), set_mode(1) */
429 /* delay caused by this driver programming the TPU for RX mode */
430 #define TRF6151_RX_TPU_DELAY (TRF6151_RX_TPU_INSTR * TRF6151_REGWR_QBITS)
432 /* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
433 void trf6151_rx_window(int16_t start_qbits, uint16_t arfcn)
435 int16_t start_pll_qbits;
437 /* power up at the right time _before_ the 'start_qbits' point in time */
438 start_pll_qbits = add_mod5000(start_qbits, -(TRF6151_RX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
439 tpu_enq_at(start_pll_qbits);
441 /* Set the AGC and PLL registers */
442 trf6151_set_arfcn(arfcn, 0);
443 trf6151_set_gain(trf6151_vga_dbm, trf6151_gain_high);
444 trf6151_set_mode(TRF6151_RX);
446 /* FIXME: power down at the right time again */
449 /* prepare a Tx window with the TRF6151 finished at time 'start' (in qbits) */
450 void trf6151_tx_window(int16_t start_qbits, uint16_t arfcn)
452 #ifdef CONFIG_TX_ENABLE
453 int16_t start_pll_qbits;
455 /* power up at the right time _before_ the 'start_qbits' point in time */
456 start_pll_qbits = add_mod5000(start_qbits, -(TRF6151_TX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
457 tpu_enq_at(start_pll_qbits);
459 trf6151_set_arfcn(arfcn, 1);
460 trf6151_set_mode(TRF6151_TX);
462 /* FIXME: power down at the right time again */
466 /* Given the expected input level of exp_inp dBm and the target of target_bb
467 * dBm, configure the RF Frontend with the respective gain */
468 void trf6151_compute_gain(int16_t exp_inp, int16_t target_bb)
470 /* TRF6151 VGA gain between 14 to 40 dB, plus 20db high/low */
471 int16_t exp_bb_dbm8, delta_dbm8;
472 int16_t exp_inp_dbm8 = to_dbm8(exp_inp);
473 int16_t target_bb_dbm8 = to_dbm8(target_bb);
474 int16_t vga_gain = TRF6151_VGA_GAIN_MIN;
477 /* calculate the dBm8 that we expect at the baseband */
478 exp_bb_dbm8 = exp_inp_dbm8 + to_dbm8(system_inherent_gain);
480 /* calculate the error that we expect. */
481 delta_dbm8 = target_bb_dbm8 - exp_bb_dbm8;
483 /* If this is negative or less than TRF6151_GAIN_MIN, we are pretty
484 * much lost as we cannot reduce the system inherent gain. If it is
485 * positive, it corresponds to the gain that we need to configure */
486 if (delta_dbm8 < to_dbm8(TRF6151_FE_GAIN_LOW + TRF6151_VGA_GAIN_MIN)) {
487 printd("AGC Input level overflow\n");
489 vga_gain = TRF6151_VGA_GAIN_MIN;
490 } else if (delta_dbm8 > to_dbm8(TRF6151_FE_GAIN_HIGH +
491 TRF6151_VGA_GAIN_MIN)) {
493 delta_dbm8 -= to_dbm8(TRF6151_FE_GAIN_HIGH);
495 vga_gain = delta_dbm8/8;
496 if (vga_gain > TRF6151_VGA_GAIN_MAX)
497 vga_gain = TRF6151_VGA_GAIN_MAX;
499 /* update the static global variables which are used when programming
501 trf6151_vga_dbm = vga_gain;
502 trf6151_gain_high = high;