Commit 7d447a1d authored by Alain Volmat's avatar Alain Volmat Committed by Benjamin Cabé
Browse files

drivers: clock: stm32: add PLLSAI2 support (common + L4)



Add stm32 common clock handling for the SAI2 PLL.

Signed-off-by: default avatarAlain Volmat <alain.volmat@foss.st.com>
parent 0abbc2f0
Loading
Loading
Loading
Loading
+72 −2
Original line number Diff line number Diff line
@@ -249,6 +249,34 @@ int enabled_clock(uint32_t src_clk)
		}
		break;
#endif /* STM32_SRC_PLLSAI1_R */
#if defined(STM32_SRC_PLLSAI2_P)
	case STM32_SRC_PLLSAI2_P:
		if (!IS_ENABLED(STM32_PLLSAI2_P_ENABLED)) {
			r = -ENOTSUP;
		}
		break;
#endif /* STM32_SRC_PLLSAI2_P */
#if defined(STM32_SRC_PLLSAI2_Q)
	case STM32_SRC_PLLSAI2_Q:
		if (!IS_ENABLED(STM32_PLLSAI2_Q_ENABLED)) {
			r = -ENOTSUP;
		}
		break;
#endif /* STM32_SRC_PLLSAI2_Q */
#if defined(STM32_SRC_PLLSAI2_R)
	case STM32_SRC_PLLSAI2_R:
		if (!IS_ENABLED(STM32_PLLSAI2_R_ENABLED)) {
			r = -ENOTSUP;
		}
		break;
#endif /* STM32_SRC_PLLSAI2_R */
#if defined(STM32_SRC_PLLSAI2_DIVR)
	case STM32_SRC_PLLSAI2_DIVR:
		if (!IS_ENABLED(STM32_PLLSAI2_R_ENABLED)) {
			r = -ENOTSUP;
		}
		break;
#endif /* STM32_SRC_PLLSAI2_DIVR */
#if defined(STM32_SRC_PLL2CLK)
	case STM32_SRC_PLL2CLK:
		if (!IS_ENABLED(STM32_PLL2_ENABLED)) {
@@ -486,8 +514,40 @@ static int stm32_clock_control_get_subsys_rate(const struct device *clock,
					      STM32_PLLSAI1_R_DIVISOR);
		break;
#endif /* STM32_SRC_PLLSAI1_R */

/* PLLSAI2x not supported yet */
#if defined(STM32_SRC_PLLSAI2_P) & STM32_PLLSAI2_P_ENABLED
	case STM32_SRC_PLLSAI2_P:
		*rate = get_pll_div_frequency(get_pllsai2src_frequency(),
					      STM32_PLLSAI2_M_DIVISOR,
					      STM32_PLLSAI2_N_MULTIPLIER,
					      STM32_PLLSAI2_P_DIVISOR);
		break;
#endif /* STM32_SRC_PLLSAI2_P */
#if defined(STM32_SRC_PLLSAI2_Q) & STM32_PLLSAI2_Q_ENABLED
	case STM32_SRC_PLLSAI2_Q:
		*rate = get_pll_div_frequency(get_pllsai2src_frequency(),
					      STM32_PLLSAI2_M_DIVISOR,
					      STM32_PLLSAI2_N_MULTIPLIER,
					      STM32_PLLSAI2_Q_DIVISOR);
		break;
#endif /* STM32_SRC_PLLSAI2_Q */
#if defined(STM32_SRC_PLLSAI2_R) & STM32_PLLSAI2_R_ENABLED
	case STM32_SRC_PLLSAI2_R:
		*rate = get_pll_div_frequency(get_pllsai2src_frequency(),
					      STM32_PLLSAI2_M_DIVISOR,
					      STM32_PLLSAI2_N_MULTIPLIER,
					      STM32_PLLSAI2_R_DIVISOR);
		break;
#endif /* STM32_SRC_PLLSAI2_R */
#if defined(STM32_SRC_PLLSAI2_DIVR) & STM32_PLLSAI2_R_ENABLED & STM32_PLLSAI2_DIVR_ENABLED \
	& defined(STM32_PLLSAI2_DIVR_DIVISOR)
	case STM32_SRC_PLLSAI2_DIVR:
		*rate = get_pll_div_frequency(get_pllsai2src_frequency(),
					      STM32_PLLSAI2_M_DIVISOR,
					      STM32_PLLSAI2_N_MULTIPLIER,
					      STM32_PLLSAI2_R_DIVISOR);
		*rate /= STM32_PLLSAI2_DIVR_DIVISOR;
		break;
#endif /* STM32_SRC_PLLSAI2_DIVR */
#if defined(STM32_SRC_LSE)
	case STM32_SRC_LSE:
		*rate = STM32_LSE_FREQ;
@@ -678,6 +738,16 @@ static void set_up_plls(void)
		/* Wait for PLL ready */
	}
#endif /* STM32_PLLSAI1_ENABLED */

#if defined(STM32_PLLSAI2_ENABLED)
	config_pllsai2();

	/* Enable PLL */
	LL_RCC_PLLSAI2_Enable();
	while (LL_RCC_PLLSAI2_IsReady() != 1U) {
		/* Wait for PLL ready */
	}
#endif /* STM32_PLLSAI2_ENABLED */
}

static void set_up_fixed_clock_sources(void)
+23 −0
Original line number Diff line number Diff line
@@ -58,6 +58,25 @@
#define z_pllsai1_r(v) LL_RCC_PLLSAI1R_DIV_ ## v
#define pllsai1r(v) z_pllsai1_r(v)

#if defined(RCC_PLLSAI2M_DIV_1_16_SUPPORT)
#define z_pllsai2_m(v) LL_RCC_PLLSAI2M_DIV_ ## v
#else
#define z_pllsai2_m(v) LL_RCC_PLLM_DIV_ ## v
#endif
#define pllsai2m(v) z_pllsai2_m(v)

#define z_pllsai2_p(v) LL_RCC_PLLSAI2P_DIV_ ## v
#define pllsai2p(v) z_pllsai2_p(v)

#define z_pllsai2_q(v) LL_RCC_PLLSAI2Q_DIV_ ## v
#define pllsai2q(v) z_pllsai2_q(v)

#define z_pllsai2_r(v) LL_RCC_PLLSAI2R_DIV_ ## v
#define pllsai2r(v) z_pllsai2_r(v)

#define z_pllsai2_divr(v) LL_RCC_PLLSAI2DIVR_DIV_ ## v
#define pllsai2divr(v) z_pllsai2_divr(v)

#ifdef __cplusplus
extern "C" {
#endif
@@ -77,6 +96,10 @@ void config_plli2s(void);
uint32_t get_pllsai1src_frequency(void);
void config_pllsai1(void);
#endif
#if defined(STM32_PLLSAI2_ENABLED)
uint32_t get_pllsai2src_frequency(void);
void config_pllsai2(void);
#endif
void config_enable_default_clocks(void);
void config_regulator_voltage(uint32_t hclk_freq);
int enabled_clock(uint32_t src_clk);
+108 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
#include <zephyr/sys/time_units.h>
#include "clock_stm32_ll_common.h"

#if defined(STM32_PLL_ENABLED) || defined(STM32_PLLSAI1_ENABLED)
#if defined(STM32_PLL_ENABLED) || defined(STM32_PLLSAI1_ENABLED) || defined(STM32_PLLSAI2_ENABLED)

#if defined(LL_RCC_MSIRANGESEL_RUN)
#define CALC_RUN_MSI_FREQ(range) __LL_RCC_CALC_MSI_FREQ(LL_RCC_MSIRANGESEL_RUN, \
@@ -179,6 +179,113 @@ void config_pllsai1(void)

#endif /* STM32_PLLSAI1_ENABLED */

#if defined(STM32_PLLSAI2_ENABLED)
#if defined(RCC_PLLSAI2_SUPPORT)

/**
 * @brief Return PLLSAI2 source
 */
__unused
static uint32_t get_pllsai2_source(void)
{
	/* Configure PLL source */
	if (IS_ENABLED(STM32_PLLSAI2_SRC_HSI)) {
		return LL_RCC_PLLSOURCE_HSI;
	} else if (IS_ENABLED(STM32_PLLSAI2_SRC_HSE)) {
		return LL_RCC_PLLSOURCE_HSE;
	} else if (IS_ENABLED(STM32_PLLSAI2_SRC_MSI)) {
		return LL_RCC_PLLSOURCE_MSI;
	}

	__ASSERT(0, "Invalid source");
	return 0;
}

/**
 * @brief Get the PLLSAI2 source frequency
 */
__unused
uint32_t get_pllsai2src_frequency(void)
{
	if (IS_ENABLED(STM32_PLLSAI2_SRC_HSI)) {
		return STM32_HSI_FREQ;
	} else if (IS_ENABLED(STM32_PLLSAI2_SRC_HSE)) {
		return STM32_HSE_FREQ;
#if defined(STM32_MSI_ENABLED)
	} else if (IS_ENABLED(STM32_PLLSAI2_SRC_MSI)) {
		return CALC_RUN_MSI_FREQ(STM32_MSI_RANGE);
#endif
	}

	__ASSERT(0, "Invalid source");
	return 0;
}

/**
 * @brief Set up PLLSAI2 configuration
 */
__unused
void config_pllsai2(void)
{
#ifndef RCC_PLLSAI2M_DIV_1_16_SUPPORT
	/*
	 * On some L4 series, there is no dedicated M_DIVISOR for PLLSAIs
	 * and it is shared with PLL and other PLLSAIs. Ensure that if they
	 * exist, they have the same value
	 */
#if defined(STM32_PLL_M_DIVISOR) && (STM32_PLL_M_DIVISOR != STM32_PLLSAI2_M_DIVISOR)
#error "PLLSAI2 M divisor must have same value as PLL M divisor"
#elif defined(STM32_PLLSAI1_M_DIVISOR) && (STM32_PLLSAI1_M_DIVISOR != STM32_PLLSAI2_M_DIVISOR)
#error "PLLSAI2 M divisor must have same value as PLLSAI1 M divisor"
#endif
#endif
#if STM32_PLLSAI2_P_ENABLED
	LL_RCC_PLLSAI2_ConfigDomain_SAI(get_pllsai2_source(),
					pllsai2m(STM32_PLLSAI2_M_DIVISOR),
					STM32_PLLSAI2_N_MULTIPLIER,
					pllsai2p(STM32_PLLSAI2_P_DIVISOR));

	LL_RCC_PLLSAI2_EnableDomain_SAI();
#endif /* STM32_PLLSAI2_P_ENABLED */

#if STM32_PLLSAI2_Q_ENABLED && defined(RCC_PLLSAI2Q_DIV_SUPPORT)
	LL_RCC_PLLSAI2_ConfigDomain_DSI(get_pllsai2_source(),
					pllsai2m(STM32_PLLSAI2_M_DIVISOR),
					STM32_PLLSAI2_N_MULTIPLIER,
					pllsai2q(STM32_PLLSAI2_Q_DIVISOR));

	LL_RCC_PLLSAI2_EnableDomain_DSI();
#endif /* STM32_PLLSAI2_Q_ENABLED */

#if STM32_PLLSAI2_R_ENABLED
#if defined(RCC_CCIPR2_PLLSAI2DIVR)
#if STM32_PLLSAI2_DIVR_ENABLED
	LL_RCC_PLLSAI2_ConfigDomain_LTDC(get_pllsai2_source(),
					 pllsai2m(STM32_PLLSAI2_M_DIVISOR),
					 STM32_PLLSAI2_N_MULTIPLIER,
					 pllsai2r(STM32_PLLSAI2_R_DIVISOR),
					 pllsai2divr(STM32_PLLSAI2_DIVR_DIVISOR));

	LL_RCC_PLLSAI2_EnableDomain_LTDC();
#else
#error "On PLLSAI2, div_divr device-tree properties is needed"
#endif
#else
	LL_RCC_PLLSAI2_ConfigDomain_ADC(get_pllsai2_source(),
					pllsai2m(STM32_PLLSAI2_M_DIVISOR),
					STM32_PLLSAI2_N_MULTIPLIER,
					pllsai2r(STM32_PLLSAI2_R_DIVISOR));

	LL_RCC_PLLSAI2_EnableDomain_ADC();
#endif
#endif /* STM32_PLLSAI2_R_ENABLED */
}
#else
#error "PLLSAI2 is not available in this platform"
#endif

#endif /* STM32_PLLSAI2_ENABLED */

/**
 * @brief Activate default clocks
 */
+41 −1
Original line number Diff line number Diff line
@@ -230,6 +230,20 @@
#define STM32_PLLSAI1_R_DIVISOR		DT_PROP_OR(DT_NODELABEL(pllsai1), div_r, 1)
#endif

#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pllsai2), st_stm32l4_pllsai_clock, okay)
#define STM32_PLLSAI2_ENABLED	1
#define STM32_PLLSAI2_M_DIVISOR		DT_PROP(DT_NODELABEL(pllsai2), div_m)
#define STM32_PLLSAI2_N_MULTIPLIER	DT_PROP(DT_NODELABEL(pllsai2), mul_n)
#define STM32_PLLSAI2_P_ENABLED		DT_NODE_HAS_PROP(DT_NODELABEL(pllsai2), div_p)
#define STM32_PLLSAI2_P_DIVISOR		DT_PROP_OR(DT_NODELABEL(pllsai2), div_p, 1)
#define STM32_PLLSAI2_Q_ENABLED		DT_NODE_HAS_PROP(DT_NODELABEL(pllsai2), div_q)
#define STM32_PLLSAI2_Q_DIVISOR		DT_PROP_OR(DT_NODELABEL(pllsai2), div_q, 1)
#define STM32_PLLSAI2_R_ENABLED		DT_NODE_HAS_PROP(DT_NODELABEL(pllsai2), div_r)
#define STM32_PLLSAI2_R_DIVISOR		DT_PROP_OR(DT_NODELABEL(pllsai2), div_r, 1)
#define STM32_PLLSAI2_DIVR_ENABLED	DT_NODE_HAS_PROP(DT_NODELABEL(pllsai2), div_divr)
#define STM32_PLLSAI2_DIVR_DIVISOR	DT_PROP_OR(DT_NODELABEL(pllsai2), div_divr, 1)
#endif

#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32u5_pll_clock, okay) || \
	DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32h7_pll_clock, okay) || \
	DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32h7rs_pll_clock, okay) || \
@@ -435,12 +449,38 @@

#endif

/* On STM32L4 series - PLL / PLLSAI1 shared same source */
/** PLLSAI2 clock source */
#if DT_NODE_HAS_STATUS(DT_NODELABEL(pllsai2), okay) && \
	DT_NODE_HAS_PROP(DT_NODELABEL(pllsai2), clocks)
#define DT_PLLSAI2_CLOCKS_CTRL	DT_CLOCKS_CTLR(DT_NODELABEL(pllsai2))
#if DT_SAME_NODE(DT_PLLSAI2_CLOCKS_CTRL, DT_NODELABEL(clk_msi))
#define STM32_PLLSAI2_SRC_MSI	1
#endif
#if DT_SAME_NODE(DT_PLLSAI2_CLOCKS_CTRL, DT_NODELABEL(clk_hsi))
#define STM32_PLLSAI2_SRC_HSI	1
#endif
#if DT_SAME_NODE(DT_PLLSAI2_CLOCKS_CTRL, DT_NODELABEL(clk_hse))
#define STM32_PLLSAI2_SRC_HSE	1
#endif

#endif

/* On STM32L4 series - PLL / PLLSAI1 and PLLSAI2 shared same source */
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32l4_pll_clock, okay) && \
	DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pllsai1), st_stm32l4_pllsai_clock, okay) && \
	!DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_PLLSAI1_CLOCKS_CTRL)
#error "On STM32L4 series, PLL / PLLSAI1 must have the same source"
#endif
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32l4_pll_clock, okay) && \
	DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pllsai2), st_stm32l4_pllsai_clock, okay) && \
	!DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_PLLSAI2_CLOCKS_CTRL)
#error "On STM32L4 series, PLL / PLLSAI2 must have the same source"
#endif
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pllsai1), st_stm32l4_pllsai_clock, okay) && \
	DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pllsai2), st_stm32l4_pllsai_clock, okay) && \
	!DT_SAME_NODE(DT_PLLSAI1_CLOCKS_CTRL, DT_PLLSAI2_CLOCKS_CTRL)
#error "On STM32L4 series, PLLSAI1 / PLLSAI2 must have the same source"
#endif

/** Fixed clocks related symbols */

+5 −0
Original line number Diff line number Diff line
@@ -39,6 +39,11 @@
#define STM32_SRC_PLLSAI1_P	(STM32_SRC_PLL_R + 1)
#define STM32_SRC_PLLSAI1_Q	(STM32_SRC_PLLSAI1_P + 1)
#define STM32_SRC_PLLSAI1_R	(STM32_SRC_PLLSAI1_Q + 1)
/* PLLSAI2 clocks */
#define STM32_SRC_PLLSAI2_P	(STM32_SRC_PLLSAI1_R + 1)
#define STM32_SRC_PLLSAI2_Q	(STM32_SRC_PLLSAI2_P + 1)
#define STM32_SRC_PLLSAI2_R	(STM32_SRC_PLLSAI2_Q + 1)
#define STM32_SRC_PLLSAI2_DIVR	(STM32_SRC_PLLSAI2_R + 1)

/** @brief RCC_CCIPR register offset */
#define CCIPR_REG		0x88