--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2020 NXP
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/pm_qos.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/dma-mapping.h>
+
+#include "fsl_aud2htx.h"
+#include "imx-pcm.h"
+
+static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct fsl_aud2htx *aud2htx = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+                                  AUD2HTX_CTRL_EN, AUD2HTX_CTRL_EN);
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                                  AUD2HTX_CTRE_DE, AUD2HTX_CTRE_DE);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                                  AUD2HTX_CTRE_DE, 0);
+               regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+                                  AUD2HTX_CTRL_EN, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
+       .trigger        = fsl_aud2htx_trigger,
+};
+
+static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+       struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
+
+       /* DMA request when number of entries < WTMK_LOW */
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                          AUD2HTX_CTRE_DT_MASK, 0);
+
+       /* Disable interrupts*/
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_IRQ_MASK,
+                          AUD2HTX_WM_HIGH_IRQ_MASK |
+                          AUD2HTX_WM_LOW_IRQ_MASK |
+                          AUD2HTX_OVF_MASK,
+                          AUD2HTX_WM_HIGH_IRQ_MASK |
+                          AUD2HTX_WM_LOW_IRQ_MASK |
+                          AUD2HTX_OVF_MASK);
+
+       /* Configure watermark */
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                          AUD2HTX_CTRE_WL_MASK,
+                          AUD2HTX_WTMK_LOW << AUD2HTX_CTRE_WL_SHIFT);
+       regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+                          AUD2HTX_CTRE_WH_MASK,
+                          AUD2HTX_WTMK_HIGH << AUD2HTX_CTRE_WH_SHIFT);
+
+       snd_soc_dai_init_dma_data(cpu_dai, &aud2htx->dma_params_tx,
+                                 &aud2htx->dma_params_rx);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver fsl_aud2htx_dai = {
+       .probe = fsl_aud2htx_dai_probe,
+       .playback = {
+               .stream_name = "CPU-Playback",
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_32000 |
+                        SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000 |
+                        SNDRV_PCM_RATE_88200 |
+                        SNDRV_PCM_RATE_96000 |
+                        SNDRV_PCM_RATE_176400 |
+                        SNDRV_PCM_RATE_192000,
+               .formats = FSL_AUD2HTX_FORMATS,
+       },
+       .ops = &fsl_aud2htx_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_aud2htx_component = {
+       .name   = "fsl-aud2htx",
+};
+
+static const struct reg_default fsl_aud2htx_reg_defaults[] = {
+       {AUD2HTX_CTRL,          0x00000000},
+       {AUD2HTX_CTRL_EXT,      0x00000000},
+       {AUD2HTX_WR,            0x00000000},
+       {AUD2HTX_STATUS,        0x00000000},
+       {AUD2HTX_IRQ_NOMASK,    0x00000000},
+       {AUD2HTX_IRQ_MASKED,    0x00000000},
+       {AUD2HTX_IRQ_MASK,      0x00000000},
+};
+
+static bool fsl_aud2htx_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AUD2HTX_CTRL:
+       case AUD2HTX_CTRL_EXT:
+       case AUD2HTX_STATUS:
+       case AUD2HTX_IRQ_NOMASK:
+       case AUD2HTX_IRQ_MASKED:
+       case AUD2HTX_IRQ_MASK:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_aud2htx_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AUD2HTX_CTRL:
+       case AUD2HTX_CTRL_EXT:
+       case AUD2HTX_WR:
+       case AUD2HTX_IRQ_NOMASK:
+       case AUD2HTX_IRQ_MASKED:
+       case AUD2HTX_IRQ_MASK:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_aud2htx_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AUD2HTX_STATUS:
+       case AUD2HTX_IRQ_NOMASK:
+       case AUD2HTX_IRQ_MASKED:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config fsl_aud2htx_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+
+       .max_register = AUD2HTX_IRQ_MASK,
+       .reg_defaults = fsl_aud2htx_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_aud2htx_reg_defaults),
+       .readable_reg = fsl_aud2htx_readable_reg,
+       .volatile_reg = fsl_aud2htx_volatile_reg,
+       .writeable_reg = fsl_aud2htx_writeable_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct of_device_id fsl_aud2htx_dt_ids[] = {
+       { .compatible = "fsl,imx8mp-aud2htx",},
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_aud2htx_dt_ids);
+
+static irqreturn_t fsl_aud2htx_isr(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
+static int fsl_aud2htx_probe(struct platform_device *pdev)
+{
+       struct fsl_aud2htx *aud2htx;
+       struct resource *res;
+       void __iomem *regs;
+       int ret, irq;
+
+       aud2htx = devm_kzalloc(&pdev->dev, sizeof(*aud2htx), GFP_KERNEL);
+       if (!aud2htx)
+               return -ENOMEM;
+
+       aud2htx->pdev = pdev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(regs)) {
+               dev_err(&pdev->dev, "failed ioremap\n");
+               return PTR_ERR(regs);
+       }
+
+       aud2htx->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                               &fsl_aud2htx_regmap_config);
+       if (IS_ERR(aud2htx->regmap)) {
+               dev_err(&pdev->dev, "failed to init regmap");
+               return PTR_ERR(aud2htx->regmap);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for node %s\n",
+                       dev_name(&pdev->dev));
+               return irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, fsl_aud2htx_isr, 0,
+                              dev_name(&pdev->dev), aud2htx);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
+               return ret;
+       }
+
+       aud2htx->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       if (IS_ERR(aud2htx->bus_clk)) {
+               dev_err(&pdev->dev, "failed to get mem clock\n");
+               return PTR_ERR(aud2htx->bus_clk);
+       }
+
+       aud2htx->dma_params_tx.chan_name = "tx";
+       aud2htx->dma_params_tx.maxburst = AUD2HTX_MAXBURST;
+       aud2htx->dma_params_tx.addr = res->start + AUD2HTX_WR;
+
+       platform_set_drvdata(pdev, aud2htx);
+       pm_runtime_enable(&pdev->dev);
+
+       regcache_cache_only(aud2htx->regmap, true);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &fsl_aud2htx_component,
+                                             &fsl_aud2htx_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register ASoC DAI\n");
+               return ret;
+       }
+
+       ret = imx_pcm_dma_init(pdev, IMX_DEFAULT_DMABUF_SIZE);
+       if (ret)
+               dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+       return ret;
+}
+
+static int fsl_aud2htx_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static int fsl_aud2htx_runtime_suspend(struct device *dev)
+{
+       struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+
+       regcache_cache_only(aud2htx->regmap, true);
+       clk_disable_unprepare(aud2htx->bus_clk);
+
+       return 0;
+}
+
+static int fsl_aud2htx_runtime_resume(struct device *dev)
+{
+       struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(aud2htx->bus_clk);
+       if (ret)
+               return ret;
+
+       regcache_cache_only(aud2htx->regmap, false);
+       regcache_mark_dirty(aud2htx->regmap);
+       regcache_sync(aud2htx->regmap);
+
+       return 0;
+}
+
+static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
+       SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend,
+                          fsl_aud2htx_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_aud2htx_driver = {
+       .probe = fsl_aud2htx_probe,
+       .remove = fsl_aud2htx_remove,
+       .driver = {
+               .name = "fsl-aud2htx",
+               .pm = &fsl_aud2htx_pm_ops,
+               .of_match_table = fsl_aud2htx_dt_ids,
+       },
+};
+module_platform_driver(fsl_aud2htx_driver);
+
+MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
+MODULE_DESCRIPTION("NXP AUD2HTX driver");
+MODULE_LICENSE("GPL v2");
 
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef _FSL_AUD2HTX_H
+#define _FSL_AUD2HTX_H
+
+#define FSL_AUD2HTX_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
+                            SNDRV_PCM_FMTBIT_S32_LE)
+
+/* AUD2HTX Register Map */
+#define AUD2HTX_CTRL          0x0   /* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EXT      0x4   /* AUD2HTX Control Extended Register */
+#define AUD2HTX_WR            0x8   /* AUD2HTX Write Register */
+#define AUD2HTX_STATUS        0xC   /* AUD2HTX Status Register */
+#define AUD2HTX_IRQ_NOMASK    0x10  /* AUD2HTX Nonmasked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASKED    0x14  /* AUD2HTX Masked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASK      0x18  /* AUD2HTX IRQ Masks Register */
+
+/* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EN          BIT(0)
+
+/* AUD2HTX Control Extended Register */
+#define AUD2HTX_CTRE_DE          BIT(0)
+#define AUD2HTX_CTRE_DT_SHIFT    0x1
+#define AUD2HTX_CTRE_DT_WIDTH    0x2
+#define AUD2HTX_CTRE_DT_MASK     ((BIT(AUD2HTX_CTRE_DT_WIDTH) - 1) \
+                                << AUD2HTX_CTRE_DT_SHIFT)
+#define AUD2HTX_CTRE_WL_SHIFT    16
+#define AUD2HTX_CTRE_WL_WIDTH    5
+#define AUD2HTX_CTRE_WL_MASK     ((BIT(AUD2HTX_CTRE_WL_WIDTH) - 1) \
+                                << AUD2HTX_CTRE_WL_SHIFT)
+#define AUD2HTX_CTRE_WH_SHIFT    24
+#define AUD2HTX_CTRE_WH_WIDTH    5
+#define AUD2HTX_CTRE_WH_MASK     ((BIT(AUD2HTX_CTRE_WH_WIDTH) - 1) \
+                                << AUD2HTX_CTRE_WH_SHIFT)
+
+/* AUD2HTX IRQ Masks Register */
+#define AUD2HTX_WM_HIGH_IRQ_MASK BIT(2)
+#define AUD2HTX_WM_LOW_IRQ_MASK  BIT(1)
+#define AUD2HTX_OVF_MASK         BIT(0)
+
+#define AUD2HTX_FIFO_DEPTH       0x20
+#define AUD2HTX_WTMK_LOW         0x10
+#define AUD2HTX_WTMK_HIGH        0x10
+#define AUD2HTX_MAXBURST         0x10
+
+/**
+ * fsl_aud2htx: AUD2HTX private data
+ *
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @bus_clk: clock source to access register
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ */
+struct fsl_aud2htx {
+       struct platform_device *pdev;
+       struct regmap *regmap;
+       struct clk *bus_clk;
+
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+};
+
+#endif /* _FSL_AUD2HTX_H */