1 /*
2 * Copyright 2012 Jared Boone
3 * Copyright 2013 Benjamin Vernoux
4 *
5 * This file is part of HackRF.
6 *
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, or (at your option)
10 * any later version.
11 *
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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include "rf_path.h"
24
25 #include <libopencm3/lpc43xx/scu.h>
26
27 #include <hackrf_core.h>
28
29 #include "hackrf_ui.h"
30
31 #include <mixer.h>
32 #include <max2837.h>
33 #include <max5864.h>
34 #include <sgpio.h>
35
36 #if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O)
37 /*
38 * RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on
39 * the RFFC5072.
40 *
41 * On HackRF One, the same signals are controlled by GPIO on the LPC.
42 * SWITCHCTRL_NO_TX_AMP_PWR and SWITCHCTRL_NO_RX_AMP_PWR are not normally used
43 * on HackRF One as the amplifier power is instead controlled only by
44 * SWITCHCTRL_AMP_BYPASS.
45 *
46 * The rad1o also uses GPIO pins to control the different switches. The amplifiers
47 * are also connected to the LPC.
48 */
49 #define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */
50 #define SWITCHCTRL_AMP_BYPASS (1 << 1) /* GPO2 bypass amp section */
51 #define SWITCHCTRL_TX (1 << 2) /* GPO3 1 for TX mode, 0 for RX mode */
52 #define SWITCHCTRL_MIX_BYPASS (1 << 3) /* GPO4 bypass RFFC5072 mixer section */
53 #define SWITCHCTRL_HP (1 << 4) /* GPO5 1 for high-pass, 0 for low-pass */
54 #define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* GPO6 turn off RX amp power */
55
56 /*
57 GPO6 GPO5 GPO4 GPO3 GPO2 GPO1
58 !RXAMP HP MIXBP TX AMPBP !TXAMP Mix mode Amp mode
59 1 X 1 1 1 1 TX bypass Bypass
60 1 X 1 1 0 0 TX bypass TX amplified
61 1 1 0 1 1 1 TX high Bypass
62 1 1 0 1 0 0 TX high TX amplified
63 1 0 0 1 1 1 TX low Bypass
64 1 0 0 1 0 0 TX low TX amplified
65 1 X 1 0 1 1 RX bypass Bypass
66 0 X 1 0 0 1 RX bypass RX amplified
67 1 1 0 0 1 1 RX high Bypass
68 0 1 0 0 0 1 RX high RX amplified
69 1 0 0 0 1 1 RX low Bypass
70 0 0 0 0 0 1 RX low RX amplified
71 */
72
73 /*
74 * Safe (initial) switch settings turn off both amplifiers and enable both amp
75 * bypass and mixer bypass.
76 */
77 #define SWITCHCTRL_SAFE (SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_TX | SWITCHCTRL_MIX_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_NO_RX_AMP_PWR)
78 #endif
79
80 uint8_t switchctrl = SWITCHCTRL_SAFE;
81
82 /*
83 * Antenna port power on HackRF One is controlled by GPO1 on the RFFC5072.
84 * This is the only thing we use RFFC5072 GPO for on HackRF One. The value of
85 * SWITCHCTRL_NO_ANT_PWR does not correspond to the GPO1 bit in the gpo
86 * register.
87 */
88 #define SWITCHCTRL_ANT_PWR (1 << 6) /* turn on antenna port power */
89
90 #ifdef HACKRF_ONE
switchctrl_set_hackrf_one(rf_path_t * const rf_path,uint8_t ctrl)91 static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) {
92 if (ctrl & SWITCHCTRL_TX) {
93 gpio_set(rf_path->gpio_tx);
94 gpio_clear(rf_path->gpio_rx);
95 } else {
96 gpio_clear(rf_path->gpio_tx);
97 gpio_set(rf_path->gpio_rx);
98 }
99
100 if (ctrl & SWITCHCTRL_MIX_BYPASS) {
101 gpio_set(rf_path->gpio_mix_bypass);
102 gpio_clear(rf_path->gpio_no_mix_bypass);
103 if (ctrl & SWITCHCTRL_TX) {
104 gpio_set(rf_path->gpio_tx_mix_bp);
105 gpio_clear(rf_path->gpio_rx_mix_bp);
106 } else {
107 gpio_clear(rf_path->gpio_tx_mix_bp);
108 gpio_set(rf_path->gpio_rx_mix_bp);
109 }
110 } else {
111 gpio_clear(rf_path->gpio_mix_bypass);
112 gpio_set(rf_path->gpio_no_mix_bypass);
113 gpio_clear(rf_path->gpio_tx_mix_bp);
114 gpio_clear(rf_path->gpio_rx_mix_bp);
115 }
116
117 if (ctrl & SWITCHCTRL_HP) {
118 gpio_set(rf_path->gpio_hp);
119 gpio_clear(rf_path->gpio_lp);
120 } else {
121 gpio_clear(rf_path->gpio_hp);
122 gpio_set(rf_path->gpio_lp);
123 }
124
125 if (ctrl & SWITCHCTRL_AMP_BYPASS) {
126 gpio_set(rf_path->gpio_amp_bypass);
127 gpio_clear(rf_path->gpio_tx_amp);
128 gpio_set(rf_path->gpio_no_tx_amp_pwr);
129 gpio_clear(rf_path->gpio_rx_amp);
130 gpio_set(rf_path->gpio_no_rx_amp_pwr);
131 } else if (ctrl & SWITCHCTRL_TX) {
132 gpio_clear(rf_path->gpio_amp_bypass);
133 gpio_set(rf_path->gpio_tx_amp);
134 gpio_clear(rf_path->gpio_no_tx_amp_pwr);
135 gpio_clear(rf_path->gpio_rx_amp);
136 gpio_set(rf_path->gpio_no_rx_amp_pwr);
137 } else {
138 gpio_clear(rf_path->gpio_amp_bypass);
139 gpio_clear(rf_path->gpio_tx_amp);
140 gpio_set(rf_path->gpio_no_tx_amp_pwr);
141 gpio_set(rf_path->gpio_rx_amp);
142 gpio_clear(rf_path->gpio_no_rx_amp_pwr);
143 }
144
145 /*
146 * These normally shouldn't be set post-Jawbreaker, but they can be
147 * used to explicitly turn off power to the amplifiers while AMP_BYPASS
148 * is unset:
149 */
150 if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR)
151 gpio_set(rf_path->gpio_no_tx_amp_pwr);
152 if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR)
153 gpio_set(rf_path->gpio_no_rx_amp_pwr);
154
155 if (ctrl & SWITCHCTRL_ANT_PWR) {
156 mixer_set_gpo(&mixer, 0x00); /* turn on antenna power by clearing GPO1 */
157 } else {
158 mixer_set_gpo(&mixer, 0x01); /* turn off antenna power by setting GPO1 */
159 }
160 }
161 #endif
162
163 #ifdef RAD1O
switchctrl_set_rad1o(rf_path_t * const rf_path,uint8_t ctrl)164 static void switchctrl_set_rad1o(rf_path_t* const rf_path, uint8_t ctrl) {
165 if (ctrl & SWITCHCTRL_TX) {
166 gpio_set(rf_path->gpio_tx_rx_n);
167 gpio_clear(rf_path->gpio_tx_rx);
168 } else {
169 gpio_clear(rf_path->gpio_tx_rx_n);
170 gpio_set(rf_path->gpio_tx_rx);
171 }
172
173 if (ctrl & SWITCHCTRL_MIX_BYPASS) {
174 gpio_clear(rf_path->gpio_by_mix);
175 gpio_set(rf_path->gpio_by_mix_n);
176 gpio_clear(rf_path->gpio_mixer_en);
177 } else {
178 gpio_set(rf_path->gpio_by_mix);
179 gpio_clear(rf_path->gpio_by_mix_n);
180 gpio_set(rf_path->gpio_mixer_en);
181 }
182
183 if (ctrl & SWITCHCTRL_HP) {
184 gpio_set(rf_path->gpio_low_high_filt);
185 gpio_clear(rf_path->gpio_low_high_filt_n);
186 } else {
187 gpio_clear(rf_path->gpio_low_high_filt);
188 gpio_set(rf_path->gpio_low_high_filt_n);
189 }
190
191 if (ctrl & SWITCHCTRL_AMP_BYPASS) {
192 gpio_clear(rf_path->gpio_by_amp);
193 gpio_set(rf_path->gpio_by_amp_n);
194
195 gpio_clear(rf_path->gpio_tx_amp);
196 gpio_clear(rf_path->gpio_rx_lna);
197
198 } else if (ctrl & SWITCHCTRL_TX) {
199 gpio_set(rf_path->gpio_by_amp);
200 gpio_clear(rf_path->gpio_by_amp_n);
201
202 gpio_set(rf_path->gpio_tx_amp);
203 gpio_clear(rf_path->gpio_rx_lna);
204
205 } else {
206 gpio_set(rf_path->gpio_by_amp);
207 gpio_clear(rf_path->gpio_by_amp_n);
208
209 gpio_clear(rf_path->gpio_tx_amp);
210 gpio_set(rf_path->gpio_rx_lna);
211 }
212
213 /*
214 * These normally shouldn't be set post-Jawbreaker, but they can be
215 * used to explicitly turn off power to the amplifiers while AMP_BYPASS
216 * is unset:
217 */
218 if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR) {
219 gpio_clear(rf_path->gpio_tx_amp);
220 }
221 if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR) {
222 gpio_clear(rf_path->gpio_rx_lna);
223 }
224 }
225 #endif
226
switchctrl_set(rf_path_t * const rf_path,const uint8_t gpo)227 static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) {
228 #ifdef JAWBREAKER
229 (void) rf_path; /* silence unused param warning */
230 mixer_set_gpo(&mixer, gpo);
231 #elif HACKRF_ONE
232 switchctrl_set_hackrf_one(rf_path, gpo);
233 #elif RAD1O
234 switchctrl_set_rad1o(rf_path, gpo);
235 #else
236 (void)gpo;
237 #endif
238 }
239
rf_path_pin_setup(rf_path_t * const rf_path)240 void rf_path_pin_setup(rf_path_t* const rf_path) {
241 #ifdef HACKRF_ONE
242 /* Configure RF switch control signals */
243 scu_pinmux(SCU_HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
244 scu_pinmux(SCU_LP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
245 scu_pinmux(SCU_TX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
246 scu_pinmux(SCU_NO_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
247 scu_pinmux(SCU_RX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
248 scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
249 scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
250 scu_pinmux(SCU_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
251 scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
252 scu_pinmux(SCU_NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
253 scu_pinmux(SCU_AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
254 scu_pinmux(SCU_RX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
255 scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
256
257 /* Configure RF power supply (VAA) switch */
258 scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
259
260 /* Configure RF switch control signals as outputs */
261 gpio_output(rf_path->gpio_amp_bypass);
262 gpio_output(rf_path->gpio_no_mix_bypass);
263 gpio_output(rf_path->gpio_rx_amp);
264 gpio_output(rf_path->gpio_no_rx_amp_pwr);
265 gpio_output(rf_path->gpio_hp);
266 gpio_output(rf_path->gpio_lp);
267 gpio_output(rf_path->gpio_tx_mix_bp);
268 gpio_output(rf_path->gpio_rx_mix_bp);
269 gpio_output(rf_path->gpio_tx_amp);
270 gpio_output(rf_path->gpio_no_tx_amp_pwr);
271 gpio_output(rf_path->gpio_tx);
272 gpio_output(rf_path->gpio_mix_bypass);
273 gpio_output(rf_path->gpio_rx);
274
275 /*
276 * Safe (initial) switch settings turn off both amplifiers and antenna port
277 * power and enable both amp bypass and mixer bypass.
278 */
279 switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
280 #elif RAD1O
281 /* Configure RF switch control signals */
282 scu_pinmux(SCU_BY_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
283 scu_pinmux(SCU_BY_AMP_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
284 scu_pinmux(SCU_TX_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
285 scu_pinmux(SCU_TX_RX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
286 scu_pinmux(SCU_BY_MIX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
287 scu_pinmux(SCU_BY_MIX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
288 scu_pinmux(SCU_LOW_HIGH_FILT, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
289 scu_pinmux(SCU_LOW_HIGH_FILT_N,SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
290 scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
291 scu_pinmux(SCU_RX_LNA, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
292 scu_pinmux(SCU_MIXER_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
293
294 /* Configure RF power supply (VAA) switch */
295 scu_pinmux(SCU_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
296
297 /* Configure RF switch control signals as outputs */
298 gpio_output(rf_path->gpio_tx_rx_n);
299 gpio_output(rf_path->gpio_tx_rx);
300 gpio_output(rf_path->gpio_by_mix);
301 gpio_output(rf_path->gpio_by_mix_n);
302 gpio_output(rf_path->gpio_by_amp);
303 gpio_output(rf_path->gpio_by_amp_n);
304 gpio_output(rf_path->gpio_mixer_en);
305 gpio_output(rf_path->gpio_low_high_filt);
306 gpio_output(rf_path->gpio_low_high_filt_n);
307 gpio_output(rf_path->gpio_tx_amp);
308 gpio_output(rf_path->gpio_rx_lna);
309
310 /*
311 * Safe (initial) switch settings turn off both amplifiers and antenna port
312 * power and enable both amp bypass and mixer bypass.
313 */
314 switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
315 #else
316 (void) rf_path; /* silence unused param warning */
317 #endif
318 }
319
rf_path_init(rf_path_t * const rf_path)320 void rf_path_init(rf_path_t* const rf_path) {
321 ssp1_set_mode_max5864();
322 max5864_setup(&max5864);
323 max5864_shutdown(&max5864);
324
325 ssp1_set_mode_max2837();
326 max2837_setup(&max2837);
327 max2837_start(&max2837);
328
329 mixer_setup(&mixer);
330 switchctrl_set(rf_path, switchctrl);
331 }
332
rf_path_set_direction(rf_path_t * const rf_path,const rf_path_direction_t direction)333 void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t direction) {
334 /* Turn off TX and RX amplifiers, then enable based on direction and bypass state. */
335 rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
336 switch(direction) {
337 case RF_PATH_DIRECTION_TX:
338 rf_path->switchctrl |= SWITCHCTRL_TX;
339 if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
340 /* TX amplifier is in path, be sure to enable TX amplifier. */
341 rf_path->switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR;
342 }
343 mixer_tx(&mixer);
344 if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
345 mixer_disable(&mixer);
346 } else {
347 mixer_enable(&mixer);
348 }
349 ssp1_set_mode_max5864();
350 max5864_tx(&max5864);
351 ssp1_set_mode_max2837();
352 max2837_tx(&max2837);
353 sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX);
354 break;
355
356 case RF_PATH_DIRECTION_RX:
357 rf_path->switchctrl &= ~SWITCHCTRL_TX;
358 if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
359 /* RX amplifier is in path, be sure to enable RX amplifier. */
360 rf_path->switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR;
361 }
362 mixer_rx(&mixer);
363 if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
364 mixer_disable(&mixer);
365 } else {
366 mixer_enable(&mixer);
367 }
368 ssp1_set_mode_max5864();
369 max5864_rx(&max5864);
370 ssp1_set_mode_max2837();
371 max2837_rx(&max2837);
372 sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
373 break;
374
375 case RF_PATH_DIRECTION_OFF:
376 default:
377 #ifdef HACKRF_ONE
378 rf_path_set_antenna(rf_path, 0);
379 #endif
380 rf_path_set_lna(rf_path, 0);
381 /* Set RF path to receive direction when "off" */
382 rf_path->switchctrl &= ~SWITCHCTRL_TX;
383 mixer_disable(&mixer);
384 ssp1_set_mode_max5864();
385 max5864_standby(&max5864);
386 ssp1_set_mode_max2837();
387 max2837_set_mode(&max2837, MAX2837_MODE_STANDBY);
388 sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
389 break;
390 }
391
392 switchctrl_set(rf_path, rf_path->switchctrl);
393
394 hackrf_ui()->set_direction(direction);
395 }
396
rf_path_set_filter(rf_path_t * const rf_path,const rf_path_filter_t filter)397 void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) {
398 switch(filter) {
399 default:
400 case RF_PATH_FILTER_BYPASS:
401 rf_path->switchctrl |= SWITCHCTRL_MIX_BYPASS;
402 mixer_disable(&mixer);
403 break;
404
405 case RF_PATH_FILTER_LOW_PASS:
406 rf_path->switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
407 mixer_enable(&mixer);
408 break;
409
410 case RF_PATH_FILTER_HIGH_PASS:
411 rf_path->switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
412 rf_path->switchctrl |= SWITCHCTRL_HP;
413 mixer_enable(&mixer);
414 break;
415 }
416
417 switchctrl_set(rf_path, rf_path->switchctrl);
418
419 hackrf_ui()->set_filter(filter);
420 }
421
rf_path_set_lna(rf_path_t * const rf_path,const uint_fast8_t enable)422 void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) {
423 if( enable ) {
424 if( rf_path->switchctrl & SWITCHCTRL_TX ) {
425 /* AMP_BYPASS=0, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=0 */
426 rf_path->switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR;
427 rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR);
428 } else {
429 /* AMP_BYPASS=0, NO_RX_AMP_PWR=0, NO_TX_AMP_PWR=1 */
430 rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR;
431 rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR);
432 }
433 } else {
434 /* AMP_BYPASS=1, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=1 */
435 rf_path->switchctrl |= SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
436 }
437
438 switchctrl_set(rf_path, rf_path->switchctrl);
439
440 hackrf_ui()->set_lna_power(enable);
441 }
442
443 /* antenna port power control */
rf_path_set_antenna(rf_path_t * const rf_path,const uint_fast8_t enable)444 void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) {
445 if (enable) {
446 rf_path->switchctrl |= SWITCHCTRL_ANT_PWR;
447 } else {
448 rf_path->switchctrl &= ~(SWITCHCTRL_ANT_PWR);
449 }
450
451 switchctrl_set(rf_path, rf_path->switchctrl);
452
453 hackrf_ui()->set_antenna_bias(enable);
454 }
455