Unverified Commit 1d9c95c1 authored by Olivier Moysan's avatar Olivier Moysan Committed by Mark Brown
Browse files

ASoC: stm32: sai: manage identification registers



Add support of identification registers in STM32 SAI.

Signed-off-by: default avatarOlivier Moysan <olivier.moysan@st.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 970c43d1
Loading
Loading
Loading
Loading
+39 −5
Original line number Diff line number Diff line
@@ -30,13 +30,20 @@
#include "stm32_sai.h"

static const struct stm32_sai_conf stm32_sai_conf_f4 = {
	.version = SAI_STM32F4,
	.has_spdif = false,
	.version = STM_SAI_STM32F4,
	.fifo_size = 8,
	.has_spdif_pdm = false,
};

/*
 * Default settings for stm32 H7 socs and next.
 * These default settings will be overridden if the soc provides
 * support of hardware configuration registers.
 */
static const struct stm32_sai_conf stm32_sai_conf_h7 = {
	.version = SAI_STM32H7,
	.has_spdif = true,
	.version = STM_SAI_STM32H7,
	.fifo_size = 8,
	.has_spdif_pdm = true,
};

static const struct of_device_id stm32_sai_ids[] = {
@@ -157,6 +164,8 @@ static int stm32_sai_probe(struct platform_device *pdev)
	struct reset_control *rst;
	struct resource *res;
	const struct of_device_id *of_id;
	u32 val;
	int ret;

	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
	if (!sai)
@@ -169,7 +178,8 @@ static int stm32_sai_probe(struct platform_device *pdev)

	of_id = of_match_device(stm32_sai_ids, &pdev->dev);
	if (of_id)
		sai->conf = (struct stm32_sai_conf *)of_id->data;
		memcpy(&sai->conf, (const struct stm32_sai_conf *)of_id->data,
		       sizeof(struct stm32_sai_conf));
	else
		return -EINVAL;

@@ -208,6 +218,30 @@ static int stm32_sai_probe(struct platform_device *pdev)
		reset_control_deassert(rst);
	}

	/* Enable peripheral clock to allow register access */
	ret = clk_prepare_enable(sai->pclk);
	if (ret) {
		dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
		return ret;
	}

	val = FIELD_GET(SAI_IDR_ID_MASK,
			readl_relaxed(sai->base + STM_SAI_IDR));
	if (val == SAI_IPIDR_NUMBER) {
		val = readl_relaxed(sai->base + STM_SAI_HWCFGR);
		sai->conf.fifo_size = FIELD_GET(SAI_HWCFGR_FIFO_SIZE, val);
		sai->conf.has_spdif_pdm = !!FIELD_GET(SAI_HWCFGR_SPDIF_PDM,
						      val);

		val = readl_relaxed(sai->base + STM_SAI_VERR);
		sai->conf.version = val;

		dev_dbg(&pdev->dev, "SAI version: %lu.%lu registered\n",
			FIELD_GET(SAI_VERR_MAJ_MASK, val),
			FIELD_GET(SAI_VERR_MIN_MASK, val));
	}
	clk_disable_unprepare(sai->pclk);

	sai->pdev = pdev;
	sai->set_sync = &stm32_sai_set_sync;
	platform_set_drvdata(pdev, sai);
+41 −13
Original line number Diff line number Diff line
@@ -37,6 +37,12 @@
#define STM_SAI_PDMCR_REGX	0x40
#define STM_SAI_PDMLY_REGX	0x44

/* Hardware configuration registers */
#define STM_SAI_HWCFGR		0x3F0
#define STM_SAI_VERR		0x3F4
#define STM_SAI_IDR		0x3F8
#define STM_SAI_SIDR		0x3FC

/******************** Bit definition for SAI_GCR register *******************/
#define SAI_GCR_SYNCIN_SHIFT	0
#define SAI_GCR_SYNCIN_WDTH	2
@@ -82,7 +88,7 @@
#define SAI_XCR1_NODIV		BIT(SAI_XCR1_NODIV_SHIFT)

#define SAI_XCR1_MCKDIV_SHIFT	20
#define SAI_XCR1_MCKDIV_WIDTH(x)	(((x) == SAI_STM32F4) ? 4 : 6)
#define SAI_XCR1_MCKDIV_WIDTH(x)	(((x) == STM_SAI_STM32F4) ? 4 : 6)
#define SAI_XCR1_MCKDIV_MASK(x) GENMASK((SAI_XCR1_MCKDIV_SHIFT + (x) - 1),\
				SAI_XCR1_MCKDIV_SHIFT)
#define SAI_XCR1_MCKDIV_SET(x)	((x) << SAI_XCR1_MCKDIV_SHIFT)
@@ -234,8 +240,33 @@
#define SAI_PDMDLY_4R_MASK	GENMASK(30, SAI_PDMDLY_4R_SHIFT)
#define SAI_PDMDLY_4R_WIDTH	3

#define STM_SAI_IS_F4(ip)	((ip)->conf->version == SAI_STM32F4)
#define STM_SAI_IS_H7(ip)	((ip)->conf->version == SAI_STM32H7)
/* Registers below apply to SAI version 2.1 and more */

/* Bit definition for SAI_HWCFGR register */
#define SAI_HWCFGR_FIFO_SIZE	GENMASK(7, 0)
#define SAI_HWCFGR_SPDIF_PDM	GENMASK(11, 8)
#define SAI_HWCFGR_REGOUT	GENMASK(19, 12)

/* Bit definition for SAI_VERR register */
#define SAI_VERR_MIN_MASK	GENMASK(3, 0)
#define SAI_VERR_MAJ_MASK	GENMASK(7, 4)

/* Bit definition for SAI_IDR register */
#define SAI_IDR_ID_MASK		GENMASK(31, 0)

/* Bit definition for SAI_SIDR register */
#define SAI_SIDR_ID_MASK	GENMASK(31, 0)

#define SAI_IPIDR_NUMBER	0x00130031

/* SAI version numbers are 1.x for F4. Major version number set to 1 for F4 */
#define STM_SAI_STM32F4		BIT(4)
/* Dummy version number for H7 socs and next */
#define STM_SAI_STM32H7		0x0

#define STM_SAI_IS_F4(ip)	((ip)->conf.version == STM_SAI_STM32F4)
#define STM_SAI_HAS_SPDIF_PDM(ip)\
				((ip)->pdata->conf.has_spdif_pdm)

enum stm32_sai_syncout {
	STM_SAI_SYNC_OUT_NONE,
@@ -243,19 +274,16 @@ enum stm32_sai_syncout {
	STM_SAI_SYNC_OUT_B,
};

enum stm32_sai_version {
	SAI_STM32F4,
	SAI_STM32H7
};

/**
 * struct stm32_sai_conf - SAI configuration
 * @version: SAI version
 * @has_spdif: SAI S/PDIF support flag
 * @fifo_size: SAI fifo size as words number
 * @has_spdif_pdm: SAI S/PDIF and PDM features support flag
 */
struct stm32_sai_conf {
	int version;
	bool has_spdif;
	u32 version;
	u32 fifo_size;
	bool has_spdif_pdm;
};

/**
@@ -265,7 +293,7 @@ struct stm32_sai_conf {
 * @pclk: SAI bus clock
 * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
 * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
 * @version: SOC version
 * @conf: SAI hardware capabitilites
 * @irq: SAI interrupt line
 * @set_sync: pointer to synchro mode configuration callback
 * @gcr: SAI Global Configuration Register
@@ -276,7 +304,7 @@ struct stm32_sai_data {
	struct clk *pclk;
	struct clk *clk_x8k;
	struct clk *clk_x11k;
	struct stm32_sai_conf *conf;
	struct stm32_sai_conf conf;
	int irq;
	int (*set_sync)(struct stm32_sai_data *sai,
			struct device_node *np_provider, int synco, int synci);
+8 −6
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@
#define SAI_DATASIZE_24		0x6
#define SAI_DATASIZE_32		0x7

#define STM_SAI_FIFO_SIZE	8
#define STM_SAI_DAI_NAME_SIZE	15

#define STM_SAI_IS_PLAYBACK(ip)	((ip)->dir == SNDRV_PCM_STREAM_PLAYBACK)
@@ -63,7 +62,8 @@
#define SAI_SYNC_EXTERNAL	0x2

#define STM_SAI_PROTOCOL_IS_SPDIF(ip)	((ip)->spdif)
#define STM_SAI_HAS_SPDIF(x)	((x)->pdata->conf->has_spdif)
#define STM_SAI_HAS_SPDIF(x)	((x)->pdata->conf.has_spdif_pdm)
#define STM_SAI_HAS_PDM(x)	((x)->pdata->conf.has_spdif_pdm)
#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))

#define SAI_IEC60958_BLOCK_FRAMES	192
@@ -274,7 +274,7 @@ static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai,
				 unsigned long input_rate,
				 unsigned long output_rate)
{
	int version = sai->pdata->conf->version;
	int version = sai->pdata->conf.version;
	int div;

	div = DIV_ROUND_CLOSEST(input_rate, output_rate);
@@ -295,7 +295,7 @@ static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai,
static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
				 unsigned int div)
{
	int version = sai->pdata->conf->version;
	int version = sai->pdata->conf.version;
	int ret, cr1, mask;

	if (div > SAI_XCR1_MCKDIV_MAX(version)) {
@@ -1148,6 +1148,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
	 * constraints).
	 */
	sai->dma_params.maxburst = 4;
	if (sai->pdata->conf.fifo_size < 8)
		sai->dma_params.maxburst = 1;
	/* Buswidth will be set by framework at runtime */
	sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;

@@ -1315,8 +1317,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
	sai->phys_addr = res->start;

	sai->regmap_config = &stm32_sai_sub_regmap_config_f4;
	/* Note: PDM registers not available for H7 sub-block B */
	if (STM_SAI_IS_H7(sai->pdata) && STM_SAI_IS_SUB_A(sai))
	/* Note: PDM registers not available for sub-block B */
	if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai))
		sai->regmap_config = &stm32_sai_sub_regmap_config_h7;

	sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck",