aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/stm/stm32_sai.c2
-rw-r--r--sound/soc/stm/stm32_sai.h2
-rw-r--r--sound/soc/stm/stm32_sai_sub.c153
3 files changed, 133 insertions, 24 deletions
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d743b7dd52fb..f22654253c43 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -30,10 +30,12 @@
30 30
31static const struct stm32_sai_conf stm32_sai_conf_f4 = { 31static const struct stm32_sai_conf stm32_sai_conf_f4 = {
32 .version = SAI_STM32F4, 32 .version = SAI_STM32F4,
33 .has_spdif = false,
33}; 34};
34 35
35static const struct stm32_sai_conf stm32_sai_conf_h7 = { 36static const struct stm32_sai_conf stm32_sai_conf_h7 = {
36 .version = SAI_STM32H7, 37 .version = SAI_STM32H7,
38 .has_spdif = true,
37}; 39};
38 40
39static const struct of_device_id stm32_sai_ids[] = { 41static const struct of_device_id stm32_sai_ids[] = {
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index bb062e70de63..f25422174909 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -248,9 +248,11 @@ enum stm32_sai_version {
248/** 248/**
249 * struct stm32_sai_conf - SAI configuration 249 * struct stm32_sai_conf - SAI configuration
250 * @version: SAI version 250 * @version: SAI version
251 * @has_spdif: SAI S/PDIF support flag
251 */ 252 */
252struct stm32_sai_conf { 253struct stm32_sai_conf {
253 int version; 254 int version;
255 bool has_spdif;
254}; 256};
255 257
256/** 258/**
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 08583b958430..cfeb219e1d78 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -23,6 +23,7 @@
23#include <linux/of_platform.h> 23#include <linux/of_platform.h>
24#include <linux/regmap.h> 24#include <linux/regmap.h>
25 25
26#include <sound/asoundef.h>
26#include <sound/core.h> 27#include <sound/core.h>
27#include <sound/dmaengine_pcm.h> 28#include <sound/dmaengine_pcm.h>
28#include <sound/pcm_params.h> 29#include <sound/pcm_params.h>
@@ -30,6 +31,7 @@
30#include "stm32_sai.h" 31#include "stm32_sai.h"
31 32
32#define SAI_FREE_PROTOCOL 0x0 33#define SAI_FREE_PROTOCOL 0x0
34#define SAI_SPDIF_PROTOCOL 0x1
33 35
34#define SAI_SLOT_SIZE_AUTO 0x0 36#define SAI_SLOT_SIZE_AUTO 0x0
35#define SAI_SLOT_SIZE_16 0x1 37#define SAI_SLOT_SIZE_16 0x1
@@ -59,8 +61,13 @@
59#define SAI_SYNC_INTERNAL 0x1 61#define SAI_SYNC_INTERNAL 0x1
60#define SAI_SYNC_EXTERNAL 0x2 62#define SAI_SYNC_EXTERNAL 0x2
61 63
64#define STM_SAI_PROTOCOL_IS_SPDIF(ip) ((ip)->spdif)
65#define STM_SAI_HAS_SPDIF(x) ((x)->pdata->conf->has_spdif)
62#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata)) 66#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
63 67
68#define SAI_IEC60958_BLOCK_FRAMES 192
69#define SAI_IEC60958_STATUS_BYTES 24
70
64/** 71/**
65 * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) 72 * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
66 * @pdev: device data pointer 73 * @pdev: device data pointer
@@ -78,6 +85,7 @@
78 * @id: SAI sub block id corresponding to sub-block A or B 85 * @id: SAI sub block id corresponding to sub-block A or B
79 * @dir: SAI block direction (playback or capture). set at init 86 * @dir: SAI block direction (playback or capture). set at init
80 * @master: SAI block mode flag. (true=master, false=slave) set at init 87 * @master: SAI block mode flag. (true=master, false=slave) set at init
88 * @spdif: SAI S/PDIF iec60958 mode flag. set at init
81 * @fmt: SAI block format. relevant only for custom protocols. set at init 89 * @fmt: SAI block format. relevant only for custom protocols. set at init
82 * @sync: SAI block synchronization mode. (none, internal or external) 90 * @sync: SAI block synchronization mode. (none, internal or external)
83 * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B) 91 * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
@@ -87,6 +95,8 @@
87 * @slot_width: rx or tx slot width in bits 95 * @slot_width: rx or tx slot width in bits
88 * @slot_mask: rx or tx active slots mask. set at init or at runtime 96 * @slot_mask: rx or tx active slots mask. set at init or at runtime
89 * @data_size: PCM data width. corresponds to PCM substream width. 97 * @data_size: PCM data width. corresponds to PCM substream width.
98 * @spdif_frm_cnt: S/PDIF playback frame counter
99 * @spdif_status_bits: S/PDIF status bits
90 */ 100 */
91struct stm32_sai_sub_data { 101struct stm32_sai_sub_data {
92 struct platform_device *pdev; 102 struct platform_device *pdev;
@@ -104,6 +114,7 @@ struct stm32_sai_sub_data {
104 unsigned int id; 114 unsigned int id;
105 int dir; 115 int dir;
106 bool master; 116 bool master;
117 bool spdif;
107 int fmt; 118 int fmt;
108 int sync; 119 int sync;
109 int synco; 120 int synco;
@@ -113,6 +124,8 @@ struct stm32_sai_sub_data {
113 int slot_width; 124 int slot_width;
114 int slot_mask; 125 int slot_mask;
115 int data_size; 126 int data_size;
127 unsigned int spdif_frm_cnt;
128 unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES];
116}; 129};
117 130
118enum stm32_sai_fifo_th { 131enum stm32_sai_fifo_th {
@@ -171,6 +184,10 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
171 } 184 }
172} 185}
173 186
187static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = {
188 0, 0, 0, IEC958_AES3_CON_FS_48000,
189};
190
174static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { 191static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
175 .reg_bits = 32, 192 .reg_bits = 32,
176 .reg_stride = 4, 193 .reg_stride = 4,
@@ -277,6 +294,11 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
277 struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); 294 struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
278 int slotr, slotr_mask, slot_size; 295 int slotr, slotr_mask, slot_size;
279 296
297 if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
298 dev_warn(cpu_dai->dev, "Slot setting relevant only for TDM\n");
299 return 0;
300 }
301
280 dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n", 302 dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n",
281 tx_mask, rx_mask, slots, slot_width); 303 tx_mask, rx_mask, slots, slot_width);
282 304
@@ -326,8 +348,17 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
326 348
327 dev_dbg(cpu_dai->dev, "fmt %x\n", fmt); 349 dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
328 350
329 cr1_mask = SAI_XCR1_PRTCFG_MASK; 351 /* Do not generate master by default */
330 cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); 352 cr1 = SAI_XCR1_NODIV;
353 cr1_mask = SAI_XCR1_NODIV;
354
355 cr1_mask |= SAI_XCR1_PRTCFG_MASK;
356 if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
357 cr1 |= SAI_XCR1_PRTCFG_SET(SAI_SPDIF_PROTOCOL);
358 goto conf_update;
359 }
360
361 cr1 |= SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
331 362
332 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 363 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
333 /* SCK active high for all protocols */ 364 /* SCK active high for all protocols */
@@ -409,10 +440,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
409 440
410 cr1_mask |= SAI_XCR1_SLAVE; 441 cr1_mask |= SAI_XCR1_SLAVE;
411 442
412 /* do not generate master by default */ 443conf_update:
413 cr1 |= SAI_XCR1_NODIV;
414 cr1_mask |= SAI_XCR1_NODIV;
415
416 ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); 444 ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
417 if (ret < 0) { 445 if (ret < 0) {
418 dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); 446 dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
@@ -478,6 +506,12 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
478 SAI_XCR2_FFLUSH | 506 SAI_XCR2_FFLUSH |
479 SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); 507 SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
480 508
509 /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/
510 if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
511 sai->spdif_frm_cnt = 0;
512 return 0;
513 }
514
481 /* Mode, data format and channel config */ 515 /* Mode, data format and channel config */
482 cr1_mask = SAI_XCR1_DS_MASK; 516 cr1_mask = SAI_XCR1_DS_MASK;
483 switch (params_format(params)) { 517 switch (params_format(params)) {
@@ -592,13 +626,14 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
592 int cr1, mask, div = 0; 626 int cr1, mask, div = 0;
593 int sai_clk_rate, mclk_ratio, den, ret; 627 int sai_clk_rate, mclk_ratio, den, ret;
594 int version = sai->pdata->conf->version; 628 int version = sai->pdata->conf->version;
629 unsigned int rate = params_rate(params);
595 630
596 if (!sai->mclk_rate) { 631 if (!sai->mclk_rate) {
597 dev_err(cpu_dai->dev, "Mclk rate is null\n"); 632 dev_err(cpu_dai->dev, "Mclk rate is null\n");
598 return -EINVAL; 633 return -EINVAL;
599 } 634 }
600 635
601 if (!(params_rate(params) % 11025)) 636 if (!(rate % 11025))
602 clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k); 637 clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k);
603 else 638 else
604 clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k); 639 clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
@@ -623,24 +658,28 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
623 * MCKDIV = sai_ck / (frl x ws) (NOMCK=1) 658 * MCKDIV = sai_ck / (frl x ws) (NOMCK=1)
624 * Note: NOMCK/NODIV correspond to same bit. 659 * Note: NOMCK/NODIV correspond to same bit.
625 */ 660 */
626 if (sai->mclk_rate) { 661 if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
627 mclk_ratio = sai->mclk_rate / params_rate(params); 662 div = DIV_ROUND_CLOSEST(sai_clk_rate,
628 if (mclk_ratio != 256) { 663 (params_rate(params) * 128));
664 } else {
665 if (sai->mclk_rate) {
666 mclk_ratio = sai->mclk_rate / rate;
629 if (mclk_ratio == 512) { 667 if (mclk_ratio == 512) {
630 mask = SAI_XCR1_OSR; 668 mask = SAI_XCR1_OSR;
631 cr1 = SAI_XCR1_OSR; 669 cr1 = SAI_XCR1_OSR;
632 } else { 670 } else if (mclk_ratio != 256) {
633 dev_err(cpu_dai->dev, 671 dev_err(cpu_dai->dev,
634 "Wrong mclk ratio %d\n", 672 "Wrong mclk ratio %d\n",
635 mclk_ratio); 673 mclk_ratio);
636 return -EINVAL; 674 return -EINVAL;
637 } 675 }
676 div = DIV_ROUND_CLOSEST(sai_clk_rate,
677 sai->mclk_rate);
678 } else {
679 /* mclk-fs not set, master clock not active */
680 den = sai->fs_length * params_rate(params);
681 div = DIV_ROUND_CLOSEST(sai_clk_rate, den);
638 } 682 }
639 div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate);
640 } else {
641 /* mclk-fs not set, master clock not active. NOMCK=1 */
642 den = sai->fs_length * params_rate(params);
643 div = DIV_ROUND_CLOSEST(sai_clk_rate, den);
644 } 683 }
645 } 684 }
646 685
@@ -670,10 +709,12 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream,
670 709
671 sai->data_size = params_width(params); 710 sai->data_size = params_width(params);
672 711
673 ret = stm32_sai_set_slots(cpu_dai); 712 if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
674 if (ret < 0) 713 ret = stm32_sai_set_slots(cpu_dai);
675 return ret; 714 if (ret < 0)
676 stm32_sai_set_frame(cpu_dai); 715 return ret;
716 stm32_sai_set_frame(cpu_dai);
717 }
677 718
678 ret = stm32_sai_set_config(cpu_dai, substream, params); 719 ret = stm32_sai_set_config(cpu_dai, substream, params);
679 if (ret) 720 if (ret)
@@ -723,6 +764,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
723 (unsigned int)~SAI_XCR1_DMAEN); 764 (unsigned int)~SAI_XCR1_DMAEN);
724 if (ret < 0) 765 if (ret < 0)
725 dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); 766 dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
767
768 if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
769 sai->spdif_frm_cnt = 0;
726 break; 770 break;
727 default: 771 default:
728 return -EINVAL; 772 return -EINVAL;
@@ -776,6 +820,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
776 sai->synco, sai->synci); 820 sai->synco, sai->synci);
777 } 821 }
778 822
823 if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
824 memcpy(sai->spdif_status_bits, default_status_bits,
825 sizeof(default_status_bits));
826
779 cr1_mask |= SAI_XCR1_SYNCEN_MASK; 827 cr1_mask |= SAI_XCR1_SYNCEN_MASK;
780 cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync); 828 cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
781 829
@@ -792,6 +840,42 @@ static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
792 .shutdown = stm32_sai_shutdown, 840 .shutdown = stm32_sai_shutdown,
793}; 841};
794 842
843static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream,
844 int channel, unsigned long hwoff,
845 void *buf, unsigned long bytes)
846{
847 struct snd_pcm_runtime *runtime = substream->runtime;
848 struct snd_soc_pcm_runtime *rtd = substream->private_data;
849 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
850 struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
851 int *ptr = (int *)(runtime->dma_area + hwoff +
852 channel * (runtime->dma_bytes / runtime->channels));
853 ssize_t cnt = bytes_to_samples(runtime, bytes);
854 unsigned int frm_cnt = sai->spdif_frm_cnt;
855 unsigned int byte;
856 unsigned int mask;
857
858 do {
859 *ptr = ((*ptr >> 8) & 0x00ffffff);
860
861 /* Set channel status bit */
862 byte = frm_cnt >> 3;
863 mask = 1 << (frm_cnt - (byte << 3));
864 if (sai->spdif_status_bits[byte] & mask)
865 *ptr |= 0x04000000;
866 ptr++;
867
868 if (!(cnt % 2))
869 frm_cnt++;
870
871 if (frm_cnt == SAI_IEC60958_BLOCK_FRAMES)
872 frm_cnt = 0;
873 } while (--cnt);
874 sai->spdif_frm_cnt = frm_cnt;
875
876 return 0;
877}
878
795static const struct snd_pcm_hardware stm32_sai_pcm_hw = { 879static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
796 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, 880 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
797 .buffer_bytes_max = 8 * PAGE_SIZE, 881 .buffer_bytes_max = 8 * PAGE_SIZE,
@@ -842,8 +926,14 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai[] = {
842}; 926};
843 927
844static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { 928static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
845 .pcm_hardware = &stm32_sai_pcm_hw, 929 .pcm_hardware = &stm32_sai_pcm_hw,
846 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 930 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
931};
932
933static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config_spdif = {
934 .pcm_hardware = &stm32_sai_pcm_hw,
935 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
936 .process = stm32_sai_pcm_process_spdif,
847}; 937};
848 938
849static const struct snd_soc_component_driver stm32_component = { 939static const struct snd_soc_component_driver stm32_component = {
@@ -900,6 +990,18 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
900 return -EINVAL; 990 return -EINVAL;
901 } 991 }
902 992
993 /* Get spdif iec60958 property */
994 sai->spdif = false;
995 if (of_get_property(np, "st,iec60958", NULL)) {
996 if (!STM_SAI_HAS_SPDIF(sai) ||
997 sai->dir == SNDRV_PCM_STREAM_CAPTURE) {
998 dev_err(&pdev->dev, "S/PDIF IEC60958 not supported\n");
999 return -EINVAL;
1000 }
1001 sai->spdif = true;
1002 sai->master = true;
1003 }
1004
903 /* Get synchronization property */ 1005 /* Get synchronization property */
904 args.np = NULL; 1006 args.np = NULL;
905 ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args); 1007 ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
@@ -999,6 +1101,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
999{ 1101{
1000 struct stm32_sai_sub_data *sai; 1102 struct stm32_sai_sub_data *sai;
1001 const struct of_device_id *of_id; 1103 const struct of_device_id *of_id;
1104 const struct snd_dmaengine_pcm_config *conf = &stm32_sai_pcm_config;
1002 int ret; 1105 int ret;
1003 1106
1004 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); 1107 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
@@ -1039,8 +1142,10 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
1039 if (ret) 1142 if (ret)
1040 return ret; 1143 return ret;
1041 1144
1042 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, 1145 if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
1043 &stm32_sai_pcm_config, 0); 1146 conf = &stm32_sai_pcm_config_spdif;
1147
1148 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
1044 if (ret) { 1149 if (ret) {
1045 dev_err(&pdev->dev, "Could not register pcm dma\n"); 1150 dev_err(&pdev->dev, "Could not register pcm dma\n");
1046 return ret; 1151 return ret;