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 tx
)
436 enum trf6151_gsm_band pll_band
;
438 uplink
= !!(arfcn
& ARFCN_UPLINK
);
439 arfcn
!= ~ARFCN_UPLINK
;
441 switch (gsm_arfcn2band(arfcn
)) {
452 printf("Unsupported band ! YMMV.\n");
456 freq_khz
= gsm_arfcn2freq10(arfcn
, uplink
) * 100;
457 printd("ARFCN %u -> %u kHz\n", arfcn
, freq_khz
);
460 trf6151_pll_rx(freq_khz
, &pll_config
, &pll_band
);
462 trf6151_pll_tx(freq_khz
, &pll_config
, &pll_band
);
464 trf6151_band_select(pll_band
);
465 trf6151_reg_write(REG_PLL
, pll_config
);
468 rf_arfcn
= arfcn
; // TODO: arfcn is referenced at other places
471 void trf6151_calib_dc_offs(void)
473 uint16_t rx
= trf6151_reg_cache
[REG_RX
];
475 /* Set RX CAL Mode bit, it will re-set automatically */
476 trf6151_reg_write(REG_RX
, rx
| RX_CAL_MODE
);
477 /* DC offset calibration can take up to 50us, i.e. 54.16 * 923ns*/
481 uint8_t trf6151_get_gain_reg(void)
483 uint16_t vga
, reg_rx
= trf6151_reg_cache
[REG_RX
];
486 switch ((reg_rx
>> 9) & 3) {
488 gain
+= TRF6151_FE_GAIN_LOW
;
491 gain
+= TRF6151_FE_GAIN_HIGH
;
495 vga
= (reg_rx
>> RX_VGA_GAIN_SHIFT
) & 0x1f;
499 gain
+= TRF6151_VGA_GAIN_MIN
+ (vga
- 6) * 2;
504 uint8_t trf6151_get_gain(void)
508 gain
= trf6151_vga_dbm
;
509 if (trf6151_gain_high
)
510 gain
+= TRF6151_FE_GAIN_HIGH
;
512 gain
+= TRF6151_FE_GAIN_LOW
;
517 void trf6151_test(uint16_t arfcn
)
519 /* Select ARFCN downlink */
520 trf6151_set_arfcn(arfcn
, 0);
522 trf6151_set_mode(TRF6151_RX
);
523 //trf6151_reg_write(REG_PWR, (PWR_SYNTHE_RX_ON | PWR_RX_MODE | PWR_REGUL_ON | (rf_band<<6) | PWR_BANDGAP_ON));
524 /* Wait for PLL stabilization (170us max) */
525 tpu_enq_wait(TRF6151_RX_PLL_DELAY
);
527 /* Use DC offset calibration after RX mode has been switched on
528 * (might not be needed) */
529 trf6151_calib_dc_offs();
536 void trf6151_tx_test(uint16_t arfcn
)
538 /* Select ARFCN uplink */
539 trf6151_set_arfcn(arfcn
| ARFCN_UPLINK
, 1);
541 trf6151_set_mode(TRF6151_TX
);
542 tpu_enq_wait(TRF6151_RX_PLL_DELAY
);
549 #define TRF6151_REGWR_QBITS 8 /* 4 GSM qbits + 4 TPU instructions */
550 #define TRF6151_RX_TPU_INSTR 4 /* set_gain_reg(1), set_arfcn(2), set_mode(1) */
552 /* delay caused by this driver programming the TPU for RX mode */
553 #define TRF6151_RX_TPU_DELAY (TRF6151_RX_TPU_INSTR * TRF6151_REGWR_QBITS)
555 /* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
556 void trf6151_rx_window(int16_t start_qbits
, uint16_t arfcn
)
558 int16_t start_pll_qbits
;
560 /* power up at the right time _before_ the 'start_qbits' point in time */
561 start_pll_qbits
= add_mod5000(start_qbits
, -(TRF6151_RX_PLL_DELAY
+ TRF6151_RX_TPU_DELAY
));
562 tpu_enq_at(start_pll_qbits
);
564 /* Set the AGC and PLL registers */
565 trf6151_set_arfcn(arfcn
, 0);
566 trf6151_set_gain_reg(trf6151_vga_dbm
, trf6151_gain_high
);
567 trf6151_set_mode(TRF6151_RX
);
569 /* FIXME: power down at the right time again */
572 /* prepare a Tx window with the TRF6151 finished at time 'start' (in qbits) */
573 void trf6151_tx_window(int16_t start_qbits
, uint16_t arfcn
)
575 #ifdef CONFIG_TX_ENABLE
576 int16_t start_pll_qbits
;
578 /* power up at the right time _before_ the 'start_qbits' point in time */
579 start_pll_qbits
= add_mod5000(start_qbits
, -(TRF6151_TX_PLL_DELAY
+ TRF6151_RX_TPU_DELAY
));
580 tpu_enq_at(start_pll_qbits
);
582 trf6151_set_arfcn(arfcn
, 1);
583 trf6151_set_mode(TRF6151_TX
);
585 /* FIXME: power down at the right time again */
589 /* Given the expected input level of exp_inp dBm and the target of target_bb
590 * dBm, configure the RF Frontend with the respective gain */
591 void trf6151_compute_gain(int16_t exp_inp
, int16_t target_bb
)
593 /* TRF6151 VGA gain between 14 to 40 dB, plus 20db high/low */
594 int16_t exp_bb
, delta
;
596 /* calculate the dBm8 that we expect at the baseband */
597 exp_bb
= exp_inp
+ system_inherent_gain
;
599 /* calculate the error that we expect. */
600 delta
= target_bb
- exp_bb
;
602 printd("computed gain %d\n", delta
);
603 trf6151_set_gain(delta
);