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

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
...@@ -30,13 +30,20 @@ ...@@ -30,13 +30,20 @@
#include "stm32_sai.h" #include "stm32_sai.h"
static const struct stm32_sai_conf stm32_sai_conf_f4 = { static const struct stm32_sai_conf stm32_sai_conf_f4 = {
.version = SAI_STM32F4, .version = STM_SAI_STM32F4,
.has_spdif = false, .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 = { static const struct stm32_sai_conf stm32_sai_conf_h7 = {
.version = SAI_STM32H7, .version = STM_SAI_STM32H7,
.has_spdif = true, .fifo_size = 8,
.has_spdif_pdm = true,
}; };
static const struct of_device_id stm32_sai_ids[] = { static const struct of_device_id stm32_sai_ids[] = {
...@@ -157,6 +164,8 @@ static int stm32_sai_probe(struct platform_device *pdev) ...@@ -157,6 +164,8 @@ static int stm32_sai_probe(struct platform_device *pdev)
struct reset_control *rst; struct reset_control *rst;
struct resource *res; struct resource *res;
const struct of_device_id *of_id; const struct of_device_id *of_id;
u32 val;
int ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai) if (!sai)
...@@ -169,7 +178,8 @@ static int stm32_sai_probe(struct platform_device *pdev) ...@@ -169,7 +178,8 @@ static int stm32_sai_probe(struct platform_device *pdev)
of_id = of_match_device(stm32_sai_ids, &pdev->dev); of_id = of_match_device(stm32_sai_ids, &pdev->dev);
if (of_id) 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 else
return -EINVAL; return -EINVAL;
...@@ -208,6 +218,30 @@ static int stm32_sai_probe(struct platform_device *pdev) ...@@ -208,6 +218,30 @@ static int stm32_sai_probe(struct platform_device *pdev)
reset_control_deassert(rst); 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->pdev = pdev;
sai->set_sync = &stm32_sai_set_sync; sai->set_sync = &stm32_sai_set_sync;
platform_set_drvdata(pdev, sai); platform_set_drvdata(pdev, sai);
......
...@@ -37,6 +37,12 @@ ...@@ -37,6 +37,12 @@
#define STM_SAI_PDMCR_REGX 0x40 #define STM_SAI_PDMCR_REGX 0x40
#define STM_SAI_PDMLY_REGX 0x44 #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 *******************/ /******************** Bit definition for SAI_GCR register *******************/
#define SAI_GCR_SYNCIN_SHIFT 0 #define SAI_GCR_SYNCIN_SHIFT 0
#define SAI_GCR_SYNCIN_WDTH 2 #define SAI_GCR_SYNCIN_WDTH 2
...@@ -82,7 +88,7 @@ ...@@ -82,7 +88,7 @@
#define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT) #define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT)
#define SAI_XCR1_MCKDIV_SHIFT 20 #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),\ #define SAI_XCR1_MCKDIV_MASK(x) GENMASK((SAI_XCR1_MCKDIV_SHIFT + (x) - 1),\
SAI_XCR1_MCKDIV_SHIFT) SAI_XCR1_MCKDIV_SHIFT)
#define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT) #define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT)
...@@ -234,8 +240,33 @@ ...@@ -234,8 +240,33 @@
#define SAI_PDMDLY_4R_MASK GENMASK(30, SAI_PDMDLY_4R_SHIFT) #define SAI_PDMDLY_4R_MASK GENMASK(30, SAI_PDMDLY_4R_SHIFT)
#define SAI_PDMDLY_4R_WIDTH 3 #define SAI_PDMDLY_4R_WIDTH 3
#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4) /* Registers below apply to SAI version 2.1 and more */
#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7)
/* 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 { enum stm32_sai_syncout {
STM_SAI_SYNC_OUT_NONE, STM_SAI_SYNC_OUT_NONE,
...@@ -243,19 +274,16 @@ enum stm32_sai_syncout { ...@@ -243,19 +274,16 @@ enum stm32_sai_syncout {
STM_SAI_SYNC_OUT_B, STM_SAI_SYNC_OUT_B,
}; };
enum stm32_sai_version {
SAI_STM32F4,
SAI_STM32H7
};
/** /**
* struct stm32_sai_conf - SAI configuration * struct stm32_sai_conf - SAI configuration
* @version: SAI version * @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 { struct stm32_sai_conf {
int version; u32 version;
bool has_spdif; u32 fifo_size;
bool has_spdif_pdm;
}; };
/** /**
...@@ -265,7 +293,7 @@ struct stm32_sai_conf { ...@@ -265,7 +293,7 @@ struct stm32_sai_conf {
* @pclk: SAI bus clock * @pclk: SAI bus clock
* @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
* @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
* @version: SOC version * @conf: SAI hardware capabitilites
* @irq: SAI interrupt line * @irq: SAI interrupt line
* @set_sync: pointer to synchro mode configuration callback * @set_sync: pointer to synchro mode configuration callback
* @gcr: SAI Global Configuration Register * @gcr: SAI Global Configuration Register
...@@ -276,7 +304,7 @@ struct stm32_sai_data { ...@@ -276,7 +304,7 @@ struct stm32_sai_data {
struct clk *pclk; struct clk *pclk;
struct clk *clk_x8k; struct clk *clk_x8k;
struct clk *clk_x11k; struct clk *clk_x11k;
struct stm32_sai_conf *conf; struct stm32_sai_conf conf;
int irq; int irq;
int (*set_sync)(struct stm32_sai_data *sai, int (*set_sync)(struct stm32_sai_data *sai,
struct device_node *np_provider, int synco, int synci); struct device_node *np_provider, int synco, int synci);
......
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
#define SAI_DATASIZE_24 0x6 #define SAI_DATASIZE_24 0x6
#define SAI_DATASIZE_32 0x7 #define SAI_DATASIZE_32 0x7
#define STM_SAI_FIFO_SIZE 8
#define STM_SAI_DAI_NAME_SIZE 15 #define STM_SAI_DAI_NAME_SIZE 15
#define STM_SAI_IS_PLAYBACK(ip) ((ip)->dir == SNDRV_PCM_STREAM_PLAYBACK) #define STM_SAI_IS_PLAYBACK(ip) ((ip)->dir == SNDRV_PCM_STREAM_PLAYBACK)
...@@ -63,7 +62,8 @@ ...@@ -63,7 +62,8 @@
#define SAI_SYNC_EXTERNAL 0x2 #define SAI_SYNC_EXTERNAL 0x2
#define STM_SAI_PROTOCOL_IS_SPDIF(ip) ((ip)->spdif) #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 STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
#define SAI_IEC60958_BLOCK_FRAMES 192 #define SAI_IEC60958_BLOCK_FRAMES 192
...@@ -274,7 +274,7 @@ static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai, ...@@ -274,7 +274,7 @@ static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai,
unsigned long input_rate, unsigned long input_rate,
unsigned long output_rate) unsigned long output_rate)
{ {
int version = sai->pdata->conf->version; int version = sai->pdata->conf.version;
int div; int div;
div = DIV_ROUND_CLOSEST(input_rate, output_rate); 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, ...@@ -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, static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
unsigned int div) unsigned int div)
{ {
int version = sai->pdata->conf->version; int version = sai->pdata->conf.version;
int ret, cr1, mask; int ret, cr1, mask;
if (div > SAI_XCR1_MCKDIV_MAX(version)) { if (div > SAI_XCR1_MCKDIV_MAX(version)) {
...@@ -1148,6 +1148,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) ...@@ -1148,6 +1148,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
* constraints). * constraints).
*/ */
sai->dma_params.maxburst = 4; 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 */ /* Buswidth will be set by framework at runtime */
sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
...@@ -1315,8 +1317,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, ...@@ -1315,8 +1317,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
sai->phys_addr = res->start; sai->phys_addr = res->start;
sai->regmap_config = &stm32_sai_sub_regmap_config_f4; sai->regmap_config = &stm32_sai_sub_regmap_config_f4;
/* Note: PDM registers not available for H7 sub-block B */ /* Note: PDM registers not available for sub-block B */
if (STM_SAI_IS_H7(sai->pdata) && STM_SAI_IS_SUB_A(sai)) if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai))
sai->regmap_config = &stm32_sai_sub_regmap_config_h7; sai->regmap_config = &stm32_sai_sub_regmap_config_h7;
sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment