From 14bc87cf7658c0a6c4891aba5890f2fafaab2a8e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 26 Sep 2025 04:52:36 +0200 Subject: [PATCH] airoha: en7581: Add pending ASOC driver Add pending ASOC driver for I2S sound support on Airoha EN7581 SoC. Signed-off-by: Christian Marangi --- ...k-move-some-header-to-global-include.patch | 410 ++++++++++ ...AFE-and-I2S-driver-for-Airoha-AN7581.patch | 729 ++++++++++++++++++ 2 files changed, 1139 insertions(+) create mode 100644 target/linux/airoha/patches-6.12/123-01-ASoC-mediatek-move-some-header-to-global-include.patch create mode 100644 target/linux/airoha/patches-6.12/123-02-ASoC-airoha-Add-AFE-and-I2S-driver-for-Airoha-AN7581.patch diff --git a/target/linux/airoha/patches-6.12/123-01-ASoC-mediatek-move-some-header-to-global-include.patch b/target/linux/airoha/patches-6.12/123-01-ASoC-mediatek-move-some-header-to-global-include.patch new file mode 100644 index 0000000000..c9cdb9a326 --- /dev/null +++ b/target/linux/airoha/patches-6.12/123-01-ASoC-mediatek-move-some-header-to-global-include.patch @@ -0,0 +1,410 @@ +From 527123b53739a2f73ca924b9c6e2f63dc66739a5 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Fri, 1 Aug 2025 11:06:56 +0200 +Subject: [PATCH 1/3] ASoC: mediatek: move some header to global include + +In preparation for support of Airoha SoC sound system based on Mediatek +AFE, move some header to global include to prevent having to use complex +redirection for inclusion. + +Signed-off-by: Christian Marangi +--- + .../common => include/sound/mediatek}/mtk-afe-fe-dai.h | 0 + .../sound/mediatek}/mtk-afe-platform-driver.h | 0 + sound/soc/mediatek/common/mtk-afe-fe-dai.c | 4 ++-- + sound/soc/mediatek/common/mtk-afe-platform-driver.c | 2 +- + sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt7986/mt7986-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 2 +- + sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 2 +- + sound/soc/mediatek/mt8186/mt8186-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt8186/mt8186-misc-control.c | 4 ++-- + sound/soc/mediatek/mt8186/mt8186-mt6366-common.c | 2 +- + sound/soc/mediatek/mt8186/mt8186-mt6366.c | 2 +- + sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt8188/mt8188-mt6359.c | 2 +- + sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 2 +- + sound/soc/mediatek/mt8195/mt8195-afe-pcm.c | 4 ++-- + sound/soc/mediatek/mt8195/mt8195-mt6359.c | 2 +- + sound/soc/mediatek/mt8365/mt8365-afe-pcm.c | 4 ++-- + 22 files changed, 32 insertions(+), 32 deletions(-) + rename {sound/soc/mediatek/common => include/sound/mediatek}/mtk-afe-fe-dai.h (100%) + rename {sound/soc/mediatek/common => include/sound/mediatek}/mtk-afe-platform-driver.h (100%) + +--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c ++++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c +@@ -11,9 +11,9 @@ + #include + #include + #include +-#include "mtk-afe-platform-driver.h" ++#include + #include +-#include "mtk-afe-fe-dai.h" ++#include + #include "mtk-base-afe.h" + + #define AFE_BASE_END_OFFSET 8 +--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c ++++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c +@@ -10,7 +10,7 @@ + #include + #include + +-#include "mtk-afe-platform-driver.h" ++#include + #include "mtk-base-afe.h" + + int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe) +--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c ++++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +@@ -16,8 +16,8 @@ + + #include "mt2701-afe-common.h" + #include "mt2701-afe-clock-ctrl.h" +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + static const struct snd_pcm_hardware mt2701_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED +--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c ++++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +@@ -16,8 +16,8 @@ + #include "mt6797-afe-clk.h" + #include "mt6797-interconnection.h" + #include "mt6797-reg.h" +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + enum { + MTK_AFE_RATE_8K = 0, +--- a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c ++++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c +@@ -16,8 +16,8 @@ + + #include "mt7986-afe-common.h" + #include "mt7986-reg.h" +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + enum { + MTK_AFE_RATE_8K = 0, +--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c ++++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +@@ -19,8 +19,8 @@ + #include + #include "mt8173-afe-common.h" + #include "../common/mtk-base-afe.h" +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + /***************************************************************************** + * R E G I S T E R D E F I N I T I O N +--- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c ++++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +@@ -18,8 +18,8 @@ + #include "mt8183-afe-clk.h" + #include "mt8183-interconnection.h" + #include "mt8183-reg.h" +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + enum { + MTK_AFE_RATE_8K = 0, +--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c ++++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +@@ -16,7 +16,7 @@ + + #include "../../codecs/da7219.h" + #include "../../codecs/rt1015.h" +-#include "../common/mtk-afe-platform-driver.h" ++#include + #include "mt8183-afe-common.h" + + #define DA7219_CODEC_DAI "da7219-hifi" +--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c ++++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +@@ -15,7 +15,7 @@ + + #include "../../codecs/rt1015.h" + #include "../../codecs/ts3a227e.h" +-#include "../common/mtk-afe-platform-driver.h" ++#include + #include "mt8183-afe-common.h" + + #define RT1015_CODEC_DAI "rt1015-aif" +--- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c ++++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c +@@ -15,8 +15,8 @@ + #include + #include + +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + #include "mt8186-afe-common.h" + #include "mt8186-afe-clk.h" +--- a/sound/soc/mediatek/mt8186/mt8186-misc-control.c ++++ b/sound/soc/mediatek/mt8186/mt8186-misc-control.c +@@ -11,8 +11,8 @@ + #include + #include + +-#include "../common/mtk-afe-fe-dai.h" +-#include "../common/mtk-afe-platform-driver.h" ++#include ++#include + #include "mt8186-afe-common.h" + + static const char * const mt8186_sgen_mode_str[] = { +--- a/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c ++++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c +@@ -9,7 +9,7 @@ + #include + + #include "../../codecs/mt6358.h" +-#include "../common/mtk-afe-platform-driver.h" ++#include + #include "mt8186-afe-common.h" + #include "mt8186-mt6366-common.h" + +--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c ++++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +@@ -24,8 +24,8 @@ + #include "mt8188-afe-common.h" + #include "mt8188-afe-clk.h" + #include "mt8188-reg.h" +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + #define MT8188_MEMIF_BUFFER_BYTES_ALIGN (0x40) + #define MT8188_MEMIF_DL7_MAX_PERIOD_SIZE (0x3fff) +--- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c ++++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +@@ -17,8 +17,8 @@ + #include + #include + +-#include "../common/mtk-afe-fe-dai.h" +-#include "../common/mtk-afe-platform-driver.h" ++#include ++#include + + #include "mt8192-afe-common.h" + #include "mt8192-afe-clk.h" +--- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c ++++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +@@ -20,8 +20,8 @@ + #include "mt8195-afe-common.h" + #include "mt8195-afe-clk.h" + #include "mt8195-reg.h" +-#include "../common/mtk-afe-platform-driver.h" +-#include "../common/mtk-afe-fe-dai.h" ++#include ++#include + + #define MT8195_MEMIF_BUFFER_BYTES_ALIGN (0x40) + #define MT8195_MEMIF_DL7_MAX_PERIOD_SIZE (0x3fff) +--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c ++++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c +@@ -19,7 +19,7 @@ + #include "../../codecs/mt6359.h" + #include "../../codecs/rt1011.h" + #include "../../codecs/rt5682.h" +-#include "../common/mtk-afe-platform-driver.h" ++#include + #include "../common/mtk-dsp-sof-common.h" + #include "../common/mtk-soc-card.h" + #include "../common/mtk-soundcard-driver.h" +--- /dev/null ++++ b/include/sound/mediatek/mtk-afe-fe-dai.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * mtk-afe-fe-dais.h -- Mediatek afe fe dai operator definition ++ * ++ * Copyright (c) 2016 MediaTek Inc. ++ * Author: Garlic Tseng ++ */ ++ ++#ifndef _MTK_AFE_FE_DAI_H_ ++#define _MTK_AFE_FE_DAI_H_ ++ ++struct snd_soc_dai_ops; ++struct mtk_base_afe; ++struct mtk_base_afe_memif; ++ ++int mtk_afe_fe_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai); ++void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai); ++int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai); ++int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai); ++int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai); ++int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai); ++ ++extern const struct snd_soc_dai_ops mtk_afe_fe_ops; ++ ++int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe); ++int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id); ++int mtk_afe_suspend(struct snd_soc_component *component); ++int mtk_afe_resume(struct snd_soc_component *component); ++ ++int mtk_memif_set_enable(struct mtk_base_afe *afe, int id); ++int mtk_memif_set_disable(struct mtk_base_afe *afe, int id); ++int mtk_memif_set_addr(struct mtk_base_afe *afe, int id, ++ unsigned char *dma_area, ++ dma_addr_t dma_addr, ++ size_t dma_bytes); ++int mtk_memif_set_channel(struct mtk_base_afe *afe, ++ int id, unsigned int channel); ++int mtk_memif_set_rate(struct mtk_base_afe *afe, ++ int id, unsigned int rate); ++int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, ++ int id, unsigned int rate); ++int mtk_memif_set_format(struct mtk_base_afe *afe, ++ int id, snd_pcm_format_t format); ++int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe, ++ int id, int pbuf_size); ++#endif +--- /dev/null ++++ b/include/sound/mediatek/mtk-afe-platform-driver.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * mtk-afe-platform-driver.h -- Mediatek afe platform driver definition ++ * ++ * Copyright (c) 2016 MediaTek Inc. ++ * Author: Garlic Tseng ++ */ ++ ++#ifndef _MTK_AFE_PLATFORM_DRIVER_H_ ++#define _MTK_AFE_PLATFORM_DRIVER_H_ ++ ++#define AFE_PCM_NAME "mtk-afe-pcm" ++extern const struct snd_soc_component_driver mtk_afe_pcm_platform; ++ ++struct mtk_base_afe; ++struct snd_pcm; ++struct snd_soc_component; ++struct snd_soc_pcm_runtime; ++ ++snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream); ++int mtk_afe_pcm_new(struct snd_soc_component *component, ++ struct snd_soc_pcm_runtime *rtd); ++ ++int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe); ++int mtk_afe_add_sub_dai_control(struct snd_soc_component *component); ++#endif ++ +--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h ++++ /dev/null +@@ -1,53 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * mtk-afe-fe-dais.h -- Mediatek afe fe dai operator definition +- * +- * Copyright (c) 2016 MediaTek Inc. +- * Author: Garlic Tseng +- */ +- +-#ifndef _MTK_AFE_FE_DAI_H_ +-#define _MTK_AFE_FE_DAI_H_ +- +-struct snd_soc_dai_ops; +-struct mtk_base_afe; +-struct mtk_base_afe_memif; +- +-int mtk_afe_fe_startup(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai); +-void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai); +-int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, +- struct snd_pcm_hw_params *params, +- struct snd_soc_dai *dai); +-int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai); +-int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai); +-int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, +- struct snd_soc_dai *dai); +- +-extern const struct snd_soc_dai_ops mtk_afe_fe_ops; +- +-int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe); +-int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id); +-int mtk_afe_suspend(struct snd_soc_component *component); +-int mtk_afe_resume(struct snd_soc_component *component); +- +-int mtk_memif_set_enable(struct mtk_base_afe *afe, int id); +-int mtk_memif_set_disable(struct mtk_base_afe *afe, int id); +-int mtk_memif_set_addr(struct mtk_base_afe *afe, int id, +- unsigned char *dma_area, +- dma_addr_t dma_addr, +- size_t dma_bytes); +-int mtk_memif_set_channel(struct mtk_base_afe *afe, +- int id, unsigned int channel); +-int mtk_memif_set_rate(struct mtk_base_afe *afe, +- int id, unsigned int rate); +-int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, +- int id, unsigned int rate); +-int mtk_memif_set_format(struct mtk_base_afe *afe, +- int id, snd_pcm_format_t format); +-int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe, +- int id, int pbuf_size); +-#endif +--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * mtk-afe-platform-driver.h -- Mediatek afe platform driver definition +- * +- * Copyright (c) 2016 MediaTek Inc. +- * Author: Garlic Tseng +- */ +- +-#ifndef _MTK_AFE_PLATFORM_DRIVER_H_ +-#define _MTK_AFE_PLATFORM_DRIVER_H_ +- +-#define AFE_PCM_NAME "mtk-afe-pcm" +-extern const struct snd_soc_component_driver mtk_afe_pcm_platform; +- +-struct mtk_base_afe; +-struct snd_pcm; +-struct snd_soc_component; +-struct snd_soc_pcm_runtime; +- +-snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, +- struct snd_pcm_substream *substream); +-int mtk_afe_pcm_new(struct snd_soc_component *component, +- struct snd_soc_pcm_runtime *rtd); +- +-int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe); +-int mtk_afe_add_sub_dai_control(struct snd_soc_component *component); +-#endif +- diff --git a/target/linux/airoha/patches-6.12/123-02-ASoC-airoha-Add-AFE-and-I2S-driver-for-Airoha-AN7581.patch b/target/linux/airoha/patches-6.12/123-02-ASoC-airoha-Add-AFE-and-I2S-driver-for-Airoha-AN7581.patch new file mode 100644 index 0000000000..00578601c4 --- /dev/null +++ b/target/linux/airoha/patches-6.12/123-02-ASoC-airoha-Add-AFE-and-I2S-driver-for-Airoha-AN7581.patch @@ -0,0 +1,729 @@ +From 9989af6ed0dba86f57ac4aa1574f9ce9b1e640af Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 31 Jul 2025 15:32:32 +0200 +Subject: [PATCH 2/3] ASoC: airoha: Add AFE and I2S driver for Airoha AN7581 + +Add support for the Sound system present on Airoha AN7581 SoC. This is +based on the mediatek AFE drivers. + +Also add the I2S driver to create an actual sound card for the AFE. + +Signed-off-by: Christian Marangi +--- + sound/soc/Kconfig | 1 + + sound/soc/Makefile | 1 + + sound/soc/airoha/Kconfig | 19 + + sound/soc/airoha/Makefile | 2 + + sound/soc/airoha/an7581/Makefile | 8 + + sound/soc/airoha/an7581/an7581-afe-common.h | 35 ++ + sound/soc/airoha/an7581/an7581-afe-pcm.c | 455 ++++++++++++++++++++ + sound/soc/airoha/an7581/an7581-i2s.c | 110 +++++ + sound/soc/airoha/an7581/an7581-reg.h | 29 ++ + 9 files changed, 660 insertions(+) + create mode 100644 sound/soc/airoha/Kconfig + create mode 100644 sound/soc/airoha/Makefile + create mode 100644 sound/soc/airoha/an7581/Makefile + create mode 100644 sound/soc/airoha/an7581/an7581-afe-common.h + create mode 100644 sound/soc/airoha/an7581/an7581-afe-pcm.c + create mode 100644 sound/soc/airoha/an7581/an7581-i2s.c + create mode 100644 sound/soc/airoha/an7581/an7581-reg.h + +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -86,6 +86,7 @@ config SND_SOC_ACPI + + # All the supported SoCs + source "sound/soc/adi/Kconfig" ++source "sound/soc/airoha/Kconfig" + source "sound/soc/amd/Kconfig" + source "sound/soc/apple/Kconfig" + source "sound/soc/atmel/Kconfig" +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -40,6 +40,7 @@ obj-$(CONFIG_SND_SOC) += codecs/ + obj-$(CONFIG_SND_SOC) += generic/ + obj-$(CONFIG_SND_SOC) += apple/ + obj-$(CONFIG_SND_SOC) += adi/ ++obj-$(CONFIG_SND_SOC) += airoha/ + obj-$(CONFIG_SND_SOC) += amd/ + obj-$(CONFIG_SND_SOC) += atmel/ + obj-$(CONFIG_SND_SOC) += au1x/ +--- /dev/null ++++ b/sound/soc/airoha/Kconfig +@@ -0,0 +1,19 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config SND_SOC_AN7581 ++ tristate "ASoC support for Airoha AN7581 chip" ++ depends on ARCH_AIROHA || COMPILE_TEST ++ select SND_SOC_MEDIATEK ++ help ++ This adds ASoC driver for Airoha AN7581 boards ++ that can be used with other codecs. ++ Select Y if you have such device. ++ If unsure select "N". ++ ++config SND_SOC_AN7581_I2S ++ tristate "I2S support for Airoha AN7581 chip" ++ depends on SND_SOC_AN7581 ++ help ++ This adds I2S driver for Airoha AN7581 boards ++ that can be used with other codecs. ++ Select Y if you have such device. ++ If unsure select "N". +--- /dev/null ++++ b/sound/soc/airoha/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_SND_SOC_AN7581) += an7581/ +--- /dev/null ++++ b/sound/soc/airoha/an7581/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++# platform driver ++snd-soc-an7581-afe-y := \ ++ an7581-afe-pcm.o ++ ++obj-$(CONFIG_SND_SOC_AN7581) += snd-soc-an7581-afe.o ++obj-$(CONFIG_SND_SOC_AN7581_I2S) += an7581-i2s.o +--- /dev/null ++++ b/sound/soc/airoha/an7581/an7581-afe-common.h +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * an7581-afe-common.h -- Airoha AN7581 audio driver definitions ++ */ ++ ++#ifndef _AN7581_AFE_COMMON_H_ ++#define _AN7581_AFE_COMMON_H_ ++ ++#include ++#include ++#include ++#include "../../mediatek/common/mtk-base-afe.h" ++ ++enum { ++ AN7581_MEMIF_DL1, ++ AN7581_MEMIF_UL1, ++ AN7581_MEMIF_NUM, ++ AN7581_DAI_NUM = AN7581_MEMIF_NUM, ++}; ++ ++enum { ++ AN7581_IRQ_0, ++ AN7581_IRQ_1, ++ AN7581_IRQ_NUM, ++}; ++ ++struct an7581_afe_private { ++ /* dai */ ++ void *dai_priv[AN7581_DAI_NUM]; ++}; ++ ++unsigned int an7581_afe_rate_transform(struct device *dev, ++ unsigned int rate); ++ ++#endif +--- /dev/null ++++ b/sound/soc/airoha/an7581/an7581-afe-pcm.c +@@ -0,0 +1,455 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Airoha ALSA SoC AFE platform driver for AN7581 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "an7581-afe-common.h" ++#include "an7581-reg.h" ++#include ++#include ++ ++enum { ++ ARH_AFE_RATE_7K = 16, ++ ARH_AFE_RATE_8K = 0, ++ ARH_AFE_RATE_11K = 17, ++ ARH_AFE_RATE_12K = 1, ++ ARH_AFE_RATE_14K = 18, ++ ARH_AFE_RATE_16K = 2, ++ ARH_AFE_RATE_22K = 19, ++ ARH_AFE_RATE_24K = 3, ++ ARH_AFE_RATE_29K = 20, ++ ARH_AFE_RATE_32K = 4, ++ ARH_AFE_RATE_44K = 21, ++ ARH_AFE_RATE_48K = 5, ++ ARH_AFE_RATE_88K = 22, ++ ARH_AFE_RATE_96K = 6, ++ ARH_AFE_RATE_176K = 23, ++ ARH_AFE_RATE_192K = 7, ++ ARH_AFE_RATE_352K = 24, ++ ARH_AFE_RATE_384K = 8, ++}; ++ ++unsigned int an7581_afe_rate_transform(struct device *dev, unsigned int rate) ++{ ++ switch (rate) { ++ case 7350: ++ return ARH_AFE_RATE_7K; ++ case 8000: ++ return ARH_AFE_RATE_8K; ++ case 11025: ++ return ARH_AFE_RATE_11K; ++ case 12000: ++ return ARH_AFE_RATE_12K; ++ case 14700: ++ return ARH_AFE_RATE_14K; ++ case 16000: ++ return ARH_AFE_RATE_16K; ++ case 22050: ++ return ARH_AFE_RATE_22K; ++ case 24000: ++ return ARH_AFE_RATE_24K; ++ case 29400: ++ return ARH_AFE_RATE_29K; ++ case 32000: ++ return ARH_AFE_RATE_32K; ++ case 44100: ++ return ARH_AFE_RATE_44K; ++ case 48000: ++ return ARH_AFE_RATE_48K; ++ case 88200: ++ return ARH_AFE_RATE_88K; ++ case 96000: ++ return ARH_AFE_RATE_96K; ++ case 176400: ++ return ARH_AFE_RATE_176K; ++ case 192000: ++ return ARH_AFE_RATE_192K; ++ case 352800: ++ return ARH_AFE_RATE_352K; ++ case 384000: ++ return ARH_AFE_RATE_384K; ++ default: ++ dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n", ++ __func__, rate, ARH_AFE_RATE_48K); ++ return ARH_AFE_RATE_48K; ++ } ++} ++ ++static const int an7581_memif_specified_irqs[AN7581_MEMIF_NUM] = { ++ [AN7581_MEMIF_DL1] = AN7581_IRQ_0, ++ [AN7581_MEMIF_UL1] = AN7581_IRQ_1, ++}; ++ ++static const struct snd_pcm_hardware an7581_afe_hardware = { ++ .info = SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP_VALID, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE, ++ .period_bytes_min = 512, ++ .period_bytes_max = 128 * 1024, ++ .periods_min = 2, ++ .periods_max = 256, ++ .buffer_bytes_max = 256 * 1024, ++ .fifo_size = 0, ++}; ++ ++static int an7581_memif_fs(struct snd_pcm_substream *substream, ++ unsigned int rate) ++{ ++ 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); ++ ++ return an7581_afe_rate_transform(afe->dev, rate); ++} ++ ++static int an7581_irq_fs(struct snd_pcm_substream *substream, ++ unsigned int rate) ++{ ++ 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); ++ ++ return an7581_afe_rate_transform(afe->dev, rate); ++} ++ ++#define ARH_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++static struct snd_soc_dai_driver an7581_memif_dai_driver[] = { ++ /* FE DAIs: memory intefaces to CPU */ ++ { ++ .name = "DL1", ++ .id = AN7581_MEMIF_DL1, ++ .playback = { ++ .stream_name = "DL1", ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = ARH_PCM_FORMATS, ++ }, ++ .ops = &mtk_afe_fe_ops, ++ }, ++ { ++ .name = "UL1", ++ .id = AN7581_MEMIF_UL1, ++ .capture = { ++ .stream_name = "UL1", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = ARH_PCM_FORMATS, ++ }, ++ .ops = &mtk_afe_fe_ops, ++ }, ++}; ++ ++static const struct snd_soc_component_driver an7581_afe_pcm_dai_component = { ++ .name = "an7581-afe-pcm-dai", ++}; ++ ++static const struct mtk_base_memif_data memif_data[AN7581_MEMIF_NUM] = { ++ [AN7581_MEMIF_DL1] = { ++ .name = "DL1", ++ .id = AN7581_MEMIF_DL1, ++ .reg_ofs_base = AFE_DL1_BASE, ++ .reg_ofs_cur = AFE_DL1_CUR, ++ .reg_ofs_end = AFE_DL1_END, ++ .fs_reg = -1, ++ .fs_shift = -1, ++ .fs_maskbit = -1, ++ .mono_reg = -1, ++ .mono_shift = -1, ++ .hd_reg = -1, ++ .hd_shift = -1, ++ .enable_reg = AFE_DAC_CON0, ++ .enable_shift = 17, ++ .msb_reg = -1, ++ .msb_shift = -1, ++ .agent_disable_reg = -1, ++ .agent_disable_shift = -1, ++ }, ++ [AN7581_MEMIF_UL1] = { ++ .name = "UL1", ++ .id = AN7581_MEMIF_UL1, ++ .reg_ofs_base = AFE_UL1_BASE, ++ .reg_ofs_cur = AFE_UL1_CUR, ++ .reg_ofs_end = AFE_UL1_END, ++ .fs_reg = -1, ++ .fs_shift = -1, ++ .fs_maskbit = -1, ++ .mono_reg = -1, ++ .mono_shift = -1, ++ .hd_reg = -1, ++ .hd_shift = -1, ++ .enable_reg = AFE_DAC_CON0, ++ .enable_shift = 1, ++ .msb_reg = -1, ++ .msb_shift = -1, ++ .agent_disable_reg = -1, ++ .agent_disable_shift = -1, ++ }, ++}; ++ ++static const struct mtk_base_irq_data irq_data[AN7581_IRQ_NUM] = { ++ [AN7581_IRQ_0] = { ++ .id = AN7581_IRQ_0, ++ .irq_cnt_reg = -1, ++ .irq_cnt_shift = -1, ++ .irq_cnt_maskbit = -1, ++ .irq_en_reg = AFE_IRQ1_CON0, ++ .irq_en_shift = 4, ++ .irq_fs_reg = -1, ++ .irq_fs_shift = -1, ++ .irq_fs_maskbit = -1, ++ .irq_clr_reg = AFE_IRQ1_CON0, ++ .irq_clr_shift = 0, ++ }, ++ [AN7581_IRQ_1] = { ++ .id = AN7581_IRQ_1, ++ .irq_cnt_reg = -1, ++ .irq_cnt_shift = -1, ++ .irq_cnt_maskbit = -1, ++ .irq_en_reg = AFE_IRQ0_CON0, ++ .irq_en_shift = 4, ++ .irq_fs_reg = -1, ++ .irq_fs_shift = -1, ++ .irq_fs_maskbit = -1, ++ .irq_clr_reg = AFE_IRQ0_CON0, ++ .irq_clr_shift = 1, ++ }, ++}; ++ ++static const struct regmap_config an7581_afe_regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = AFE_MAX_REGISTER, ++ .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1), ++}; ++ ++static irqreturn_t an7581_afe_irq_handler(int irq_id, void *dev) ++{ ++ struct mtk_base_afe *afe = dev; ++ struct mtk_base_afe_irq *irq; ++ u32 status; ++ u32 reg; ++ int i; ++ ++ regmap_read(afe->regmap, AFE_IRQ_STS, &status); ++ ++ if (status & AFE_IRQ_STS_RECORD) ++ reg = AFE_IRQ0_CON0; ++ else ++ reg = AFE_IRQ1_CON0; ++ ++ regmap_set_bits(afe->regmap, reg, BIT(2)); ++ regmap_clear_bits(afe->regmap, reg, BIT(2)); ++ ++ regmap_set_bits(afe->regmap, reg, BIT(3)); ++ regmap_clear_bits(afe->regmap, reg, BIT(3)); ++ ++ for (i = 0; i < AN7581_MEMIF_NUM; i++) { ++ struct mtk_base_afe_memif *memif = &afe->memif[i]; ++ ++ if (!memif->substream) ++ continue; ++ ++ if (memif->irq_usage < 0) ++ continue; ++ ++ irq = &afe->irqs[memif->irq_usage]; ++ ++ if (status & (1 << irq->irq_data->irq_clr_shift)) ++ snd_pcm_period_elapsed(memif->substream); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int an7581_afe_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int an7581_afe_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++ ++static int an7581_dai_memif_register(struct mtk_base_afe *afe) ++{ ++ struct mtk_base_afe_dai *dai; ++ ++ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); ++ if (!dai) ++ return -ENOMEM; ++ ++ list_add(&dai->list, &afe->sub_dais); ++ ++ dai->dai_drivers = an7581_memif_dai_driver; ++ dai->num_dai_drivers = ARRAY_SIZE(an7581_memif_dai_driver); ++ ++ return 0; ++} ++ ++typedef int (*dai_register_cb)(struct mtk_base_afe *); ++static const dai_register_cb dai_register_cbs[] = { ++ an7581_dai_memif_register, ++}; ++ ++static int an7581_afe_pcm_dev_probe(struct platform_device *pdev) ++{ ++ struct mtk_base_afe *afe; ++ struct an7581_afe_private *afe_priv; ++ struct device *dev; ++ int i, irq_id, ret; ++ ++ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); ++ if (!afe) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, afe); ++ ++ afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), ++ GFP_KERNEL); ++ if (!afe->platform_priv) ++ return -ENOMEM; ++ ++ afe_priv = afe->platform_priv; ++ afe->dev = &pdev->dev; ++ dev = afe->dev; ++ ++ afe->base_addr = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(afe->base_addr)) ++ return PTR_ERR(afe->base_addr); ++ ++ ret = devm_pm_runtime_enable(dev); ++ if (ret) ++ return ret; ++ ++ pm_runtime_get_sync(&pdev->dev); ++ ++ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, ++ &an7581_afe_regmap_config); ++ ++ pm_runtime_put_sync(&pdev->dev); ++ if (IS_ERR(afe->regmap)) ++ return PTR_ERR(afe->regmap); ++ ++ mutex_init(&afe->irq_alloc_lock); ++ ++ /* irq initialize */ ++ afe->irqs_size = AN7581_IRQ_NUM; ++ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), ++ GFP_KERNEL); ++ if (!afe->irqs) ++ return -ENOMEM; ++ ++ for (i = 0; i < afe->irqs_size; i++) ++ afe->irqs[i].irq_data = &irq_data[i]; ++ ++ /* request irq */ ++ irq_id = platform_get_irq(pdev, 0); ++ if (irq_id < 0) ++ return irq_id; ++ ++ ret = devm_request_irq(dev, irq_id, an7581_afe_irq_handler, ++ IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n"); ++ ++ /* init memif */ ++ afe->memif_size = AN7581_MEMIF_NUM; ++ afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), ++ GFP_KERNEL); ++ if (!afe->memif) ++ return -ENOMEM; ++ ++ for (i = 0; i < afe->memif_size; i++) { ++ int sel_irq = an7581_memif_specified_irqs[i]; ++ ++ afe->memif[i].data = &memif_data[i]; ++ afe->memif[i].irq_usage = sel_irq; ++ afe->memif[i].const_irq = 1; ++ afe->irqs[sel_irq].irq_occupyed = true; ++ } ++ ++ /* init sub_dais */ ++ INIT_LIST_HEAD(&afe->sub_dais); ++ ++ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { ++ ret = dai_register_cbs[i](afe); ++ if (ret) ++ return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i); ++ } ++ ++ /* init dai_driver and component_driver */ ++ ret = mtk_afe_combine_sub_dai(afe); ++ if (ret) ++ return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n"); ++ ++ afe->mtk_afe_hardware = &an7581_afe_hardware; ++ afe->memif_fs = an7581_memif_fs; ++ afe->irq_fs = an7581_irq_fs; ++ ++ afe->runtime_resume = an7581_afe_runtime_resume; ++ afe->runtime_suspend = an7581_afe_runtime_suspend; ++ ++ /* register component */ ++ ret = devm_snd_soc_register_component(&pdev->dev, ++ &mtk_afe_pcm_platform, ++ NULL, 0); ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot register AFE component\n"); ++ ++ ret = devm_snd_soc_register_component(afe->dev, ++ &an7581_afe_pcm_dai_component, ++ afe->dai_drivers, ++ afe->num_dai_drivers); ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n"); ++ ++ return 0; ++} ++ ++static void an7581_afe_pcm_dev_remove(struct platform_device *pdev) ++{ ++ pm_runtime_disable(&pdev->dev); ++ if (!pm_runtime_status_suspended(&pdev->dev)) ++ an7581_afe_runtime_suspend(&pdev->dev); ++} ++ ++static const struct of_device_id an7581_afe_pcm_dt_match[] = { ++ { .compatible = "airoha,an7581-afe" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, an7581_afe_pcm_dt_match); ++ ++static const struct dev_pm_ops an7581_afe_pm_ops = { ++ RUNTIME_PM_OPS(an7581_afe_runtime_suspend, ++ an7581_afe_runtime_resume, NULL) ++}; ++ ++static struct platform_driver an7581_afe_pcm_driver = { ++ .driver = { ++ .name = "an7581-audio", ++ .of_match_table = an7581_afe_pcm_dt_match, ++ .pm = pm_ptr(&an7581_afe_pm_ops), ++ }, ++ .probe = an7581_afe_pcm_dev_probe, ++ .remove_new = an7581_afe_pcm_dev_remove, ++}; ++module_platform_driver(an7581_afe_pcm_driver); ++ ++MODULE_DESCRIPTION("Airoha SoC AFE platform driver for ALSA AN7581"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/sound/soc/airoha/an7581/an7581-i2s.c +@@ -0,0 +1,110 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Airoha ALSA SoC I2S platform driver for AN7581 ++ * ++ */ ++ ++#include ++#include ++ ++#include "an7581-afe-common.h" ++ ++SND_SOC_DAILINK_DEFS(playback, ++ DAILINK_COMP_ARRAY(COMP_CPU("DL1")), ++ DAILINK_COMP_ARRAY(COMP_DUMMY()), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++SND_SOC_DAILINK_DEFS(capture, ++ DAILINK_COMP_ARRAY(COMP_CPU("UL1")), ++ DAILINK_COMP_ARRAY(COMP_DUMMY()), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++static struct snd_soc_dai_link an7581_i2s_dai_links[] = { ++ { ++ .name = "an7581-i2s-playback", ++ .stream_name = "an7581-i2s-playback", ++ .trigger = {SND_SOC_DPCM_TRIGGER_POST, ++ SND_SOC_DPCM_TRIGGER_POST}, ++ .dynamic = 0, ++ .playback_only = 1, ++ SND_SOC_DAILINK_REG(playback), ++ }, ++ { ++ .name = "an7581-i2s-capture", ++ .stream_name = "an7581-i2s-capture", ++ .trigger = {SND_SOC_DPCM_TRIGGER_POST, ++ SND_SOC_DPCM_TRIGGER_POST}, ++ .dynamic = 0, ++ .capture_only = 1, ++ SND_SOC_DAILINK_REG(capture), ++ }, ++}; ++ ++static struct snd_soc_card an7581_i2s_card = { ++ .name = "an7581-i2s", ++ .owner = THIS_MODULE, ++ .dai_link = an7581_i2s_dai_links, ++ .num_links = ARRAY_SIZE(an7581_i2s_dai_links), ++}; ++ ++static int an7581_i2s_machine_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_card *card = &an7581_i2s_card; ++ struct device_node *platform_dai_node; ++ struct snd_soc_dai_link *dai_link; ++ struct device_node *platform; ++ int ret, i; ++ ++ card->dev = &pdev->dev; ++ ++ platform = of_get_child_by_name(pdev->dev.of_node, "platform"); ++ ++ if (platform) { ++ platform_dai_node = of_parse_phandle(platform, "sound-dai", 0); ++ of_node_put(platform); ++ ++ if (!platform_dai_node) { ++ dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n"); ++ return -EINVAL; ++ } ++ } else { ++ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); ++ return -EINVAL; ++ } ++ ++ for_each_card_prelinks(card, i, dai_link) { ++ if (dai_link->platforms->name) ++ continue; ++ dai_link->platforms->of_node = platform_dai_node; ++ } ++ ++ ret = devm_snd_soc_register_card(&pdev->dev, card); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__); ++ goto err_of_node_put; ++ } ++ ++ return 0; ++ ++err_of_node_put: ++ of_node_put(platform_dai_node); ++ return ret; ++} ++ ++static const struct of_device_id an7581_i2s_machine_dt_match[] = { ++ { .compatible = "airoha,an7581-i2s" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, an7581_i2s_machine_dt_match); ++ ++static struct platform_driver an7581_i2s_driver = { ++ .driver = { ++ .name = "an7581-i2s", ++ .of_match_table = an7581_i2s_machine_dt_match, ++ }, ++ .probe = an7581_i2s_machine_probe, ++}; ++module_platform_driver(an7581_i2s_driver); ++ ++MODULE_DESCRIPTION("Airoha SoC I2S platform driver for ALSA AN7581"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/sound/soc/airoha/an7581/an7581-reg.h +@@ -0,0 +1,29 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * an7581-reg.h -- Airoha AN7581 audio driver reg definition ++ */ ++ ++#ifndef _AN7581_REG_H_ ++#define _AN7581_REG_H_ ++ ++#define AFE_DAC_CON0 0x0 ++ ++#define AFE_DL1_BASE 0xa8 ++#define AFE_DL1_END 0xac ++#define AFE_DL1_CUR 0xb0 ++ ++#define AFE_UL1_BASE 0xc4 ++#define AFE_UL1_END 0xc8 ++#define AFE_UL1_CUR 0xcc ++ ++#define AFE_IRQ0_CON0 0xe4 ++ ++#define AFE_IRQ_STS 0xf8 ++#define AFE_IRQ_STS_PLAY BIT(1) ++#define AFE_IRQ_STS_RECORD BIT(0) ++ ++#define AFE_IRQ1_CON0 0x100 ++ ++#define AFE_MAX_REGISTER AFE_IRQ1_CON0 ++ ++#endif -- 2.30.2