h1r9: add Si5351A support
This commit is contained in:

committed by
Mike Walters

parent
6d48671084
commit
1f73f2fd25
@ -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,6 +415,17 @@ 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;
|
||||||
|
|
||||||
|
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
|
||||||
|
/*
|
||||||
|
* 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). */
|
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
|
||||||
si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
|
si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
|
||||||
|
|
||||||
@ -422,6 +434,7 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
|
|||||||
|
|
||||||
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
|
||||||
|
/*
|
||||||
|
* 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). */
|
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
|
||||||
si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1);
|
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,6 +649,16 @@ void cpu_clock_init(void)
|
|||||||
* CLK7 -> LPC43xx (uses a 12MHz crystal by default)
|
* CLK7 -> LPC43xx (uses a 12MHz crystal by default)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
|
||||||
|
/* MS0/CLK0 is the reference for both RFFC5071 and MAX2837. */
|
||||||
|
si5351c_configure_multisynth(
|
||||||
|
&clock_gen,
|
||||||
|
0,
|
||||||
|
20 * 128 - 512,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0); /* 800/20 = 40MHz */
|
||||||
|
} else {
|
||||||
/* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */
|
/* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */
|
||||||
si5351c_configure_multisynth(
|
si5351c_configure_multisynth(
|
||||||
&clock_gen,
|
&clock_gen,
|
||||||
@ -623,6 +675,7 @@ void cpu_clock_init(void)
|
|||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
0); /* 800/20 = 40MHz */
|
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)
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user