0
0
mirror of https://git.openwrt.org/openwrt/openwrt.git/ synced 2025-10-06 02:52:47 +02:00

airoha: en7581: Add pending ASOC driver

Add pending ASOC driver for I2S sound support on Airoha EN7581 SoC.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
Christian Marangi
2025-09-26 04:52:36 +02:00
parent c3d70b1ae5
commit 14bc87cf76
2 changed files with 1139 additions and 0 deletions

View File

@@ -0,0 +1,410 @@
From 527123b53739a2f73ca924b9c6e2f63dc66739a5 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
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 <ansuelsmth@gmail.com>
---
.../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 <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <sound/soc.h>
-#include "mtk-afe-platform-driver.h"
+#include <sound/mediatek/mtk-afe-platform-driver.h>
#include <sound/pcm_params.h>
-#include "mtk-afe-fe-dai.h"
+#include <sound/mediatek/mtk-afe-fe-dai.h>
#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 <linux/dma-mapping.h>
#include <sound/soc.h>
-#include "mtk-afe-platform-driver.h"
+#include <sound/mediatek/mtk-afe-platform-driver.h>
#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 <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
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 <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
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 <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
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 <sound/soc.h>
#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 <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
/*****************************************************************************
* 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 <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
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 <sound/mediatek/mtk-afe-platform-driver.h>
#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 <sound/mediatek/mtk-afe-platform-driver.h>
#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 <linux/reset.h>
#include <sound/soc.h>
-#include "../common/mtk-afe-platform-driver.h"
-#include "../common/mtk-afe-fe-dai.h"
+#include <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
#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 <linux/regmap.h>
#include <sound/soc.h>
-#include "../common/mtk-afe-fe-dai.h"
-#include "../common/mtk-afe-platform-driver.h"
+#include <sound/mediatek/mtk-afe-fe-dai.h>
+#include <sound/mediatek/mtk-afe-platform-driver.h>
#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 <sound/soc.h>
#include "../../codecs/mt6358.h"
-#include "../common/mtk-afe-platform-driver.h"
+#include <sound/mediatek/mtk-afe-platform-driver.h>
#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 <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
#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 <linux/reset.h>
#include <sound/soc.h>
-#include "../common/mtk-afe-fe-dai.h"
-#include "../common/mtk-afe-platform-driver.h"
+#include <sound/mediatek/mtk-afe-fe-dai.h>
+#include <sound/mediatek/mtk-afe-platform-driver.h>
#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 <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
#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 <sound/mediatek/mtk-afe-platform-driver.h>
#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 <garlic.tseng@mediatek.com>
+ */
+
+#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 <garlic.tseng@mediatek.com>
+ */
+
+#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 <garlic.tseng@mediatek.com>
- */
-
-#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 <garlic.tseng@mediatek.com>
- */
-
-#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
-

View File

@@ -0,0 +1,729 @@
From 9989af6ed0dba86f57ac4aa1574f9ce9b1e640af Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
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 <ansuelsmth@gmail.com>
---
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 <sound/soc.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+
+#include "an7581-afe-common.h"
+#include "an7581-reg.h"
+#include <sound/mediatek/mtk-afe-platform-driver.h>
+#include <sound/mediatek/mtk-afe-fe-dai.h>
+
+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 <linux/module.h>
+#include <sound/soc.h>
+
+#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