diff options
Diffstat (limited to 'sound/soc/mediatek/common')
-rw-r--r-- | sound/soc/mediatek/common/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-afe-fe-dai.c | 79 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-afe-platform-driver.c | 4 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-base-afe.h | 30 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-btcvsd.c | 66 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-dsp-sof-common.c | 275 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-dsp-sof-common.h | 44 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-soc-card.h | 17 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-soundcard-driver.c | 134 | ||||
-rw-r--r-- | sound/soc/mediatek/common/mtk-soundcard-driver.h | 14 |
10 files changed, 600 insertions, 65 deletions
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile index acbe01e9e928..42e636c10c1e 100644 --- a/sound/soc/mediatek/common/Makefile +++ b/sound/soc/mediatek/common/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # platform driver -snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o +snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o mtk-soundcard-driver.o obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index 882cdf86c8bf..3044d9ab3d4d 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -37,10 +37,10 @@ static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) int mtk_afe_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct snd_pcm_runtime *runtime = substream->runtime; - int memif_num = asoc_rtd_to_cpu(rtd, 0)->id; + int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; int ret; @@ -98,9 +98,9 @@ EXPORT_SYMBOL_GPL(mtk_afe_fe_startup); void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id]; + struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id]; int irq_id; irq_id = memif->irq_usage; @@ -120,9 +120,9 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - int id = asoc_rtd_to_cpu(rtd, 0)->id; + int id = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[id]; int ret; unsigned int channels = params_channels(params); @@ -139,7 +139,7 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, substream->runtime->dma_area, substream->runtime->dma_bytes); - memset_io(substream->runtime->dma_area, 0, + memset_io((void __force __iomem *)substream->runtime->dma_area, 0, substream->runtime->dma_bytes); /* set addr */ @@ -196,10 +196,10 @@ EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free); int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime * const runtime = substream->runtime; struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - int id = asoc_rtd_to_cpu(rtd, 0)->id; + int id = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[id]; struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; const struct mtk_base_irq_data *irq_data = irqs->irq_data; @@ -263,9 +263,9 @@ EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger); int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - int id = asoc_rtd_to_cpu(rtd, 0)->id; + int id = snd_soc_rtd_to_cpu(rtd, 0)->id; int pbuf_size; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -288,7 +288,6 @@ const struct snd_soc_dai_ops mtk_afe_fe_ops = { }; EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); -static DEFINE_MUTEX(irqs_lock); int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) { int i; @@ -334,9 +333,11 @@ int mtk_afe_suspend(struct snd_soc_component *component) devm_kcalloc(dev, afe->reg_back_up_list_num, sizeof(unsigned int), GFP_KERNEL); - for (i = 0; i < afe->reg_back_up_list_num; i++) - regmap_read(regmap, afe->reg_back_up_list[i], - &afe->reg_back_up[i]); + if (afe->reg_back_up) { + for (i = 0; i < afe->reg_back_up_list_num; i++) + regmap_read(regmap, afe->reg_back_up_list[i], + &afe->reg_back_up[i]); + } afe->suspended = true; afe->runtime_suspend(dev); @@ -349,19 +350,20 @@ int mtk_afe_resume(struct snd_soc_component *component) struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); struct device *dev = afe->dev; struct regmap *regmap = afe->regmap; - int i = 0; + int i; if (pm_runtime_status_suspended(dev) || !afe->suspended) return 0; afe->runtime_resume(dev); - if (!afe->reg_back_up) + if (!afe->reg_back_up) { dev_dbg(dev, "%s no reg_backup\n", __func__); - - for (i = 0; i < afe->reg_back_up_list_num; i++) - mtk_regmap_write(regmap, afe->reg_back_up_list[i], - afe->reg_back_up[i]); + } else { + for (i = 0; i < afe->reg_back_up_list_num; i++) + mtk_regmap_write(regmap, afe->reg_back_up_list[i], + afe->reg_back_up[i]); + } afe->suspended = false; return 0; @@ -433,11 +435,20 @@ int mtk_memif_set_addr(struct mtk_base_afe *afe, int id, phys_buf_addr_upper_32); } - /* set MSB to 33-bit */ - if (memif->data->msb_reg >= 0) + /* + * set MSB to 33-bit, for memif address + * only for memif base address, if msb_end_reg exists + */ + if (memif->data->msb_reg) mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, 1, msb_at_bit33, memif->data->msb_shift); + /* set MSB to 33-bit, for memif end address */ + if (memif->data->msb_end_reg) + mtk_regmap_update_bits(afe->regmap, memif->data->msb_end_reg, + 1, msb_at_bit33, + memif->data->msb_end_shift); + return 0; } EXPORT_SYMBOL_GPL(mtk_memif_set_addr); @@ -464,6 +475,13 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe, else mono = (channel == 1) ? 1 : 0; + /* for specific configuration of memif mono mode */ + if (memif->data->int_odd_flag_reg) + mtk_regmap_update_bits(afe->regmap, + memif->data->int_odd_flag_reg, + 1, mono, + memif->data->int_odd_flag_shift); + return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, 1, mono, memif->data->mono_shift); } @@ -505,7 +523,7 @@ EXPORT_SYMBOL_GPL(mtk_memif_set_rate); int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, int id, unsigned int rate) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); @@ -542,8 +560,13 @@ int mtk_memif_set_format(struct mtk_base_afe *afe, break; case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_U32_LE: - hd_audio = 1; - hd_align = 1; + if (afe->memif_32bit_supported) { + hd_audio = 2; + hd_align = 0; + } else { + hd_audio = 1; + hd_align = 1; + } break; case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_U24_LE: @@ -556,10 +579,10 @@ int mtk_memif_set_format(struct mtk_base_afe *afe, } mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, - 1, hd_audio, memif->data->hd_shift); + 0x3, hd_audio, memif->data->hd_shift); mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg, - 1, hd_align, memif->data->hd_align_mshift); + 0x1, hd_align, memif->data->hd_align_mshift); return 0; } diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c index 01501d5747a7..32edcb6d5219 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c @@ -80,9 +80,9 @@ EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control); snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); - struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id]; + struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id]; const struct mtk_base_memif_data *memif_data = memif->data; struct regmap *regmap = afe->regmap; struct device *dev = afe->dev; diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h index a8cf44d98244..f51578b6c50a 100644 --- a/sound/soc/mediatek/common/mtk-base-afe.h +++ b/sound/soc/mediatek/common/mtk-base-afe.h @@ -9,7 +9,26 @@ #ifndef _MTK_BASE_AFE_H_ #define _MTK_BASE_AFE_H_ +#include <linux/soc/mediatek/mtk_sip_svc.h> + #define MTK_STREAM_NUM (SNDRV_PCM_STREAM_LAST + 1) +#define MTK_SIP_AUDIO_CONTROL MTK_SIP_SMC_CMD(0x517) + +/* SMC CALL Operations */ +enum mtk_audio_smc_call_op { + MTK_AUDIO_SMC_OP_INIT = 0, + MTK_AUDIO_SMC_OP_DRAM_REQUEST, + MTK_AUDIO_SMC_OP_DRAM_RELEASE, + MTK_AUDIO_SMC_OP_SRAM_REQUEST, + MTK_AUDIO_SMC_OP_SRAM_RELEASE, + MTK_AUDIO_SMC_OP_ADSP_REQUEST, + MTK_AUDIO_SMC_OP_ADSP_RELEASE, + MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS, + MTK_AUDIO_SMC_OP_BTCVSD_WRITE, + MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_CLEAR, + MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_UNDERFLOW, + MTK_AUDIO_SMC_OP_NUM +}; struct mtk_base_memif_data { int id; @@ -29,6 +48,8 @@ struct mtk_base_memif_data { int quad_ch_reg; int quad_ch_mask; int quad_ch_shift; + int int_odd_flag_reg; + int int_odd_flag_shift; int enable_reg; int enable_shift; int hd_reg; @@ -37,10 +58,13 @@ struct mtk_base_memif_data { int hd_align_mshift; int msb_reg; int msb_shift; - int msb2_reg; - int msb2_shift; + int msb_end_reg; + int msb_end_shift; int agent_disable_reg; int agent_disable_shift; + int ch_num_reg; + int ch_num_shift; + int ch_num_maskbit; /* playback memif only */ int pbuf_reg; int pbuf_mask; @@ -62,6 +86,7 @@ struct mtk_base_irq_data { int irq_en_shift; int irq_clr_reg; int irq_clr_shift; + int irq_status_shift; }; struct device; @@ -91,6 +116,7 @@ struct mtk_base_afe { int memif_size; struct mtk_base_afe_irq *irqs; int irqs_size; + int memif_32bit_supported; struct list_head sub_dais; struct snd_soc_dai_driver *dai_drivers; diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index 668fef3e319a..c12d170fa1de 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -696,11 +696,10 @@ static int wait_for_bt_irq(struct mtk_btcvsd_snd *bt, } static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, - char __user *buf, + struct iov_iter *buf, size_t count) { ssize_t read_size = 0, read_count = 0, cur_read_idx, cont; - unsigned int cur_buf_ofs = 0; unsigned long avail; unsigned long flags; unsigned int packet_size = bt->rx->packet_size; @@ -743,10 +742,9 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, if (read_size > cont) read_size = cont; - if (copy_to_user(buf + cur_buf_ofs, - bt->rx_packet_buf + cur_read_idx, - read_size)) { - dev_warn(bt->dev, "%s(), copy_to_user fail\n", + if (copy_to_iter(bt->rx_packet_buf + cur_read_idx, + read_size, buf) != read_size) { + dev_warn(bt->dev, "%s(), copy_to_iter fail\n", __func__); return -EFAULT; } @@ -756,7 +754,6 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, spin_unlock_irqrestore(&bt->rx_lock, flags); read_count += read_size; - cur_buf_ofs += read_size; count -= read_size; } @@ -777,11 +774,10 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, } static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, - char __user *buf, + struct iov_iter *buf, size_t count) { - int written_size = count, avail = 0, cur_write_idx, write_size, cont; - unsigned int cur_buf_ofs = 0; + int written_size = count, avail, cur_write_idx, write_size, cont; unsigned long flags; unsigned int packet_size = bt->tx->packet_size; @@ -808,7 +804,7 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, spin_unlock_irqrestore(&bt->tx_lock, flags); if (!avail) { - int ret = wait_for_bt_irq(bt, bt->rx); + int ret = wait_for_bt_irq(bt, bt->tx); if (ret) return written_size; @@ -835,11 +831,9 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, if (write_size > cont) write_size = cont; - if (copy_from_user(bt->tx_packet_buf + - cur_write_idx, - buf + cur_buf_ofs, - write_size)) { - dev_warn(bt->dev, "%s(), copy_from_user fail\n", + if (copy_from_iter(bt->tx_packet_buf + cur_write_idx, + write_size, buf) != write_size) { + dev_warn(bt->dev, "%s(), copy_from_iter fail\n", __func__); return -EFAULT; } @@ -847,7 +841,6 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, spin_lock_irqsave(&bt->tx_lock, flags); bt->tx->packet_w += write_size / packet_size; spin_unlock_irqrestore(&bt->tx_lock, flags); - cur_buf_ofs += write_size; count -= write_size; } @@ -1033,16 +1026,14 @@ static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer( static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component, struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *buf, unsigned long count) + struct iov_iter *buf, unsigned long count) { struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - mtk_btcvsd_snd_write(bt, buf, count); + return mtk_btcvsd_snd_write(bt, buf, count); else - mtk_btcvsd_snd_read(bt, buf, count); - - return 0; + return mtk_btcvsd_snd_read(bt, buf, count); } /* kcontrol */ @@ -1276,12 +1267,12 @@ static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = { .prepare = mtk_pcm_btcvsd_prepare, .trigger = mtk_pcm_btcvsd_trigger, .pointer = mtk_pcm_btcvsd_pointer, - .copy_user = mtk_pcm_btcvsd_copy, + .copy = mtk_pcm_btcvsd_copy, }; static int mtk_btcvsd_snd_probe(struct platform_device *pdev) { - int ret = 0; + int ret; int irq_id; u32 offset[5] = {0, 0, 0, 0, 0}; struct mtk_btcvsd_snd *btcvsd; @@ -1337,7 +1328,8 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) btcvsd->bt_sram_bank2_base = of_iomap(dev->of_node, 1); if (!btcvsd->bt_sram_bank2_base) { dev_err(dev, "iomap bt_sram_bank2_base fail\n"); - return -EIO; + ret = -EIO; + goto unmap_pkv_err; } btcvsd->infra = syscon_regmap_lookup_by_phandle(dev->of_node, @@ -1345,7 +1337,8 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) if (IS_ERR(btcvsd->infra)) { dev_err(dev, "cannot find infra controller: %ld\n", PTR_ERR(btcvsd->infra)); - return PTR_ERR(btcvsd->infra); + ret = PTR_ERR(btcvsd->infra); + goto unmap_bank2_err; } /* get offset */ @@ -1354,7 +1347,7 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) ARRAY_SIZE(offset)); if (ret) { dev_warn(dev, "%s(), get offset fail, ret %d\n", __func__, ret); - return ret; + goto unmap_bank2_err; } btcvsd->infra_misc_offset = offset[0]; btcvsd->conn_bt_cvsd_mask = offset[1]; @@ -1373,17 +1366,26 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) mtk_btcvsd_snd_set_state(btcvsd, btcvsd->tx, BT_SCO_STATE_IDLE); mtk_btcvsd_snd_set_state(btcvsd, btcvsd->rx, BT_SCO_STATE_IDLE); - return devm_snd_soc_register_component(dev, &mtk_btcvsd_snd_platform, - NULL, 0); + ret = devm_snd_soc_register_component(dev, &mtk_btcvsd_snd_platform, + NULL, 0); + if (ret) + goto unmap_bank2_err; + + return 0; + +unmap_bank2_err: + iounmap(btcvsd->bt_sram_bank2_base); +unmap_pkv_err: + iounmap(btcvsd->bt_pkv_base); + return ret; } -static int mtk_btcvsd_snd_remove(struct platform_device *pdev) +static void mtk_btcvsd_snd_remove(struct platform_device *pdev) { struct mtk_btcvsd_snd *btcvsd = dev_get_drvdata(&pdev->dev); iounmap(btcvsd->bt_pkv_base); iounmap(btcvsd->bt_sram_bank2_base); - return 0; } static const struct of_device_id mtk_btcvsd_snd_dt_match[] = { @@ -1398,7 +1400,7 @@ static struct platform_driver mtk_btcvsd_snd_driver = { .of_match_table = mtk_btcvsd_snd_dt_match, }, .probe = mtk_btcvsd_snd_probe, - .remove = mtk_btcvsd_snd_remove, + .remove_new = mtk_btcvsd_snd_remove, }; module_platform_driver(mtk_btcvsd_snd_driver); diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c new file mode 100644 index 000000000000..7ec8965a70c0 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mtk-dsp-sof-common.c -- MediaTek dsp sof common ctrl + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Chunxu Li <chunxu.li@mediatek.com> + */ + +#include "mtk-dsp-sof-common.h" +#include "mtk-soc-card.h" + +/* fixup the BE DAI link to match any values from topology */ +int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_card *card = rtd->card; + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + int i, j, ret = 0; + + for (i = 0; i < sof_priv->num_streams; i++) { + struct snd_soc_dai *cpu_dai; + struct snd_soc_pcm_runtime *runtime; + struct snd_soc_dai_link *sof_dai_link = NULL; + const struct sof_conn_stream *conn = &sof_priv->conn_streams[i]; + + if (conn->normal_link && strcmp(rtd->dai_link->name, conn->normal_link)) + continue; + + for_each_card_rtds(card, runtime) { + if (strcmp(runtime->dai_link->name, conn->sof_link)) + continue; + + for_each_rtd_cpu_dais(runtime, j, cpu_dai) { + if (snd_soc_dai_stream_active(cpu_dai, conn->stream_dir) > 0) { + sof_dai_link = runtime->dai_link; + break; + } + } + break; + } + + if (sof_dai_link && sof_dai_link->be_hw_params_fixup) + ret = sof_dai_link->be_hw_params_fixup(runtime, params); + + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mtk_sof_dai_link_fixup); + +int mtk_sof_card_probe(struct snd_soc_card *card) +{ + int i; + struct snd_soc_dai_link *dai_link; + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + + /* Set stream_name to help sof bind widgets */ + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->no_pcm && !dai_link->stream_name && dai_link->name) + dai_link->stream_name = dai_link->name; + } + + INIT_LIST_HEAD(&sof_priv->dai_link_list); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_sof_card_probe); + +static struct snd_soc_pcm_runtime *mtk_sof_find_tplg_be(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + struct snd_soc_pcm_runtime *fe; + struct snd_soc_pcm_runtime *be; + struct snd_soc_dpcm *dpcm; + int i, stream; + + for_each_pcm_streams(stream) { + fe = NULL; + for_each_dpcm_fe(rtd, stream, dpcm) { + fe = dpcm->fe; + if (fe) + break; + } + + if (!fe) + continue; + + for_each_dpcm_be(fe, stream, dpcm) { + be = dpcm->be; + if (be == rtd) + continue; + + for (i = 0; i < sof_priv->num_streams; i++) { + const struct sof_conn_stream *conn = &sof_priv->conn_streams[i]; + + if (!strcmp(be->dai_link->name, conn->sof_link)) + return be; + } + } + } + + return NULL; +} + +/* fixup the BE DAI link to match any values from topology */ +static int mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_card *card = rtd->card; + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + struct snd_soc_pcm_runtime *sof_be; + struct mtk_dai_link *dai_link; + int ret = 0; + + sof_be = mtk_sof_find_tplg_be(rtd); + if (sof_be) { + if (sof_priv->sof_dai_link_fixup) + ret = sof_priv->sof_dai_link_fixup(rtd, params); + else if (sof_be->dai_link->be_hw_params_fixup) + ret = sof_be->dai_link->be_hw_params_fixup(sof_be, params); + } else { + list_for_each_entry(dai_link, &sof_priv->dai_link_list, list) { + if (strcmp(dai_link->name, rtd->dai_link->name) == 0) { + if (dai_link->be_hw_params_fixup) + ret = dai_link->be_hw_params_fixup(rtd, params); + + break; + } + } + } + + return ret; +} + +int mtk_sof_card_late_probe(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *sof_comp = NULL; + struct mtk_soc_card_data *soc_card_data = + snd_soc_card_get_drvdata(card); + struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; + struct snd_soc_dai_link *dai_link; + struct mtk_dai_link *mtk_dai_link; + int i; + + /* 1. find sof component */ + for_each_card_rtds(card, rtd) { + sof_comp = snd_soc_rtdcom_lookup(rtd, "sof-audio-component"); + if (sof_comp) + break; + } + + if (!sof_comp) { + dev_info(card->dev, "probe without sof-audio-component\n"); + return 0; + } + + /* 2. overwrite all BE fixups, and backup the existing fixup */ + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->be_hw_params_fixup) { + mtk_dai_link = devm_kzalloc(card->dev, + sizeof(*mtk_dai_link), + GFP_KERNEL); + if (!mtk_dai_link) + return -ENOMEM; + + mtk_dai_link->be_hw_params_fixup = dai_link->be_hw_params_fixup; + mtk_dai_link->name = dai_link->name; + + list_add(&mtk_dai_link->list, &sof_priv->dai_link_list); + } + + if (dai_link->no_pcm) + dai_link->be_hw_params_fixup = mtk_sof_check_tplg_be_dai_link_fixup; + } + + /* 3. add route path and SOF_BE fixup callback */ + for (i = 0; i < sof_priv->num_streams; i++) { + const struct sof_conn_stream *conn = &sof_priv->conn_streams[i]; + struct snd_soc_pcm_runtime *sof_rtd = NULL; + + for_each_card_rtds(card, rtd) { + if (!strcmp(rtd->dai_link->name, conn->sof_link)) { + sof_rtd = rtd; + break; + } + } + if (sof_rtd) { + int j; + struct snd_soc_dai *cpu_dai; + + for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) { + struct snd_soc_dapm_route route; + struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_widget *widget = snd_soc_dai_get_widget(cpu_dai, conn->stream_dir); + + memset(&route, 0, sizeof(route)); + if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && widget) { + snd_soc_dapm_widget_for_each_sink_path(widget, p) { + route.source = conn->sof_dma; + route.sink = p->sink->name; + snd_soc_dapm_add_routes(&card->dapm, &route, 1); + } + } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && widget) { + snd_soc_dapm_widget_for_each_source_path(widget, p) { + route.source = p->source->name; + route.sink = conn->sof_dma; + snd_soc_dapm_add_routes(&card->dapm, &route, 1); + } + } else { + dev_err(cpu_dai->dev, "stream dir and widget not pair\n"); + } + } + + /* overwrite SOF BE fixup */ + sof_rtd->dai_link->be_hw_params_fixup = + sof_comp->driver->be_hw_params_fixup; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe); + +int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, + const char *propname, struct snd_soc_dai_link *pre_dai_links, + int pre_num_links) +{ + struct device *dev = card->dev; + struct snd_soc_dai_link *parsed_dai_link; + const char *dai_name = NULL; + int i, j, ret, num_links, parsed_num_links = 0; + + num_links = of_property_count_strings(np, "mediatek,dai-link"); + if (num_links < 0 || num_links > card->num_links) { + dev_dbg(dev, "number of dai-link is invalid\n"); + return -EINVAL; + } + + parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL); + if (!parsed_dai_link) + return -ENOMEM; + + for (i = 0; i < num_links; i++) { + ret = of_property_read_string_index(np, propname, i, &dai_name); + if (ret) { + dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n", + propname, i, ret); + return ret; + } + dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name); + for (j = 0; j < pre_num_links; j++) { + if (!strcmp(dai_name, pre_dai_links[j].name)) { + memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j], + sizeof(struct snd_soc_dai_link)); + break; + } + } + } + + if (parsed_num_links != num_links) + return -EINVAL; + + card->dai_link = parsed_dai_link; + card->num_links = parsed_num_links; + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of); diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.h b/sound/soc/mediatek/common/mtk-dsp-sof-common.h new file mode 100644 index 000000000000..4bc5e1c0c8ed --- /dev/null +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mtk-dsp-sof-common.h -- MediaTek dsp sof common definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Chunxu Li <chunxu.li@mediatek.com> + */ + +#ifndef _MTK_DSP_SOF_COMMON_H_ +#define _MTK_DSP_SOF_COMMON_H_ + +#include <sound/soc.h> + +struct sof_conn_stream { + const char *normal_link; + const char *sof_link; + const char *sof_dma; + int stream_dir; +}; + +struct mtk_dai_link { + const char *name; + int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); + struct list_head list; +}; + +struct mtk_sof_priv { + const struct sof_conn_stream *conn_streams; + int num_streams; + int (*sof_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); + struct list_head dai_link_list; +}; + +int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); +int mtk_sof_card_probe(struct snd_soc_card *card); +int mtk_sof_card_late_probe(struct snd_soc_card *card); +int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, + const char *propname, struct snd_soc_dai_link *pre_dai_links, + int pre_num_links); + +#endif diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h new file mode 100644 index 000000000000..eeda79370049 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-soc-card.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mtk-soc-card.h -- MediaTek soc card data definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Chunxu Li <chunxu.li@mediatek.com> + */ + +#ifndef _MTK_SOC_CARD_H_ +#define _MTK_SOC_CARD_H_ + +struct mtk_soc_card_data { + void *mach_priv; + void *sof_priv; +}; + +#endif diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c new file mode 100644 index 000000000000..a58e1e3674de --- /dev/null +++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mtk-soundcard-driver.c -- MediaTek soundcard driver common + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Trevor Wu <trevor.wu@mediatek.com> + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <sound/soc.h> + +#include "mtk-soundcard-driver.h" + +static int set_card_codec_info(struct snd_soc_card *card, + struct device_node *sub_node, + struct snd_soc_dai_link *dai_link) +{ + struct device *dev = card->dev; + struct device_node *codec_node; + int ret; + + codec_node = of_get_child_by_name(sub_node, "codec"); + if (!codec_node) { + dev_dbg(dev, "%s no specified codec\n", dai_link->name); + return 0; + } + + /* set card codec info */ + ret = snd_soc_of_get_dai_link_codecs(dev, codec_node, dai_link); + + of_node_put(codec_node); + + if (ret < 0) + return dev_err_probe(dev, ret, "%s: codec dai not found\n", + dai_link->name); + + return 0; +} + +static int set_dailink_daifmt(struct snd_soc_card *card, + struct device_node *sub_node, + struct snd_soc_dai_link *dai_link) +{ + unsigned int daifmt; + const char *str; + int ret; + struct { + char *name; + unsigned int val; + } of_clk_table[] = { + { "cpu", SND_SOC_DAIFMT_CBC_CFC }, + { "codec", SND_SOC_DAIFMT_CBP_CFP }, + }; + + daifmt = snd_soc_daifmt_parse_format(sub_node, NULL); + if (daifmt) { + dai_link->dai_fmt &= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + dai_link->dai_fmt |= daifmt; + } + + /* + * check "mediatek,clk-provider = xxx" + * SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK area + */ + ret = of_property_read_string(sub_node, "mediatek,clk-provider", &str); + if (ret == 0) { + int i; + + for (i = 0; i < ARRAY_SIZE(of_clk_table); i++) { + if (strcmp(str, of_clk_table[i].name) == 0) { + dai_link->dai_fmt &= ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + dai_link->dai_fmt |= of_clk_table[i].val; + break; + } + } + } + + return 0; +} + +int parse_dai_link_info(struct snd_soc_card *card) +{ + struct device *dev = card->dev; + struct device_node *sub_node; + struct snd_soc_dai_link *dai_link; + const char *dai_link_name; + int ret, i; + + /* Loop over all the dai link sub nodes */ + for_each_available_child_of_node(dev->of_node, sub_node) { + if (of_property_read_string(sub_node, "link-name", + &dai_link_name)) { + of_node_put(sub_node); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (!strcmp(dai_link_name, dai_link->name)) + break; + } + + if (i >= card->num_links) { + of_node_put(sub_node); + return -EINVAL; + } + + ret = set_card_codec_info(card, sub_node, dai_link); + if (ret < 0) { + of_node_put(sub_node); + return ret; + } + + ret = set_dailink_daifmt(card, sub_node, dai_link); + if (ret < 0) { + of_node_put(sub_node); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(parse_dai_link_info); + +void clean_card_reference(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + int i; + + /* release codec reference gotten by set_card_codec_info */ + for_each_card_prelinks(card, i, dai_link) + snd_soc_of_put_dai_link_codecs(dai_link); +} +EXPORT_SYMBOL_GPL(clean_card_reference); diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.h b/sound/soc/mediatek/common/mtk-soundcard-driver.h new file mode 100644 index 000000000000..d92cac1d7b72 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-soundcard-driver.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mtk-soundcard-driver.h -- MediaTek soundcard driver common definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Trevor Wu <trevor.wu@mediatek.com> + */ + +#ifndef _MTK_SOUNDCARD_DRIVER_H_ +#define _MTK_SOUNDCARD_DRIVER_H_ + +int parse_dai_link_info(struct snd_soc_card *card); +void clean_card_reference(struct snd_soc_card *card); +#endif |