]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
ASoC: stm32: sai: manage identification registers
authorOlivier Moysan <olivier.moysan@st.com>
Mon, 3 Jun 2019 08:16:34 +0000 (10:16 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 3 Jun 2019 16:46:11 +0000 (17:46 +0100)
Add support of identification registers in STM32 SAI.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/stm/stm32_sai.c
sound/soc/stm/stm32_sai.h
sound/soc/stm/stm32_sai_sub.c

index 7550d5f08be3d9c0c2bfc82a06adf00974e77f00..98b29f7128312650e58dfe24f9afdf707d297b8c 100644 (file)
 #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);
index 9c36a393ab7b9b159ebc07c3e5aa84befd899104..158c73f557f7ea4bbc388692e489fec38552b362 100644 (file)
 #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)
 #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);
index 2a74ce7c9440f56ddbcbb968a751a88efb0d4454..7d27efb19380683cd5be25de1fa768a72e2ac6d6 100644 (file)
@@ -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",