h1r9: add Si5351A support

This commit is contained in:
Michael Ossmann
2022-09-08 03:33:47 -04:00
committed by Mike Walters
parent 6d48671084
commit 1f73f2fd25
2 changed files with 127 additions and 45 deletions

View File

@ -36,6 +36,7 @@
#include "i2c_lpc.h" #include "i2c_lpc.h"
#include "cpld_jtag.h" #include "cpld_jtag.h"
#include "platform_detect.h" #include "platform_detect.h"
#include "clkin.h"
#include <libopencm3/lpc43xx/cgu.h> #include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/ccu.h> #include <libopencm3/lpc43xx/ccu.h>
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
@ -414,14 +415,26 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
MSx_P2 = (128 * b) % c; MSx_P2 = (128 * b) % c;
MSx_P3 = c; MSx_P3 = c;
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ if (detected_platform() == BOARD_ID_HACKRF1_R9) {
si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1); /*
* On HackRF One r9 all sample clocks are externally derived
* from MS1/CLK1 operating at twice the sample rate.
*/
si5351c_configure_multisynth(&clock_gen, 1, MSx_P1, MSx_P2, MSx_P3, 0);
} else {
/*
* On other platforms the clock generator produces three
* different sample clocks, all derived from multisynth 0.
*/
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter
}
if (streaming) { if (streaming) {
sgpio_cpld_stream_enable(&sgpio_config); sgpio_cpld_stream_enable(&sgpio_config);
@ -482,14 +495,38 @@ bool sample_rate_set(const uint32_t sample_rate_hz)
return false; return false;
} }
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ if (detected_platform() == BOARD_ID_HACKRF1_R9) {
si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); /*
* On HackRF One r9 all sample clocks are externally derived
* from MS1/CLK1 operating at twice the sample rate.
*/
si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 0);
} else {
/*
* On other platforms the clock generator produces three
* different sample clocks, all derived from multisynth 0.
*/
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(&clock_gen, 1, p1, 0, 1, 0); //p1 doesn't matter si5351c_configure_multisynth(
&clock_gen,
1,
p1,
0,
1,
0); //p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(&clock_gen, 2, p1, 0, 1, 0); //p1 doesn't matter si5351c_configure_multisynth(
&clock_gen,
2,
p1,
0,
1,
0); //p1 doesn't matter
}
return true; return true;
} }
@ -596,7 +633,12 @@ void cpu_clock_init(void)
si5351c_configure_pll_multisynth(&clock_gen); si5351c_configure_pll_multisynth(&clock_gen);
/* /*
* Clocks: * Clocks on HackRF One r9:
* CLK0 -> MAX5864/CPLD/SGPIO (sample clocks)
* CLK1 -> RFFC5072/MAX2837
* CLK2 -> External Clock Output/LPC43xx (power down at boot)
*
* Clocks on other platforms:
* CLK0 -> MAX5864/CPLD * CLK0 -> MAX5864/CPLD
* CLK1 -> CPLD * CLK1 -> CPLD
* CLK2 -> SGPIO * CLK2 -> SGPIO
@ -607,22 +649,33 @@ void cpu_clock_init(void)
* CLK7 -> LPC43xx (uses a 12MHz crystal by default) * CLK7 -> LPC43xx (uses a 12MHz crystal by default)
*/ */
/* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ if (detected_platform() == BOARD_ID_HACKRF1_R9) {
si5351c_configure_multisynth( /* MS0/CLK0 is the reference for both RFFC5071 and MAX2837. */
&clock_gen, si5351c_configure_multisynth(
4, &clock_gen,
20 * 128 - 512, 0,
0, 20 * 128 - 512,
1, 0,
0); /* 800/20 = 40MHz */ 1,
/* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ 0); /* 800/20 = 40MHz */
si5351c_configure_multisynth( } else {
&clock_gen, /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */
5, si5351c_configure_multisynth(
20 * 128 - 512, &clock_gen,
0, 4,
1, 20 * 128 - 512,
0); /* 800/20 = 40MHz */ 0,
1,
0); /* 800/20 = 40MHz */
/* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */
si5351c_configure_multisynth(
&clock_gen,
5,
20 * 128 - 512,
0,
1,
0); /* 800/20 = 40MHz */
}
/* MS6/CLK6 is unused. */ /* MS6/CLK6 is unused. */
/* MS7/CLK7 is unused. */ /* MS7/CLK7 is unused. */
@ -766,6 +819,10 @@ void cpu_clock_init(void)
// CCU2_CLK_APLL_CFG = 0; // CCU2_CLK_APLL_CFG = 0;
// CCU2_CLK_SDIO_CFG = 0; // CCU2_CLK_SDIO_CFG = 0;
#endif #endif
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
clkin_detect_init();
}
} }
clock_source_t activate_best_clock_source(void) clock_source_t activate_best_clock_source(void)

View File

@ -191,7 +191,7 @@ void si5351c_configure_clock_control(
const enum pll_sources source) const enum pll_sources source)
{ {
uint8_t pll; uint8_t pll;
uint8_t clk3_ctrl; uint8_t clkout_ctrl;
#ifdef RAD1O #ifdef RAD1O
(void) source; (void) source;
@ -201,31 +201,29 @@ void si5351c_configure_clock_control(
#if (defined JAWBREAKER || defined HACKRF_ONE) #if (defined JAWBREAKER || defined HACKRF_ONE)
if (source == PLL_SOURCE_CLKIN) { if (source == PLL_SOURCE_CLKIN) {
if (detected_platform() < BOARD_ID_HACKRF1_R9) { /* PLLB on CLKIN */
pll = SI5351C_CLK_PLL_SRC_B;
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
/* /*
* HackRF One r9 always uses PLL A on the XTAL input * HackRF One r9 always uses PLL A on the XTAL input
* but externally switches that input to CLKIN. * but externally switches that input to CLKIN.
*/ */
pll = SI5351C_CLK_PLL_SRC_A;
gpio_set(&gpio_h1r9_clkin_en); gpio_set(&gpio_h1r9_clkin_en);
} else {
/* PLLB on CLKIN */
pll = SI5351C_CLK_PLL_SRC_B;
} }
} else { } else {
/* PLLA on XTAL */ /* PLLA on XTAL */
pll = SI5351C_CLK_PLL_SRC_A; pll = SI5351C_CLK_PLL_SRC_A;
if (detected_platform() < BOARD_ID_HACKRF1_R9) { if (detected_platform() == BOARD_ID_HACKRF1_R9) {
gpio_clear(&gpio_h1r9_clkin_en); gpio_clear(&gpio_h1r9_clkin_en);
} }
} }
#endif #endif
if (clkout_enabled) { if (clkout_enabled) {
clk3_ctrl = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | clkout_ctrl = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) |
SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) |
SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA); SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA);
} else { } else {
clk3_ctrl = SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE; clkout_ctrl = SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE;
} }
/* Clock to CPU is deactivated as it is not used and creates noise */ /* Clock to CPU is deactivated as it is not used and creates noise */
@ -241,7 +239,7 @@ void si5351c_configure_clock_control(
SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) |
SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) |
SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA), SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA),
clk3_ctrl, clkout_ctrl,
SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) |
SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) |
SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA) | SI5351C_CLK_INV, SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA) | SI5351C_CLK_INV,
@ -249,18 +247,28 @@ void si5351c_configure_clock_control(
SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) |
SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA), SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA),
SI5351C_CLK_POWERDOWN | SI5351C_CLK_POWERDOWN |
SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ SI5351C_CLK_INT_MODE, /* not connected, but: PLL A int mode */
,
SI5351C_CLK_POWERDOWN | SI5351C_CLK_POWERDOWN |
SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ SI5351C_CLK_INT_MODE /* not connected, but: PLL B int mode */
}; };
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
data[1] = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC_A |
SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) |
SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA);
data[2] = SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC_A |
SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) |
SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA);
data[3] = clkout_ctrl;
data[4] = SI5351C_CLK_POWERDOWN;
data[5] = SI5351C_CLK_POWERDOWN;
data[6] = SI5351C_CLK_POWERDOWN;
}
si5351c_write(drv, data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
#define SI5351C_CLK_ENABLE(x) (0 << x) #define SI5351C_CLK_ENABLE(x) (0 << x)
#define SI5351C_CLK_DISABLE(x) (1 << x) #define SI5351C_CLK_DISABLE(x) (1 << x)
#define SI5351C_REG_OUTPUT_EN (3) #define SI5351C_REG_OUTPUT_EN (3)
#define SI5351C_REG_CLK3_CTRL (19)
void si5351c_enable_clock_outputs(si5351c_driver_t* const drv) void si5351c_enable_clock_outputs(si5351c_driver_t* const drv)
{ {
@ -270,8 +278,19 @@ void si5351c_enable_clock_outputs(si5351c_driver_t* const drv)
uint8_t value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) | uint8_t value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) |
SI5351C_CLK_ENABLE(2) | SI5351C_CLK_ENABLE(4) | SI5351C_CLK_ENABLE(5) | SI5351C_CLK_ENABLE(2) | SI5351C_CLK_ENABLE(4) | SI5351C_CLK_ENABLE(5) |
SI5351C_CLK_DISABLE(6) | SI5351C_CLK_DISABLE(7); SI5351C_CLK_DISABLE(6) | SI5351C_CLK_DISABLE(7);
uint8_t clkout = 3;
value |= (clkout_enabled) ? SI5351C_CLK_ENABLE(3) : SI5351C_CLK_DISABLE(3); /* HackRF One r9 has only three clock generator outputs. */
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
clkout = 2;
value = SI5351C_CLK_ENABLE(0) | SI5351C_CLK_ENABLE(1) |
SI5351C_CLK_DISABLE(3) | SI5351C_CLK_DISABLE(4) |
SI5351C_CLK_DISABLE(5) | SI5351C_CLK_DISABLE(6) |
SI5351C_CLK_DISABLE(7);
}
value |= (clkout_enabled) ? SI5351C_CLK_ENABLE(clkout) :
SI5351C_CLK_DISABLE(clkout);
uint8_t data[] = {SI5351C_REG_OUTPUT_EN, value}; uint8_t data[] = {SI5351C_REG_OUTPUT_EN, value};
si5351c_write(drv, data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
@ -325,8 +344,14 @@ void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable)
{ {
clkout_enabled = (enable > 0); clkout_enabled = (enable > 0);
//FIXME this should be somewhere else
uint8_t clkout = 3;
/* HackRF One r9 has only three clock generator outputs. */
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
clkout = 2;
}
/* Configure clock to 10MHz */ /* Configure clock to 10MHz */
si5351c_configure_multisynth(drv, 3, 80 * 128 - 512, 0, 1, 0); si5351c_configure_multisynth(drv, clkout, 80 * 128 - 512, 0, 1, 0);
si5351c_configure_clock_control(drv, active_clock_source); si5351c_configure_clock_control(drv, active_clock_source);
si5351c_enable_clock_outputs(drv); si5351c_enable_clock_outputs(drv);