aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorolivier moysan <olivier.moysan@st.com>2017-06-16 08:16:24 -0400
committerMark Brown <broonie@kernel.org>2017-06-16 13:59:03 -0400
commit03e78a242a15eca68e5c7cb606c94959382e2b18 (patch)
treed76d53c35180a2bb7d2dada264bce63fa5152499
parent3861da5801f59f3e9252b6a5db92cfa71629995c (diff)
ASoC: stm32: sai: add h7 support
Add support of SAI on STM32H7 family. Signed-off-by: olivier moysan <olivier.moysan@st.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/stm/stm32_sai.c13
-rw-r--r--sound/soc/stm/stm32_sai.h72
-rw-r--r--sound/soc/stm/stm32_sai_sub.c92
3 files changed, 155 insertions, 22 deletions
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 6159d66c2c54..f7713314913b 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -27,8 +27,17 @@
27 27
28#include "stm32_sai.h" 28#include "stm32_sai.h"
29 29
30static const struct stm32_sai_conf stm32_sai_conf_f4 = {
31 .version = SAI_STM32F4,
32};
33
34static const struct stm32_sai_conf stm32_sai_conf_h7 = {
35 .version = SAI_STM32H7,
36};
37
30static const struct of_device_id stm32_sai_ids[] = { 38static const struct of_device_id stm32_sai_ids[] = {
31 { .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 }, 39 { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 },
40 { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 },
32 {} 41 {}
33}; 42};
34 43
@@ -52,7 +61,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
52 61
53 of_id = of_match_device(stm32_sai_ids, &pdev->dev); 62 of_id = of_match_device(stm32_sai_ids, &pdev->dev);
54 if (of_id) 63 if (of_id)
55 sai->version = (enum stm32_sai_version)of_id->data; 64 sai->conf = (struct stm32_sai_conf *)of_id->data;
56 else 65 else
57 return -EINVAL; 66 return -EINVAL;
58 67
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 270be93b845e..889974dc62d9 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -31,6 +31,10 @@
31#define STM_SAI_CLRFR_REGX 0x18 31#define STM_SAI_CLRFR_REGX 0x18
32#define STM_SAI_DR_REGX 0x1C 32#define STM_SAI_DR_REGX 0x1C
33 33
34/* Sub-block A registers, relative to sub-block A address */
35#define STM_SAI_PDMCR_REGX 0x40
36#define STM_SAI_PDMLY_REGX 0x44
37
34/******************** Bit definition for SAI_GCR register *******************/ 38/******************** Bit definition for SAI_GCR register *******************/
35#define SAI_GCR_SYNCIN_SHIFT 0 39#define SAI_GCR_SYNCIN_SHIFT 0
36#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT) 40#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
@@ -75,10 +79,11 @@
75#define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT) 79#define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT)
76 80
77#define SAI_XCR1_MCKDIV_SHIFT 20 81#define SAI_XCR1_MCKDIV_SHIFT 20
78#define SAI_XCR1_MCKDIV_WIDTH 4 82#define SAI_XCR1_MCKDIV_WIDTH(x) (((x) == SAI_STM32F4) ? 4 : 6)
79#define SAI_XCR1_MCKDIV_MASK GENMASK(24, SAI_XCR1_MCKDIV_SHIFT) 83#define SAI_XCR1_MCKDIV_MASK(x) GENMASK((SAI_XCR1_MCKDIV_SHIFT + (x) - 1),\
84 SAI_XCR1_MCKDIV_SHIFT)
80#define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT) 85#define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT)
81#define SAI_XCR1_MCKDIV_MAX ((1 << SAI_XCR1_MCKDIV_WIDTH) - 1) 86#define SAI_XCR1_MCKDIV_MAX(x) ((1 << SAI_XCR1_MCKDIV_WIDTH(x)) - 1)
82 87
83#define SAI_XCR1_OSR_SHIFT 26 88#define SAI_XCR1_OSR_SHIFT 26
84#define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT) 89#define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT)
@@ -178,8 +183,65 @@
178#define SAI_XCLRFR_SHIFT 0 183#define SAI_XCLRFR_SHIFT 0
179#define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT) 184#define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT)
180 185
186/****************** Bit definition for SAI_PDMCR register ******************/
187#define SAI_PDMCR_PDMEN BIT(0)
188
189#define SAI_PDMCR_MICNBR_SHIFT 4
190#define SAI_PDMCR_MICNBR_MASK GENMASK(5, SAI_PDMCR_MICNBR_SHIFT)
191#define SAI_PDMCR_MICNBR_SET(x) ((x) << SAI_PDMCR_MICNBR_SHIFT)
192
193#define SAI_PDMCR_CKEN1 BIT(8)
194#define SAI_PDMCR_CKEN2 BIT(9)
195#define SAI_PDMCR_CKEN3 BIT(10)
196#define SAI_PDMCR_CKEN4 BIT(11)
197
198/****************** Bit definition for (SAI_PDMDLY register ****************/
199#define SAI_PDMDLY_1L_SHIFT 0
200#define SAI_PDMDLY_1L_MASK GENMASK(2, SAI_PDMDLY_1L_SHIFT)
201#define SAI_PDMDLY_1L_WIDTH 3
202
203#define SAI_PDMDLY_1R_SHIFT 4
204#define SAI_PDMDLY_1R_MASK GENMASK(6, SAI_PDMDLY_1R_SHIFT)
205#define SAI_PDMDLY_1R_WIDTH 3
206
207#define SAI_PDMDLY_2L_SHIFT 8
208#define SAI_PDMDLY_2L_MASK GENMASK(10, SAI_PDMDLY_2L_SHIFT)
209#define SAI_PDMDLY_2L_WIDTH 3
210
211#define SAI_PDMDLY_2R_SHIFT 12
212#define SAI_PDMDLY_2R_MASK GENMASK(14, SAI_PDMDLY_2R_SHIFT)
213#define SAI_PDMDLY_2R_WIDTH 3
214
215#define SAI_PDMDLY_3L_SHIFT 16
216#define SAI_PDMDLY_3L_MASK GENMASK(18, SAI_PDMDLY_3L_SHIFT)
217#define SAI_PDMDLY_3L_WIDTH 3
218
219#define SAI_PDMDLY_3R_SHIFT 20
220#define SAI_PDMDLY_3R_MASK GENMASK(22, SAI_PDMDLY_3R_SHIFT)
221#define SAI_PDMDLY_3R_WIDTH 3
222
223#define SAI_PDMDLY_4L_SHIFT 24
224#define SAI_PDMDLY_4L_MASK GENMASK(26, SAI_PDMDLY_4L_SHIFT)
225#define SAI_PDMDLY_4L_WIDTH 3
226
227#define SAI_PDMDLY_4R_SHIFT 28
228#define SAI_PDMDLY_4R_MASK GENMASK(30, SAI_PDMDLY_4R_SHIFT)
229#define SAI_PDMDLY_4R_WIDTH 3
230
231#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4)
232#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7)
233
181enum stm32_sai_version { 234enum stm32_sai_version {
182 SAI_STM32F4 235 SAI_STM32F4,
236 SAI_STM32H7
237};
238
239/**
240 * struct stm32_sai_conf - SAI configuration
241 * @version: SAI version
242 */
243struct stm32_sai_conf {
244 int version;
183}; 245};
184 246
185/** 247/**
@@ -194,6 +256,6 @@ struct stm32_sai_data {
194 struct platform_device *pdev; 256 struct platform_device *pdev;
195 struct clk *clk_x8k; 257 struct clk *clk_x8k;
196 struct clk *clk_x11k; 258 struct clk *clk_x11k;
197 int version; 259 struct stm32_sai_conf *conf;
198 int irq; 260 int irq;
199}; 261};
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index ce48c02db051..ba3fdc777ed8 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -51,12 +51,15 @@
51#define STM_SAI_A_ID 0x0 51#define STM_SAI_A_ID 0x0
52#define STM_SAI_B_ID 0x1 52#define STM_SAI_B_ID 0x1
53 53
54#define STM_SAI_IS_SUB_A(x) ((x)->id == STM_SAI_A_ID)
55#define STM_SAI_IS_SUB_B(x) ((x)->id == STM_SAI_B_ID)
54#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B") 56#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B")
55 57
56/** 58/**
57 * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) 59 * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
58 * @pdev: device data pointer 60 * @pdev: device data pointer
59 * @regmap: SAI register map pointer 61 * @regmap: SAI register map pointer
62 * @regmap_config: SAI sub block register map configuration pointer
60 * @dma_params: dma configuration data for rx or tx channel 63 * @dma_params: dma configuration data for rx or tx channel
61 * @cpu_dai_drv: DAI driver data pointer 64 * @cpu_dai_drv: DAI driver data pointer
62 * @cpu_dai: DAI runtime data pointer 65 * @cpu_dai: DAI runtime data pointer
@@ -79,6 +82,7 @@
79struct stm32_sai_sub_data { 82struct stm32_sai_sub_data {
80 struct platform_device *pdev; 83 struct platform_device *pdev;
81 struct regmap *regmap; 84 struct regmap *regmap;
85 const struct regmap_config *regmap_config;
82 struct snd_dmaengine_dai_dma_data dma_params; 86 struct snd_dmaengine_dai_dma_data dma_params;
83 struct snd_soc_dai_driver *cpu_dai_drv; 87 struct snd_soc_dai_driver *cpu_dai_drv;
84 struct snd_soc_dai *cpu_dai; 88 struct snd_soc_dai *cpu_dai;
@@ -118,6 +122,8 @@ static bool stm32_sai_sub_readable_reg(struct device *dev, unsigned int reg)
118 case STM_SAI_SR_REGX: 122 case STM_SAI_SR_REGX:
119 case STM_SAI_CLRFR_REGX: 123 case STM_SAI_CLRFR_REGX:
120 case STM_SAI_DR_REGX: 124 case STM_SAI_DR_REGX:
125 case STM_SAI_PDMCR_REGX:
126 case STM_SAI_PDMLY_REGX:
121 return true; 127 return true;
122 default: 128 default:
123 return false; 129 return false;
@@ -145,13 +151,15 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
145 case STM_SAI_SR_REGX: 151 case STM_SAI_SR_REGX:
146 case STM_SAI_CLRFR_REGX: 152 case STM_SAI_CLRFR_REGX:
147 case STM_SAI_DR_REGX: 153 case STM_SAI_DR_REGX:
154 case STM_SAI_PDMCR_REGX:
155 case STM_SAI_PDMLY_REGX:
148 return true; 156 return true;
149 default: 157 default:
150 return false; 158 return false;
151 } 159 }
152} 160}
153 161
154static const struct regmap_config stm32_sai_sub_regmap_config = { 162static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
155 .reg_bits = 32, 163 .reg_bits = 32,
156 .reg_stride = 4, 164 .reg_stride = 4,
157 .val_bits = 32, 165 .val_bits = 32,
@@ -162,6 +170,17 @@ static const struct regmap_config stm32_sai_sub_regmap_config = {
162 .fast_io = true, 170 .fast_io = true,
163}; 171};
164 172
173static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
174 .reg_bits = 32,
175 .reg_stride = 4,
176 .val_bits = 32,
177 .max_register = STM_SAI_PDMLY_REGX,
178 .readable_reg = stm32_sai_sub_readable_reg,
179 .volatile_reg = stm32_sai_sub_volatile_reg,
180 .writeable_reg = stm32_sai_sub_writeable_reg,
181 .fast_io = true,
182};
183
165static irqreturn_t stm32_sai_isr(int irq, void *devid) 184static irqreturn_t stm32_sai_isr(int irq, void *devid)
166{ 185{
167 struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; 186 struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
@@ -551,7 +570,8 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
551{ 570{
552 struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); 571 struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
553 int cr1, mask, div = 0; 572 int cr1, mask, div = 0;
554 int sai_clk_rate, ret; 573 int sai_clk_rate, mclk_ratio, den, ret;
574 int version = sai->pdata->conf->version;
555 575
556 if (!sai->mclk_rate) { 576 if (!sai->mclk_rate) {
557 dev_err(cpu_dai->dev, "Mclk rate is null\n"); 577 dev_err(cpu_dai->dev, "Mclk rate is null\n");
@@ -564,22 +584,54 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
564 clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k); 584 clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
565 sai_clk_rate = clk_get_rate(sai->sai_ck); 585 sai_clk_rate = clk_get_rate(sai->sai_ck);
566 586
567 /* 587 if (STM_SAI_IS_F4(sai->pdata)) {
568 * mclk_rate = 256 * fs 588 /*
569 * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate 589 * mclk_rate = 256 * fs
570 * MCKDIV = sai_ck / (2 * mclk_rate) otherwise 590 * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate
571 */ 591 * MCKDIV = sai_ck / (2 * mclk_rate) otherwise
572 if (2 * sai_clk_rate >= 3 * sai->mclk_rate) 592 */
573 div = DIV_ROUND_CLOSEST(sai_clk_rate, 2 * sai->mclk_rate); 593 if (2 * sai_clk_rate >= 3 * sai->mclk_rate)
574 594 div = DIV_ROUND_CLOSEST(sai_clk_rate,
575 if (div > SAI_XCR1_MCKDIV_MAX) { 595 2 * sai->mclk_rate);
596 } else {
597 /*
598 * TDM mode :
599 * mclk on
600 * MCKDIV = sai_ck / (ws x 256) (NOMCK=0. OSR=0)
601 * MCKDIV = sai_ck / (ws x 512) (NOMCK=0. OSR=1)
602 * mclk off
603 * MCKDIV = sai_ck / (frl x ws) (NOMCK=1)
604 * Note: NOMCK/NODIV correspond to same bit.
605 */
606 if (sai->mclk_rate) {
607 mclk_ratio = sai->mclk_rate / params_rate(params);
608 if (mclk_ratio != 256) {
609 if (mclk_ratio == 512) {
610 mask = SAI_XCR1_OSR;
611 cr1 = SAI_XCR1_OSR;
612 } else {
613 dev_err(cpu_dai->dev,
614 "Wrong mclk ratio %d\n",
615 mclk_ratio);
616 return -EINVAL;
617 }
618 }
619 div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate);
620 } else {
621 /* mclk-fs not set, master clock not active. NOMCK=1 */
622 den = sai->fs_length * params_rate(params);
623 div = DIV_ROUND_CLOSEST(sai_clk_rate, den);
624 }
625 }
626
627 if (div > SAI_XCR1_MCKDIV_MAX(version)) {
576 dev_err(cpu_dai->dev, "Divider %d out of range\n", div); 628 dev_err(cpu_dai->dev, "Divider %d out of range\n", div);
577 return -EINVAL; 629 return -EINVAL;
578 } 630 }
579 dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div); 631 dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div);
580 632
581 mask = SAI_XCR1_MCKDIV_MASK; 633 mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version));
582 cr1 = SAI_XCR1_MCKDIV_SET(div); 634 cr1 = SAI_XCR1_MCKDIV_SET(div);
583 ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); 635 ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1);
584 if (ret < 0) { 636 if (ret < 0) {
585 dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); 637 dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
@@ -780,8 +832,18 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
780 return PTR_ERR(base); 832 return PTR_ERR(base);
781 833
782 sai->phys_addr = res->start; 834 sai->phys_addr = res->start;
783 sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", base, 835
784 &stm32_sai_sub_regmap_config); 836 sai->regmap_config = &stm32_sai_sub_regmap_config_f4;
837 /* Note: PDM registers not available for H7 sub-block B */
838 if (STM_SAI_IS_H7(sai->pdata) && STM_SAI_IS_SUB_A(sai))
839 sai->regmap_config = &stm32_sai_sub_regmap_config_h7;
840
841 sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck",
842 base, sai->regmap_config);
843 if (IS_ERR(sai->regmap)) {
844 dev_err(&pdev->dev, "Failed to initialize MMIO\n");
845 return PTR_ERR(sai->regmap);
846 }
785 847
786 /* Get direction property */ 848 /* Get direction property */
787 if (of_property_match_string(np, "dma-names", "tx") >= 0) { 849 if (of_property_match_string(np, "dma-names", "tx") >= 0) {