diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index b0ec4e3a..88accc11 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -28,8 +28,6 @@ #include #include -#ifdef JELLYBEAN - void delay(uint32_t duration) { uint32_t i; @@ -51,6 +49,19 @@ void cpu_clock_init(void) si5351c_configure_pll_sources_for_xtal(); si5351c_configure_pll1_multisynth(); +#ifdef JELLYBEAN + /* + * Jellybean/Lemondrop clocks: + * CLK0 -> MAX2837 + * CLK1 -> MAX5864/CPLD + * CLK2 -> CPLD + * CLK3 -> CPLD + * CLK4 -> LPC4330 + * CLK5 -> RFFC5072 + * CLK6 -> extra + * CLK7 -> extra + */ + /* MS0/CLK0 is the source for the MAX2837 clock input. */ si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */ @@ -68,6 +79,42 @@ void cpu_clock_init(void) /* MS5/CLK5 is the source for the RFFC5071 mixer. */ si5351c_configure_multisynth(5, 1536, 0, 1, 0); /* 50MHz */ +#endif + +#ifdef JAWBREAKER + /* + * Jawbreaker clocks: + * CLK0 -> MAX5864/CPLD + * CLK1 -> CPLD + * CLK2 -> SGPIO + * CLK3 -> external clock output + * CLK4 -> RFFC5072 + * CLK5 -> MAX2837 + * CLK6 -> none + * CLK7 -> LPC4330 (but LPC4330 starts up on its own crystal) + */ + + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(0, 4608, 0, 1, 1); /* 10MHz */ + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth(1, 4608, 0, 1, 0); /* 20MHz */ + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth(2, 4608, 0, 1, 0); /* 20MHz */ + + /* MS0/CLK3 is the source for the external clock output. */ + si5351c_configure_multisynth(3, 4608, 0, 1, 0); /* 20MHz */ + + /* MS4/CLK4 is the source for the RFFC5071 mixer. */ + si5351c_configure_multisynth(4, 1536, 0, 1, 0); /* 50MHz */ + + /* MS5/CLK5 is the source for the MAX2837 clock input. */ + si5351c_configure_multisynth(5, 2048, 0, 1, 0); /* 40MHz */ + + /* MS7/CLK7 is the source for the LPC43xx microcontroller. */ + //si5351c_configure_multisynth(7, 8021, 0, 3, 0); /* 12MHz */ +#endif si5351c_configure_clock_control(); si5351c_enable_clock_outputs(); @@ -75,14 +122,18 @@ void cpu_clock_init(void) //FIXME disable I2C /* - * 12MHz clock is entering LPC XTAL1/OSC input now. + * 12MHz clock is entering LPC XTAL1/OSC input now. On + * Jellybean/Lemondrop, this is a signal from the clock generator. On + * Jawbreaker, there is a 12 MHz crystal at the LPC. * Set up PLL1 to run from XTAL1 input. */ //FIXME a lot of the details here should be in a CGU driver +#ifdef JELLYBEAN /* configure xtal oscillator for external clock input signal */ CGU_XTAL_OSC_CTRL |= CGU_XTAL_OSC_CTRL_BYPASS; +#endif /* set xtal oscillator to low frequency mode */ CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF; @@ -203,56 +254,3 @@ void ssp1_set_mode_max5864(void) SSP_MASTER, SSP_SLAVE_OUT_ENABLE); } - -void pin_setup(void) { - /* Release CPLD JTAG pins */ - scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); - scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); - - GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO; - GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK; - GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS; - GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI; - - /* Configure SCU Pin Mux as GPIO */ - scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST); - scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST); - scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST); - - scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST); - - scu_pinmux(SCU_PINMUX_BOOT0, SCU_GPIO_FAST); - scu_pinmux(SCU_PINMUX_BOOT1, SCU_GPIO_FAST); - scu_pinmux(SCU_PINMUX_BOOT2, SCU_GPIO_FAST); - scu_pinmux(SCU_PINMUX_BOOT3, SCU_GPIO_FAST); - - /* Configure all GPIO as Input (safe state) */ - GPIO0_DIR = 0; - GPIO1_DIR = 0; - GPIO2_DIR = 0; - GPIO3_DIR = 0; - GPIO4_DIR = 0; - GPIO5_DIR = 0; - GPIO6_DIR = 0; - GPIO7_DIR = 0; - - /* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */ - GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3); - - /* GPIO3[6] on P6_10 as output. */ - GPIO3_DIR |= PIN_EN1V8; - - /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ - scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); - scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); - scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); -} - -void enable_1v8_power(void) { - gpio_set(PORT_EN1V8, PIN_EN1V8); -} - -#endif diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index c2e029d7..d85000a3 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -32,15 +32,19 @@ extern "C" #include /* hardware identification number */ -#define BOARD_ID_JELLYBEAN 0 +#define BOARD_ID_JELLYBEAN 0 +#define BOARD_ID_JAWBREAKER 1 #ifdef JELLYBEAN #define BOARD_ID BOARD_ID_JELLYBEAN #endif -#ifdef JELLYBEAN +#ifdef JAWBREAKER +#define BOARD_ID BOARD_ID_JAWBREAKER +#endif + /* - * Jellybean SCU PinMux + * SCU PinMux */ /* GPIO Output PinMux */ @@ -96,14 +100,28 @@ extern "C" #define SCU_AD_CS (P5_7) /* GPIO2[7] on P5_7 */ /* RFFC5071 GPIO serial interface PinMux */ +#ifdef JELLYBEAN #define SCU_MIXER_ENX (P7_0) /* GPIO3[8] on P7_0 */ #define SCU_MIXER_SCLK (P7_1) /* GPIO3[9] on P7_1 */ #define SCU_MIXER_SDATA (P7_2) /* GPIO3[10] on P7_2 */ +#define SCU_MIXER_RESETX (P7_3) /* GPIO3[11] on P7_3 */ +#endif +#ifdef JAWBREAKER +#define SCU_MIXER_ENX (P5_4) /* GPIO2[13] on P5_4 */ +#define SCU_MIXER_SCLK (P2_6) /* GPIO5[6] on P2_6 */ +#define SCU_MIXER_SDATA (P6_4) /* GPIO3[3] on P6_4 */ +#define SCU_MIXER_RESETX (P5_5) /* GPIO2[14] on P5_5 */ +#endif + +/* RF LDO control */ +#ifdef JAWBREAKER +#define RF_LDO_ENABLE (P5_0) /* GPIO2[9] on P5_0 */ +#endif /* TODO add other Pins */ /* - * Jellybean GPIO Pins + * GPIO Pins */ /* GPIO Output */ @@ -125,10 +143,31 @@ extern "C" #define PIN_AD_CS (BIT7) /* GPIO2[7] on P5_7 */ #define PORT_AD_CS (GPIO2) /* PORT for AD_CS */ -#define PIN_MIXER_ENX (BIT8) /* GPIO3[8] on P7_0 */ -#define PIN_MIXER_SCLK (BIT9) /* GPIO3[9] on P7_1 */ -#define PIN_MIXER_SDATA (BIT10) /* GPIO3[10] on P7_2 */ -#define PORT_MIXER (GPIO3) /* PORT for mixer serial interface */ +#ifdef JELLYBEAN +#define PIN_MIXER_ENX (BIT8) /* GPIO3[8] on P7_0 */ +#define PORT_MIXER_ENX (GPIO3) +#define PIN_MIXER_SCLK (BIT9) /* GPIO3[9] on P7_1 */ +#define PORT_MIXER_SCLK (GPIO3) +#define PIN_MIXER_SDATA (BIT10) /* GPIO3[10] on P7_2 */ +#define PORT_MIXER_SDATA (GPIO3) +#define PIN_MIXER_RESETX (BIT11) /* GPIO3[11] on P7_3 */ +#define PORT_MIXER_RESETX (GPIO3) +#endif +#ifdef JAWBREAKER +#define PIN_MIXER_ENX (BIT13) /* GPIO2[13] on P5_4 */ +#define PORT_MIXER_ENX (GPIO2) +#define PIN_MIXER_SCLK (BIT6) /* GPIO5[6] on P2_6 */ +#define PORT_MIXER_SCLK (GPIO5) +#define PIN_MIXER_SDATA (BIT3) /* GPIO3[3] on P6_4 */ +#define PORT_MIXER_SDATA (GPIO3) +#define PIN_MIXER_RESETX (BIT14) /* GPIO2[14] on P5_5 */ +#define PORT_MIXER_RESETX (GPIO2) +#endif + +#ifdef JAWBREAKER +#define PIN_RF_LDO_ENABLE (BIT9) /* GPIO2[9] on P5_0 */ +#define PORT_RF_LDO_ENABLE (GPIO2) /* PORT for RF_LDO_ENABLE */ +#endif /* GPIO Input */ #define PIN_BOOT0 (BIT8) /* GPIO0[8] on P1_1 */ @@ -147,14 +186,14 @@ extern "C" #define PORT_CPLD_TDI (GPIO3) /* Read GPIO Pin */ -#define BOOT0_STATE ((GPIO0_PIN & PIN_BOOT0)==PIN_BOOT0) -#define BOOT1_STATE ((GPIO0_PIN & PIN_BOOT1)==PIN_BOOT1) -#define BOOT2_STATE ((GPIO5_PIN & PIN_BOOT2)==PIN_BOOT2) -#define BOOT3_STATE ((GPIO1_PIN & PIN_BOOT3)==PIN_BOOT3) -#define MIXER_SDATA_STATE ((GPIO3_PIN & PIN_MIXER_SDATA)==PIN_MIXER_SDATA) +#define GPIO_STATE(port, pin) ((GPIO_PIN(port) & (pin)) == (pin)) +#define BOOT0_STATE GPIO_STATE(GPIO0, PIN_BOOT0) +#define BOOT1_STATE GPIO_STATE(GPIO0, PIN_BOOT1) +#define BOOT2_STATE GPIO_STATE(GPIO5, PIN_BOOT2) +#define BOOT3_STATE GPIO_STATE(GPIO1, PIN_BOOT3) +#define MIXER_SDATA_STATE GPIO_STATE(PORT_MIXER_SDATA, PIN_MIXER_SDATA) /* TODO add other Pins */ -#endif void delay(uint32_t duration); diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index 3bc678bf..35f2b8c8 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -24,6 +24,12 @@ * program would do if it had a real spi library */ +/* + * The actual part on Jawbreaker is the RFFC5072, not the RFFC5071, but the + * RFFC5071 may be installed instead. The only difference between the parts is + * that the RFFC5071 includes a second mixer. + */ + #include #include #include "rffc5071.h" @@ -103,13 +109,19 @@ void rffc5071_setup(void) scu_pinmux(SCU_MIXER_ENX, SCU_GPIO_FAST); scu_pinmux(SCU_MIXER_SCLK, SCU_GPIO_FAST); scu_pinmux(SCU_MIXER_SDATA, SCU_GPIO_FAST); + scu_pinmux(SCU_MIXER_RESETX, SCU_GPIO_FAST); /* Set GPIO pins as outputs. */ - GPIO3_DIR |= (PIN_MIXER_ENX | PIN_MIXER_SCLK | PIN_MIXER_SDATA); + GPIO_DIR(PORT_MIXER_ENX) |= PIN_MIXER_ENX; + GPIO_DIR(PORT_MIXER_SCLK) |= PIN_MIXER_SCLK; + GPIO_DIR(PORT_MIXER_SDATA) |= PIN_MIXER_SDATA; + GPIO_DIR(PORT_MIXER_RESETX) |= PIN_MIXER_RESETX; /* set to known state */ - gpio_set(PORT_MIXER, PIN_MIXER_ENX); /* active low */ - gpio_clear(PORT_MIXER, (PIN_MIXER_SCLK | PIN_MIXER_SDATA)); + gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX); /* active low */ + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA); + gpio_set(PORT_MIXER_RESETX, PIN_MIXER_RESETX); /* active low */ #endif /* initial setup */ @@ -133,24 +145,10 @@ void rffc5071_setup(void) * not control pins. */ set_RFFC5071_SIPIN(1); - /* Initial settings for Lollipop switches, same for both - * paths. These could use some #defines that iron out the - * (non)inverted signals. - * - * bit0: SWTXB1 (!tx_bypass) - * bit1: SWRXB1 (rx_bypass) - * bit2: SWTXA1 (tx_hp) - * bit3: unused (lock bit) - * bit4: SWRXA1 (rx_hp) - * bit5 SWD1 (!tx_ant) - * - * Unknown whether shift is needed. There are 7 register bits - * to hold 6 GPO bits. */ - set_RFFC5071_P1GPO(0b010100<<1); - set_RFFC5071_P2GPO(0b010100<<1); - - /* send lock flag on GPO4 */ - set_RFFC5071_LOCK(1); +#ifdef JAWBREAKER + /* initial safe switch control settings */ + rffc5071_set_gpo(SWITCHCTRL_SAFE); +#endif /* GPOs are active at all times */ set_RFFC5071_GATE(1); @@ -185,69 +183,79 @@ uint16_t rffc5071_spi_read(uint8_t r) { return 0; #else /* make sure everything is starting in the correct state */ - gpio_set(PORT_MIXER, PIN_MIXER_ENX); - gpio_clear(PORT_MIXER, (PIN_MIXER_SCLK | PIN_MIXER_SDATA)); + gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA); /* * The device requires two clocks while ENX is high before a serial * transaction. This is not clearly documented. */ serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); /* start transaction by bringing ENX low */ - gpio_clear(PORT_MIXER, PIN_MIXER_ENX); + gpio_clear(PORT_MIXER_ENX, PIN_MIXER_ENX); while (bits--) { if (data & msb) - gpio_set(PORT_MIXER, PIN_MIXER_SDATA); + gpio_set(PORT_MIXER_SDATA, PIN_MIXER_SDATA); else - gpio_clear(PORT_MIXER, PIN_MIXER_SDATA); + gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA); data <<= 1; serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); } serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); bits = 16; data = 0; /* set SDATA line as input */ - GPIO3_DIR &= ~PIN_MIXER_SDATA; + GPIO_DIR(PORT_MIXER_SDATA) &= ~PIN_MIXER_SDATA; while (bits--) { data <<= 1; serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); if (MIXER_SDATA_STATE) data |= 1; } /* set SDATA line as output */ - GPIO3_DIR |= PIN_MIXER_SDATA; + GPIO_DIR(PORT_MIXER_SDATA) |= PIN_MIXER_SDATA; serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_ENX); + gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX); + + /* + * The device requires a clock while ENX is high after a serial + * transaction. This is not clearly documented. + */ + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); + + serial_delay(); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); return data; #endif /* DEBUG */ @@ -272,44 +280,54 @@ void rffc5071_spi_write(uint8_t r, uint16_t v) { uint32_t data = ((r & 0x7f) << 16) | v; /* make sure everything is starting in the correct state */ - gpio_set(PORT_MIXER, PIN_MIXER_ENX); - gpio_clear(PORT_MIXER, (PIN_MIXER_SCLK | PIN_MIXER_SDATA)); + gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA); /* * The device requires two clocks while ENX is high before a serial * transaction. This is not clearly documented. */ serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); /* start transaction by bringing ENX low */ - gpio_clear(PORT_MIXER, PIN_MIXER_ENX); + gpio_clear(PORT_MIXER_ENX, PIN_MIXER_ENX); while (bits--) { if (data & msb) - gpio_set(PORT_MIXER, PIN_MIXER_SDATA); + gpio_set(PORT_MIXER_SDATA, PIN_MIXER_SDATA); else - gpio_clear(PORT_MIXER, PIN_MIXER_SDATA); + gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA); data <<= 1; serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_SCLK); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); serial_delay(); - gpio_clear(PORT_MIXER, PIN_MIXER_SCLK); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); } + gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX); + + /* + * The device requires a clock while ENX is high after a serial + * transaction. This is not clearly documented. + */ serial_delay(); - gpio_set(PORT_MIXER, PIN_MIXER_ENX); + gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK); + + serial_delay(); + gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK); #endif } @@ -349,26 +367,58 @@ void rffc5071_regs_commit(void) } } -void rffc5071_tx(void) { +void rffc5071_tx(uint8_t gpo) { LOG("# rffc5071_tx\n"); set_RFFC5071_ENBL(0); set_RFFC5071_FULLD(0); - set_RFFC5071_MODE(0); /* mixer 1 only (TX) */ + set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */ +#ifdef JAWBREAKER + /* honor SWITCHCTRL_AMP_BYPASS and SWITCHCTRL_HP settings from caller */ + gpo &= (SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_HP); + if ((gpo & SWITCHCTRL_AMP_BYPASS) == SWITCHCTRL_AMP_BYPASS) + gpo |= SWITCHCTRL_NO_TX_AMP_PWR; + gpo |= (SWITCHCTRL_TX | SWITCHCTRL_NO_RX_AMP_PWR); + rffc5071_set_gpo(gpo); +#endif rffc5071_regs_commit(); - rffc5071_enable(); +#ifdef JAWBREAKER + /* honor SWITCHCTRL_MIX_BYPASS setting from caller */ + if ((gpo & SWITCHCTRL_MIX_BYPASS) == SWITCHCTRL_MIX_BYPASS) + rffc5071_disable(); + else +#endif + rffc5071_enable(); } -void rffc5071_rx(void) { +void rffc5071_rx(uint8_t gpo) { LOG("# rfc5071_rx\n"); set_RFFC5071_ENBL(0); set_RFFC5071_FULLD(0); - set_RFFC5071_MODE(1); /* mixer 2 only (RX) */ + set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */ +#ifdef JAWBREAKER + /* honor SWITCHCTRL_AMP_BYPASS and SWITCHCTRL_HP settings from caller */ + gpo &= (SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_HP); + if ((gpo & SWITCHCTRL_AMP_BYPASS) == SWITCHCTRL_AMP_BYPASS) + gpo |= SWITCHCTRL_NO_RX_AMP_PWR; + gpo |= SWITCHCTRL_NO_TX_AMP_PWR; + rffc5071_set_gpo(gpo); +#endif rffc5071_regs_commit(); - rffc5071_enable(); +#ifdef JAWBREAKER + /* honor SWITCHCTRL_MIX_BYPASS setting from caller */ + if ((gpo & SWITCHCTRL_MIX_BYPASS) == SWITCHCTRL_MIX_BYPASS) + rffc5071_disable(); + else +#endif + rffc5071_enable(); } +/* + * This function turns on both mixer (full-duplex) on the RFFC5071, but our + * current hardware designs do not support full-duplex operation. + */ void rffc5071_rxtx(void) { LOG("# rfc5071_rxtx\n"); set_RFFC5071_ENBL(0); @@ -433,14 +483,14 @@ uint16_t rffc5071_config_synth_int(uint16_t lo) { lo, n_lo, lodiv, fvco, fbkdiv, n, tune_freq); /* Path 1 */ - set_RFFC5071_P1LODIV(lodiv); + set_RFFC5071_P1LODIV(n_lo); set_RFFC5071_P1N(n); set_RFFC5071_P1PRESC(fbkdiv >> 1); set_RFFC5071_P1NMSB(0); set_RFFC5071_P1NLSB(0); /* Path 2 */ - set_RFFC5071_P2LODIV(lodiv); + set_RFFC5071_P2LODIV(n_lo); set_RFFC5071_P2N(n); set_RFFC5071_P2PRESC(fbkdiv >> 1); set_RFFC5071_P2NMSB(0); @@ -468,6 +518,15 @@ uint16_t rffc5071_set_frequency(uint16_t mhz, uint32_t hz) { return tune_freq; } +void rffc5071_set_gpo(uint8_t gpo) +{ + /* We set GPO for both paths just in case. */ + set_RFFC5071_P1GPO(gpo); + set_RFFC5071_P2GPO(gpo); + + rffc5071_regs_commit(); +} + #ifdef TEST int main(int ac, char **av) { diff --git a/firmware/common/rffc5071.h b/firmware/common/rffc5071.h index c9a5e08e..9b81fd46 100644 --- a/firmware/common/rffc5071.h +++ b/firmware/common/rffc5071.h @@ -31,6 +31,25 @@ extern uint32_t rffc5071_regs_dirty; #define RFFC5071_REG_SET_CLEAN(r) rffc5071_regs_dirty &= ~(1UL<