[openwrt/openwrt] airoha: en7581: Add pending ASOC driver

LEDE Commits lede-commits at lists.infradead.org
Thu Sep 25 20:04:18 PDT 2025


ansuel pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/14bc87cf7658c0a6c4891aba5890f2fafaab2a8e

commit 14bc87cf7658c0a6c4891aba5890f2fafaab2a8e
Author: Christian Marangi <ansuelsmth at gmail.com>
AuthorDate: Fri Sep 26 04:52:36 2025 +0200

    airoha: en7581: Add pending ASOC driver
    
    Add pending ASOC driver for I2S sound support on Airoha EN7581 SoC.
    
    Signed-off-by: Christian Marangi <ansuelsmth at gmail.com>
---
 ...diatek-move-some-header-to-global-include.patch | 410 ++++++++++++
 ...-Add-AFE-and-I2S-driver-for-Airoha-AN7581.patch | 729 +++++++++++++++++++++
 2 files changed, 1139 insertions(+)

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 <ansuelsmth at 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 at 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 at 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 at 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 at 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 at 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
+-
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 <ansuelsmth at 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 at 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




More information about the lede-commits mailing list