Loading sound/soc/stm/stm32_sai.c +2 −0 Original line number Diff line number Diff line Loading @@ -30,10 +30,12 @@ static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = SAI_STM32F4, .has_spdif = false, }; static const struct stm32_sai_conf stm32_sai_conf_h7 = { .version = SAI_STM32H7, .has_spdif = true, }; static const struct of_device_id stm32_sai_ids[] = { Loading sound/soc/stm/stm32_sai.h +2 −0 Original line number Diff line number Diff line Loading @@ -248,9 +248,11 @@ enum stm32_sai_version { /** * struct stm32_sai_conf - SAI configuration * @version: SAI version * @has_spdif: SAI S/PDIF support flag */ struct stm32_sai_conf { int version; bool has_spdif; }; /** Loading sound/soc/stm/stm32_sai_sub.c +129 −24 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/of_platform.h> #include <linux/regmap.h> #include <sound/asoundef.h> #include <sound/core.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> Loading @@ -30,6 +31,7 @@ #include "stm32_sai.h" #define SAI_FREE_PROTOCOL 0x0 #define SAI_SPDIF_PROTOCOL 0x1 #define SAI_SLOT_SIZE_AUTO 0x0 #define SAI_SLOT_SIZE_16 0x1 Loading Loading @@ -59,8 +61,13 @@ #define SAI_SYNC_INTERNAL 0x1 #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_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata)) #define SAI_IEC60958_BLOCK_FRAMES 192 #define SAI_IEC60958_STATUS_BYTES 24 /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) * @pdev: device data pointer Loading @@ -78,6 +85,7 @@ * @id: SAI sub block id corresponding to sub-block A or B * @dir: SAI block direction (playback or capture). set at init * @master: SAI block mode flag. (true=master, false=slave) set at init * @spdif: SAI S/PDIF iec60958 mode flag. set at init * @fmt: SAI block format. relevant only for custom protocols. set at init * @sync: SAI block synchronization mode. (none, internal or external) * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B) Loading @@ -87,6 +95,8 @@ * @slot_width: rx or tx slot width in bits * @slot_mask: rx or tx active slots mask. set at init or at runtime * @data_size: PCM data width. corresponds to PCM substream width. * @spdif_frm_cnt: S/PDIF playback frame counter * @spdif_status_bits: S/PDIF status bits */ struct stm32_sai_sub_data { struct platform_device *pdev; Loading @@ -104,6 +114,7 @@ struct stm32_sai_sub_data { unsigned int id; int dir; bool master; bool spdif; int fmt; int sync; int synco; Loading @@ -113,6 +124,8 @@ struct stm32_sai_sub_data { int slot_width; int slot_mask; int data_size; unsigned int spdif_frm_cnt; unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES]; }; enum stm32_sai_fifo_th { Loading Loading @@ -171,6 +184,10 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) } } static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = { 0, 0, 0, IEC958_AES3_CON_FS_48000, }; static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .reg_bits = 32, .reg_stride = 4, Loading Loading @@ -277,6 +294,11 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int slotr, slotr_mask, slot_size; if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { dev_warn(cpu_dai->dev, "Slot setting relevant only for TDM\n"); return 0; } dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n", tx_mask, rx_mask, slots, slot_width); Loading Loading @@ -326,8 +348,17 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) dev_dbg(cpu_dai->dev, "fmt %x\n", fmt); cr1_mask = SAI_XCR1_PRTCFG_MASK; cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); /* Do not generate master by default */ cr1 = SAI_XCR1_NODIV; cr1_mask = SAI_XCR1_NODIV; cr1_mask |= SAI_XCR1_PRTCFG_MASK; if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { cr1 |= SAI_XCR1_PRTCFG_SET(SAI_SPDIF_PROTOCOL); goto conf_update; } cr1 |= SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { /* SCK active high for all protocols */ Loading Loading @@ -409,10 +440,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) cr1_mask |= SAI_XCR1_SLAVE; /* do not generate master by default */ cr1 |= SAI_XCR1_NODIV; cr1_mask |= SAI_XCR1_NODIV; conf_update: ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); if (ret < 0) { dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); Loading Loading @@ -478,6 +506,12 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { sai->spdif_frm_cnt = 0; return 0; } /* Mode, data format and channel config */ cr1_mask = SAI_XCR1_DS_MASK; switch (params_format(params)) { Loading Loading @@ -592,13 +626,14 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, int cr1, mask, div = 0; int sai_clk_rate, mclk_ratio, den, ret; int version = sai->pdata->conf->version; unsigned int rate = params_rate(params); if (!sai->mclk_rate) { dev_err(cpu_dai->dev, "Mclk rate is null\n"); return -EINVAL; } if (!(params_rate(params) % 11025)) if (!(rate % 11025)) clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k); else clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k); Loading @@ -623,26 +658,30 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, * MCKDIV = sai_ck / (frl x ws) (NOMCK=1) * Note: NOMCK/NODIV correspond to same bit. */ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { div = DIV_ROUND_CLOSEST(sai_clk_rate, (params_rate(params) * 128)); } else { if (sai->mclk_rate) { mclk_ratio = sai->mclk_rate / params_rate(params); if (mclk_ratio != 256) { mclk_ratio = sai->mclk_rate / rate; if (mclk_ratio == 512) { mask = SAI_XCR1_OSR; cr1 = SAI_XCR1_OSR; } else { } else if (mclk_ratio != 256) { dev_err(cpu_dai->dev, "Wrong mclk ratio %d\n", mclk_ratio); return -EINVAL; } } div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate); div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate); } else { /* mclk-fs not set, master clock not active. NOMCK=1 */ /* mclk-fs not set, master clock not active */ den = sai->fs_length * params_rate(params); div = DIV_ROUND_CLOSEST(sai_clk_rate, den); } } } if (div > SAI_XCR1_MCKDIV_MAX(version)) { dev_err(cpu_dai->dev, "Divider %d out of range\n", div); Loading Loading @@ -670,10 +709,12 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream, sai->data_size = params_width(params); if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) { ret = stm32_sai_set_slots(cpu_dai); if (ret < 0) return ret; stm32_sai_set_frame(cpu_dai); } ret = stm32_sai_set_config(cpu_dai, substream, params); if (ret) Loading Loading @@ -723,6 +764,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, (unsigned int)~SAI_XCR1_DMAEN); if (ret < 0) dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) sai->spdif_frm_cnt = 0; break; default: return -EINVAL; Loading Loading @@ -776,6 +820,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) sai->synco, sai->synci); } if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) memcpy(sai->spdif_status_bits, default_status_bits, sizeof(default_status_bits)); cr1_mask |= SAI_XCR1_SYNCEN_MASK; cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync); Loading @@ -792,6 +840,42 @@ static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { .shutdown = stm32_sai_shutdown, }; static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, void *buf, unsigned long bytes) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); int *ptr = (int *)(runtime->dma_area + hwoff + channel * (runtime->dma_bytes / runtime->channels)); ssize_t cnt = bytes_to_samples(runtime, bytes); unsigned int frm_cnt = sai->spdif_frm_cnt; unsigned int byte; unsigned int mask; do { *ptr = ((*ptr >> 8) & 0x00ffffff); /* Set channel status bit */ byte = frm_cnt >> 3; mask = 1 << (frm_cnt - (byte << 3)); if (sai->spdif_status_bits[byte] & mask) *ptr |= 0x04000000; ptr++; if (!(cnt % 2)) frm_cnt++; if (frm_cnt == SAI_IEC60958_BLOCK_FRAMES) frm_cnt = 0; } while (--cnt); sai->spdif_frm_cnt = frm_cnt; return 0; } static const struct snd_pcm_hardware stm32_sai_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, .buffer_bytes_max = 8 * PAGE_SIZE, Loading Loading @@ -846,6 +930,12 @@ static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, }; static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config_spdif = { .pcm_hardware = &stm32_sai_pcm_hw, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, .process = stm32_sai_pcm_process_spdif, }; static const struct snd_soc_component_driver stm32_component = { .name = "stm32-sai", }; Loading Loading @@ -900,6 +990,18 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return -EINVAL; } /* Get spdif iec60958 property */ sai->spdif = false; if (of_get_property(np, "st,iec60958", NULL)) { if (!STM_SAI_HAS_SPDIF(sai) || sai->dir == SNDRV_PCM_STREAM_CAPTURE) { dev_err(&pdev->dev, "S/PDIF IEC60958 not supported\n"); return -EINVAL; } sai->spdif = true; sai->master = true; } /* Get synchronization property */ args.np = NULL; ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args); Loading Loading @@ -999,6 +1101,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) { struct stm32_sai_sub_data *sai; const struct of_device_id *of_id; const struct snd_dmaengine_pcm_config *conf = &stm32_sai_pcm_config; int ret; sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); Loading Loading @@ -1039,8 +1142,10 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) if (ret) return ret; ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &stm32_sai_pcm_config, 0); if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) conf = &stm32_sai_pcm_config_spdif; ret = devm_snd_dmaengine_pcm_register(&pdev->dev, conf, 0); if (ret) { dev_err(&pdev->dev, "Could not register pcm dma\n"); return ret; Loading Loading
sound/soc/stm/stm32_sai.c +2 −0 Original line number Diff line number Diff line Loading @@ -30,10 +30,12 @@ static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = SAI_STM32F4, .has_spdif = false, }; static const struct stm32_sai_conf stm32_sai_conf_h7 = { .version = SAI_STM32H7, .has_spdif = true, }; static const struct of_device_id stm32_sai_ids[] = { Loading
sound/soc/stm/stm32_sai.h +2 −0 Original line number Diff line number Diff line Loading @@ -248,9 +248,11 @@ enum stm32_sai_version { /** * struct stm32_sai_conf - SAI configuration * @version: SAI version * @has_spdif: SAI S/PDIF support flag */ struct stm32_sai_conf { int version; bool has_spdif; }; /** Loading
sound/soc/stm/stm32_sai_sub.c +129 −24 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/of_platform.h> #include <linux/regmap.h> #include <sound/asoundef.h> #include <sound/core.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> Loading @@ -30,6 +31,7 @@ #include "stm32_sai.h" #define SAI_FREE_PROTOCOL 0x0 #define SAI_SPDIF_PROTOCOL 0x1 #define SAI_SLOT_SIZE_AUTO 0x0 #define SAI_SLOT_SIZE_16 0x1 Loading Loading @@ -59,8 +61,13 @@ #define SAI_SYNC_INTERNAL 0x1 #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_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata)) #define SAI_IEC60958_BLOCK_FRAMES 192 #define SAI_IEC60958_STATUS_BYTES 24 /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) * @pdev: device data pointer Loading @@ -78,6 +85,7 @@ * @id: SAI sub block id corresponding to sub-block A or B * @dir: SAI block direction (playback or capture). set at init * @master: SAI block mode flag. (true=master, false=slave) set at init * @spdif: SAI S/PDIF iec60958 mode flag. set at init * @fmt: SAI block format. relevant only for custom protocols. set at init * @sync: SAI block synchronization mode. (none, internal or external) * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B) Loading @@ -87,6 +95,8 @@ * @slot_width: rx or tx slot width in bits * @slot_mask: rx or tx active slots mask. set at init or at runtime * @data_size: PCM data width. corresponds to PCM substream width. * @spdif_frm_cnt: S/PDIF playback frame counter * @spdif_status_bits: S/PDIF status bits */ struct stm32_sai_sub_data { struct platform_device *pdev; Loading @@ -104,6 +114,7 @@ struct stm32_sai_sub_data { unsigned int id; int dir; bool master; bool spdif; int fmt; int sync; int synco; Loading @@ -113,6 +124,8 @@ struct stm32_sai_sub_data { int slot_width; int slot_mask; int data_size; unsigned int spdif_frm_cnt; unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES]; }; enum stm32_sai_fifo_th { Loading Loading @@ -171,6 +184,10 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) } } static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = { 0, 0, 0, IEC958_AES3_CON_FS_48000, }; static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .reg_bits = 32, .reg_stride = 4, Loading Loading @@ -277,6 +294,11 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int slotr, slotr_mask, slot_size; if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { dev_warn(cpu_dai->dev, "Slot setting relevant only for TDM\n"); return 0; } dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n", tx_mask, rx_mask, slots, slot_width); Loading Loading @@ -326,8 +348,17 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) dev_dbg(cpu_dai->dev, "fmt %x\n", fmt); cr1_mask = SAI_XCR1_PRTCFG_MASK; cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); /* Do not generate master by default */ cr1 = SAI_XCR1_NODIV; cr1_mask = SAI_XCR1_NODIV; cr1_mask |= SAI_XCR1_PRTCFG_MASK; if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { cr1 |= SAI_XCR1_PRTCFG_SET(SAI_SPDIF_PROTOCOL); goto conf_update; } cr1 |= SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { /* SCK active high for all protocols */ Loading Loading @@ -409,10 +440,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) cr1_mask |= SAI_XCR1_SLAVE; /* do not generate master by default */ cr1 |= SAI_XCR1_NODIV; cr1_mask |= SAI_XCR1_NODIV; conf_update: ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); if (ret < 0) { dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); Loading Loading @@ -478,6 +506,12 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { sai->spdif_frm_cnt = 0; return 0; } /* Mode, data format and channel config */ cr1_mask = SAI_XCR1_DS_MASK; switch (params_format(params)) { Loading Loading @@ -592,13 +626,14 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, int cr1, mask, div = 0; int sai_clk_rate, mclk_ratio, den, ret; int version = sai->pdata->conf->version; unsigned int rate = params_rate(params); if (!sai->mclk_rate) { dev_err(cpu_dai->dev, "Mclk rate is null\n"); return -EINVAL; } if (!(params_rate(params) % 11025)) if (!(rate % 11025)) clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k); else clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k); Loading @@ -623,26 +658,30 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, * MCKDIV = sai_ck / (frl x ws) (NOMCK=1) * Note: NOMCK/NODIV correspond to same bit. */ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { div = DIV_ROUND_CLOSEST(sai_clk_rate, (params_rate(params) * 128)); } else { if (sai->mclk_rate) { mclk_ratio = sai->mclk_rate / params_rate(params); if (mclk_ratio != 256) { mclk_ratio = sai->mclk_rate / rate; if (mclk_ratio == 512) { mask = SAI_XCR1_OSR; cr1 = SAI_XCR1_OSR; } else { } else if (mclk_ratio != 256) { dev_err(cpu_dai->dev, "Wrong mclk ratio %d\n", mclk_ratio); return -EINVAL; } } div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate); div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate); } else { /* mclk-fs not set, master clock not active. NOMCK=1 */ /* mclk-fs not set, master clock not active */ den = sai->fs_length * params_rate(params); div = DIV_ROUND_CLOSEST(sai_clk_rate, den); } } } if (div > SAI_XCR1_MCKDIV_MAX(version)) { dev_err(cpu_dai->dev, "Divider %d out of range\n", div); Loading Loading @@ -670,10 +709,12 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream, sai->data_size = params_width(params); if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) { ret = stm32_sai_set_slots(cpu_dai); if (ret < 0) return ret; stm32_sai_set_frame(cpu_dai); } ret = stm32_sai_set_config(cpu_dai, substream, params); if (ret) Loading Loading @@ -723,6 +764,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, (unsigned int)~SAI_XCR1_DMAEN); if (ret < 0) dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) sai->spdif_frm_cnt = 0; break; default: return -EINVAL; Loading Loading @@ -776,6 +820,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) sai->synco, sai->synci); } if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) memcpy(sai->spdif_status_bits, default_status_bits, sizeof(default_status_bits)); cr1_mask |= SAI_XCR1_SYNCEN_MASK; cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync); Loading @@ -792,6 +840,42 @@ static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { .shutdown = stm32_sai_shutdown, }; static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream, int channel, unsigned long hwoff, void *buf, unsigned long bytes) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); int *ptr = (int *)(runtime->dma_area + hwoff + channel * (runtime->dma_bytes / runtime->channels)); ssize_t cnt = bytes_to_samples(runtime, bytes); unsigned int frm_cnt = sai->spdif_frm_cnt; unsigned int byte; unsigned int mask; do { *ptr = ((*ptr >> 8) & 0x00ffffff); /* Set channel status bit */ byte = frm_cnt >> 3; mask = 1 << (frm_cnt - (byte << 3)); if (sai->spdif_status_bits[byte] & mask) *ptr |= 0x04000000; ptr++; if (!(cnt % 2)) frm_cnt++; if (frm_cnt == SAI_IEC60958_BLOCK_FRAMES) frm_cnt = 0; } while (--cnt); sai->spdif_frm_cnt = frm_cnt; return 0; } static const struct snd_pcm_hardware stm32_sai_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, .buffer_bytes_max = 8 * PAGE_SIZE, Loading Loading @@ -846,6 +930,12 @@ static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, }; static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config_spdif = { .pcm_hardware = &stm32_sai_pcm_hw, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, .process = stm32_sai_pcm_process_spdif, }; static const struct snd_soc_component_driver stm32_component = { .name = "stm32-sai", }; Loading Loading @@ -900,6 +990,18 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return -EINVAL; } /* Get spdif iec60958 property */ sai->spdif = false; if (of_get_property(np, "st,iec60958", NULL)) { if (!STM_SAI_HAS_SPDIF(sai) || sai->dir == SNDRV_PCM_STREAM_CAPTURE) { dev_err(&pdev->dev, "S/PDIF IEC60958 not supported\n"); return -EINVAL; } sai->spdif = true; sai->master = true; } /* Get synchronization property */ args.np = NULL; ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args); Loading Loading @@ -999,6 +1101,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) { struct stm32_sai_sub_data *sai; const struct of_device_id *of_id; const struct snd_dmaengine_pcm_config *conf = &stm32_sai_pcm_config; int ret; sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); Loading Loading @@ -1039,8 +1142,10 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) if (ret) return ret; ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &stm32_sai_pcm_config, 0); if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) conf = &stm32_sai_pcm_config_spdif; ret = devm_snd_dmaengine_pcm_register(&pdev->dev, conf, 0); if (ret) { dev_err(&pdev->dev, "Could not register pcm dma\n"); return ret; Loading