18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NXP AUDMIX ALSA SoC Digital Audio Interface (DAI) driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2017 NXP
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/clk.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
128c2ecf20Sopenharmony_ci#include <sound/soc.h>
138c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "fsl_audmix.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define SOC_ENUM_SINGLE_S(xreg, xshift, xtexts) \
188c2ecf20Sopenharmony_ci	SOC_ENUM_SINGLE(xreg, xshift, ARRAY_SIZE(xtexts), xtexts)
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic const char
218c2ecf20Sopenharmony_ci	*tdm_sel[] = { "TDM1", "TDM2", },
228c2ecf20Sopenharmony_ci	*mode_sel[] = { "Disabled", "TDM1", "TDM2", "Mixed", },
238c2ecf20Sopenharmony_ci	*width_sel[] = { "16b", "18b", "20b", "24b", "32b", },
248c2ecf20Sopenharmony_ci	*endis_sel[] = { "Disabled", "Enabled", },
258c2ecf20Sopenharmony_ci	*updn_sel[] = { "Downward", "Upward", },
268c2ecf20Sopenharmony_ci	*mask_sel[] = { "Unmask", "Mask", };
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic const struct soc_enum fsl_audmix_enum[] = {
298c2ecf20Sopenharmony_ci/* FSL_AUDMIX_CTR enums */
308c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_MIXCLK_SHIFT, tdm_sel),
318c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_OUTSRC_SHIFT, mode_sel),
328c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_OUTWIDTH_SHIFT, width_sel),
338c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_MASKRTDF_SHIFT, mask_sel),
348c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_MASKCKDF_SHIFT, mask_sel),
358c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_SYNCMODE_SHIFT, endis_sel),
368c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_SYNCSRC_SHIFT, tdm_sel),
378c2ecf20Sopenharmony_ci/* FSL_AUDMIX_ATCR0 enums */
388c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR0, 0, endis_sel),
398c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR0, 1, updn_sel),
408c2ecf20Sopenharmony_ci/* FSL_AUDMIX_ATCR1 enums */
418c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR1, 0, endis_sel),
428c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR1, 1, updn_sel),
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct fsl_audmix_state {
468c2ecf20Sopenharmony_ci	u8 tdms;
478c2ecf20Sopenharmony_ci	u8 clk;
488c2ecf20Sopenharmony_ci	char msg[64];
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const struct fsl_audmix_state prms[4][4] = {{
528c2ecf20Sopenharmony_ci	/* DIS->DIS, do nothing */
538c2ecf20Sopenharmony_ci	{ .tdms = 0, .clk = 0, .msg = "" },
548c2ecf20Sopenharmony_ci	/* DIS->TDM1*/
558c2ecf20Sopenharmony_ci	{ .tdms = 1, .clk = 1, .msg = "DIS->TDM1: TDM1 not started!\n" },
568c2ecf20Sopenharmony_ci	/* DIS->TDM2*/
578c2ecf20Sopenharmony_ci	{ .tdms = 2, .clk = 2, .msg = "DIS->TDM2: TDM2 not started!\n" },
588c2ecf20Sopenharmony_ci	/* DIS->MIX */
598c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 0, .msg = "DIS->MIX: Please start both TDMs!\n" }
608c2ecf20Sopenharmony_ci}, {	/* TDM1->DIS */
618c2ecf20Sopenharmony_ci	{ .tdms = 1, .clk = 0, .msg = "TDM1->DIS: TDM1 not started!\n" },
628c2ecf20Sopenharmony_ci	/* TDM1->TDM1, do nothing */
638c2ecf20Sopenharmony_ci	{ .tdms = 0, .clk = 0, .msg = "" },
648c2ecf20Sopenharmony_ci	/* TDM1->TDM2 */
658c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 2, .msg = "TDM1->TDM2: Please start both TDMs!\n" },
668c2ecf20Sopenharmony_ci	/* TDM1->MIX */
678c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 0, .msg = "TDM1->MIX: Please start both TDMs!\n" }
688c2ecf20Sopenharmony_ci}, {	/* TDM2->DIS */
698c2ecf20Sopenharmony_ci	{ .tdms = 2, .clk = 0, .msg = "TDM2->DIS: TDM2 not started!\n" },
708c2ecf20Sopenharmony_ci	/* TDM2->TDM1 */
718c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 1, .msg = "TDM2->TDM1: Please start both TDMs!\n" },
728c2ecf20Sopenharmony_ci	/* TDM2->TDM2, do nothing */
738c2ecf20Sopenharmony_ci	{ .tdms = 0, .clk = 0, .msg = "" },
748c2ecf20Sopenharmony_ci	/* TDM2->MIX */
758c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 0, .msg = "TDM2->MIX: Please start both TDMs!\n" }
768c2ecf20Sopenharmony_ci}, {	/* MIX->DIS */
778c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 0, .msg = "MIX->DIS: Please start both TDMs!\n" },
788c2ecf20Sopenharmony_ci	/* MIX->TDM1 */
798c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 1, .msg = "MIX->TDM1: Please start both TDMs!\n" },
808c2ecf20Sopenharmony_ci	/* MIX->TDM2 */
818c2ecf20Sopenharmony_ci	{ .tdms = 3, .clk = 2, .msg = "MIX->TDM2: Please start both TDMs!\n" },
828c2ecf20Sopenharmony_ci	/* MIX->MIX, do nothing */
838c2ecf20Sopenharmony_ci	{ .tdms = 0, .clk = 0, .msg = "" }
848c2ecf20Sopenharmony_ci}, };
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int fsl_audmix_state_trans(struct snd_soc_component *comp,
878c2ecf20Sopenharmony_ci				  unsigned int *mask, unsigned int *ctr,
888c2ecf20Sopenharmony_ci				  const struct fsl_audmix_state prm)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
918c2ecf20Sopenharmony_ci	/* Enforce all required TDMs are started */
928c2ecf20Sopenharmony_ci	if ((priv->tdms & prm.tdms) != prm.tdms) {
938c2ecf20Sopenharmony_ci		dev_dbg(comp->dev, "%s", prm.msg);
948c2ecf20Sopenharmony_ci		return -EINVAL;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	switch (prm.clk) {
988c2ecf20Sopenharmony_ci	case 1:
998c2ecf20Sopenharmony_ci	case 2:
1008c2ecf20Sopenharmony_ci		/* Set mix clock */
1018c2ecf20Sopenharmony_ci		(*mask) |= FSL_AUDMIX_CTR_MIXCLK_MASK;
1028c2ecf20Sopenharmony_ci		(*ctr)  |= FSL_AUDMIX_CTR_MIXCLK(prm.clk - 1);
1038c2ecf20Sopenharmony_ci		break;
1048c2ecf20Sopenharmony_ci	default:
1058c2ecf20Sopenharmony_ci		break;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int fsl_audmix_put_mix_clk_src(struct snd_kcontrol *kcontrol,
1128c2ecf20Sopenharmony_ci				      struct snd_ctl_elem_value *ucontrol)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1158c2ecf20Sopenharmony_ci	struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
1168c2ecf20Sopenharmony_ci	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1178c2ecf20Sopenharmony_ci	unsigned int *item = ucontrol->value.enumerated.item;
1188c2ecf20Sopenharmony_ci	unsigned int reg_val, val, mix_clk;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/* Get current state */
1218c2ecf20Sopenharmony_ci	reg_val = snd_soc_component_read(comp, FSL_AUDMIX_CTR);
1228c2ecf20Sopenharmony_ci	mix_clk = ((reg_val & FSL_AUDMIX_CTR_MIXCLK_MASK)
1238c2ecf20Sopenharmony_ci			>> FSL_AUDMIX_CTR_MIXCLK_SHIFT);
1248c2ecf20Sopenharmony_ci	val = snd_soc_enum_item_to_val(e, item[0]);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	dev_dbg(comp->dev, "TDMs=x%08x, val=x%08x\n", priv->tdms, val);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/**
1298c2ecf20Sopenharmony_ci	 * Ensure the current selected mixer clock is available
1308c2ecf20Sopenharmony_ci	 * for configuration propagation
1318c2ecf20Sopenharmony_ci	 */
1328c2ecf20Sopenharmony_ci	if (!(priv->tdms & BIT(mix_clk))) {
1338c2ecf20Sopenharmony_ci		dev_err(comp->dev,
1348c2ecf20Sopenharmony_ci			"Started TDM%d needed for config propagation!\n",
1358c2ecf20Sopenharmony_ci			mix_clk + 1);
1368c2ecf20Sopenharmony_ci		return -EINVAL;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (!(priv->tdms & BIT(val))) {
1408c2ecf20Sopenharmony_ci		dev_err(comp->dev,
1418c2ecf20Sopenharmony_ci			"The selected clock source has no TDM%d enabled!\n",
1428c2ecf20Sopenharmony_ci			val + 1);
1438c2ecf20Sopenharmony_ci		return -EINVAL;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return snd_soc_put_enum_double(kcontrol, ucontrol);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int fsl_audmix_put_out_src(struct snd_kcontrol *kcontrol,
1508c2ecf20Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
1538c2ecf20Sopenharmony_ci	struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
1548c2ecf20Sopenharmony_ci	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1558c2ecf20Sopenharmony_ci	unsigned int *item = ucontrol->value.enumerated.item;
1568c2ecf20Sopenharmony_ci	u32 out_src, mix_clk;
1578c2ecf20Sopenharmony_ci	unsigned int reg_val, val, mask = 0, ctr = 0;
1588c2ecf20Sopenharmony_ci	int ret;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* Get current state */
1618c2ecf20Sopenharmony_ci	reg_val = snd_soc_component_read(comp, FSL_AUDMIX_CTR);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* "From" state */
1648c2ecf20Sopenharmony_ci	out_src = ((reg_val & FSL_AUDMIX_CTR_OUTSRC_MASK)
1658c2ecf20Sopenharmony_ci			>> FSL_AUDMIX_CTR_OUTSRC_SHIFT);
1668c2ecf20Sopenharmony_ci	mix_clk = ((reg_val & FSL_AUDMIX_CTR_MIXCLK_MASK)
1678c2ecf20Sopenharmony_ci			>> FSL_AUDMIX_CTR_MIXCLK_SHIFT);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* "To" state */
1708c2ecf20Sopenharmony_ci	val = snd_soc_enum_item_to_val(e, item[0]);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	dev_dbg(comp->dev, "TDMs=x%08x, val=x%08x\n", priv->tdms, val);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* Check if state is changing ... */
1758c2ecf20Sopenharmony_ci	if (out_src == val)
1768c2ecf20Sopenharmony_ci		return 0;
1778c2ecf20Sopenharmony_ci	/**
1788c2ecf20Sopenharmony_ci	 * Ensure the current selected mixer clock is available
1798c2ecf20Sopenharmony_ci	 * for configuration propagation
1808c2ecf20Sopenharmony_ci	 */
1818c2ecf20Sopenharmony_ci	if (!(priv->tdms & BIT(mix_clk))) {
1828c2ecf20Sopenharmony_ci		dev_err(comp->dev,
1838c2ecf20Sopenharmony_ci			"Started TDM%d needed for config propagation!\n",
1848c2ecf20Sopenharmony_ci			mix_clk + 1);
1858c2ecf20Sopenharmony_ci		return -EINVAL;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/* Check state transition constraints */
1898c2ecf20Sopenharmony_ci	ret = fsl_audmix_state_trans(comp, &mask, &ctr, prms[out_src][val]);
1908c2ecf20Sopenharmony_ci	if (ret)
1918c2ecf20Sopenharmony_ci		return ret;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Complete transition to new state */
1948c2ecf20Sopenharmony_ci	mask |= FSL_AUDMIX_CTR_OUTSRC_MASK;
1958c2ecf20Sopenharmony_ci	ctr  |= FSL_AUDMIX_CTR_OUTSRC(val);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return snd_soc_component_update_bits(comp, FSL_AUDMIX_CTR, mask, ctr);
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new fsl_audmix_snd_controls[] = {
2018c2ecf20Sopenharmony_ci	/* FSL_AUDMIX_CTR controls */
2028c2ecf20Sopenharmony_ci	{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2038c2ecf20Sopenharmony_ci		.name = "Mixing Clock Source",
2048c2ecf20Sopenharmony_ci		.info = snd_soc_info_enum_double,
2058c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_WRITE,
2068c2ecf20Sopenharmony_ci		.put = fsl_audmix_put_mix_clk_src,
2078c2ecf20Sopenharmony_ci		.private_value = (unsigned long)&fsl_audmix_enum[0] },
2088c2ecf20Sopenharmony_ci	{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2098c2ecf20Sopenharmony_ci		.name = "Output Source",
2108c2ecf20Sopenharmony_ci		.info = snd_soc_info_enum_double,
2118c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_WRITE,
2128c2ecf20Sopenharmony_ci		.put = fsl_audmix_put_out_src,
2138c2ecf20Sopenharmony_ci		.private_value = (unsigned long)&fsl_audmix_enum[1] },
2148c2ecf20Sopenharmony_ci	SOC_ENUM("Output Width", fsl_audmix_enum[2]),
2158c2ecf20Sopenharmony_ci	SOC_ENUM("Frame Rate Diff Error", fsl_audmix_enum[3]),
2168c2ecf20Sopenharmony_ci	SOC_ENUM("Clock Freq Diff Error", fsl_audmix_enum[4]),
2178c2ecf20Sopenharmony_ci	SOC_ENUM("Sync Mode Config", fsl_audmix_enum[5]),
2188c2ecf20Sopenharmony_ci	SOC_ENUM("Sync Mode Clk Source", fsl_audmix_enum[6]),
2198c2ecf20Sopenharmony_ci	/* TDM1 Attenuation controls */
2208c2ecf20Sopenharmony_ci	SOC_ENUM("TDM1 Attenuation", fsl_audmix_enum[7]),
2218c2ecf20Sopenharmony_ci	SOC_ENUM("TDM1 Attenuation Direction", fsl_audmix_enum[8]),
2228c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM1 Attenuation Step Divider", FSL_AUDMIX_ATCR0,
2238c2ecf20Sopenharmony_ci		   2, 0x00fff, 0),
2248c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM1 Attenuation Initial Value", FSL_AUDMIX_ATIVAL0,
2258c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2268c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM1 Attenuation Step Up Factor", FSL_AUDMIX_ATSTPUP0,
2278c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2288c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM1 Attenuation Step Down Factor", FSL_AUDMIX_ATSTPDN0,
2298c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2308c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM1 Attenuation Step Target", FSL_AUDMIX_ATSTPTGT0,
2318c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2328c2ecf20Sopenharmony_ci	/* TDM2 Attenuation controls */
2338c2ecf20Sopenharmony_ci	SOC_ENUM("TDM2 Attenuation", fsl_audmix_enum[9]),
2348c2ecf20Sopenharmony_ci	SOC_ENUM("TDM2 Attenuation Direction", fsl_audmix_enum[10]),
2358c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM2 Attenuation Step Divider", FSL_AUDMIX_ATCR1,
2368c2ecf20Sopenharmony_ci		   2, 0x00fff, 0),
2378c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM2 Attenuation Initial Value", FSL_AUDMIX_ATIVAL1,
2388c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2398c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM2 Attenuation Step Up Factor", FSL_AUDMIX_ATSTPUP1,
2408c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2418c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM2 Attenuation Step Down Factor", FSL_AUDMIX_ATSTPDN1,
2428c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2438c2ecf20Sopenharmony_ci	SOC_SINGLE("TDM2 Attenuation Step Target", FSL_AUDMIX_ATSTPTGT1,
2448c2ecf20Sopenharmony_ci		   0, 0x3ffff, 0),
2458c2ecf20Sopenharmony_ci};
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct snd_soc_component *comp = dai->component;
2508c2ecf20Sopenharmony_ci	u32 mask = 0, ctr = 0;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* AUDMIX is working in DSP_A format only */
2538c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2548c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
2558c2ecf20Sopenharmony_ci		break;
2568c2ecf20Sopenharmony_ci	default:
2578c2ecf20Sopenharmony_ci		return -EINVAL;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* For playback the AUDMIX is slave, and for record is master */
2618c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2628c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
2638c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
2648c2ecf20Sopenharmony_ci		break;
2658c2ecf20Sopenharmony_ci	default:
2668c2ecf20Sopenharmony_ci		return -EINVAL;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
2708c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_IB_NF:
2718c2ecf20Sopenharmony_ci		/* Output data will be written on positive edge of the clock */
2728c2ecf20Sopenharmony_ci		ctr |= FSL_AUDMIX_CTR_OUTCKPOL(0);
2738c2ecf20Sopenharmony_ci		break;
2748c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF:
2758c2ecf20Sopenharmony_ci		/* Output data will be written on negative edge of the clock */
2768c2ecf20Sopenharmony_ci		ctr |= FSL_AUDMIX_CTR_OUTCKPOL(1);
2778c2ecf20Sopenharmony_ci		break;
2788c2ecf20Sopenharmony_ci	default:
2798c2ecf20Sopenharmony_ci		return -EINVAL;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	mask |= FSL_AUDMIX_CTR_OUTCKPOL_MASK;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return snd_soc_component_update_bits(comp, FSL_AUDMIX_CTR, mask, ctr);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
2888c2ecf20Sopenharmony_ci				  struct snd_soc_dai *dai)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai);
2918c2ecf20Sopenharmony_ci	unsigned long lock_flags;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/* Capture stream shall not be handled */
2948c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2958c2ecf20Sopenharmony_ci		return 0;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	switch (cmd) {
2988c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
2998c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
3008c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3018c2ecf20Sopenharmony_ci		spin_lock_irqsave(&priv->lock, lock_flags);
3028c2ecf20Sopenharmony_ci		priv->tdms |= BIT(dai->driver->id);
3038c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&priv->lock, lock_flags);
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
3068c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
3078c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
3088c2ecf20Sopenharmony_ci		spin_lock_irqsave(&priv->lock, lock_flags);
3098c2ecf20Sopenharmony_ci		priv->tdms &= ~BIT(dai->driver->id);
3108c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&priv->lock, lock_flags);
3118c2ecf20Sopenharmony_ci		break;
3128c2ecf20Sopenharmony_ci	default:
3138c2ecf20Sopenharmony_ci		return -EINVAL;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops fsl_audmix_dai_ops = {
3208c2ecf20Sopenharmony_ci	.set_fmt      = fsl_audmix_dai_set_fmt,
3218c2ecf20Sopenharmony_ci	.trigger      = fsl_audmix_dai_trigger,
3228c2ecf20Sopenharmony_ci};
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver fsl_audmix_dai[] = {
3258c2ecf20Sopenharmony_ci	{
3268c2ecf20Sopenharmony_ci		.id   = 0,
3278c2ecf20Sopenharmony_ci		.name = "audmix-0",
3288c2ecf20Sopenharmony_ci		.playback = {
3298c2ecf20Sopenharmony_ci			.stream_name = "AUDMIX-Playback-0",
3308c2ecf20Sopenharmony_ci			.channels_min = 8,
3318c2ecf20Sopenharmony_ci			.channels_max = 8,
3328c2ecf20Sopenharmony_ci			.rate_min = 8000,
3338c2ecf20Sopenharmony_ci			.rate_max = 96000,
3348c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_96000,
3358c2ecf20Sopenharmony_ci			.formats = FSL_AUDMIX_FORMATS,
3368c2ecf20Sopenharmony_ci		},
3378c2ecf20Sopenharmony_ci		.capture = {
3388c2ecf20Sopenharmony_ci			.stream_name = "AUDMIX-Capture-0",
3398c2ecf20Sopenharmony_ci			.channels_min = 8,
3408c2ecf20Sopenharmony_ci			.channels_max = 8,
3418c2ecf20Sopenharmony_ci			.rate_min = 8000,
3428c2ecf20Sopenharmony_ci			.rate_max = 96000,
3438c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_96000,
3448c2ecf20Sopenharmony_ci			.formats = FSL_AUDMIX_FORMATS,
3458c2ecf20Sopenharmony_ci		},
3468c2ecf20Sopenharmony_ci		.ops = &fsl_audmix_dai_ops,
3478c2ecf20Sopenharmony_ci	},
3488c2ecf20Sopenharmony_ci	{
3498c2ecf20Sopenharmony_ci		.id   = 1,
3508c2ecf20Sopenharmony_ci		.name = "audmix-1",
3518c2ecf20Sopenharmony_ci		.playback = {
3528c2ecf20Sopenharmony_ci			.stream_name = "AUDMIX-Playback-1",
3538c2ecf20Sopenharmony_ci			.channels_min = 8,
3548c2ecf20Sopenharmony_ci			.channels_max = 8,
3558c2ecf20Sopenharmony_ci			.rate_min = 8000,
3568c2ecf20Sopenharmony_ci			.rate_max = 96000,
3578c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_96000,
3588c2ecf20Sopenharmony_ci			.formats = FSL_AUDMIX_FORMATS,
3598c2ecf20Sopenharmony_ci		},
3608c2ecf20Sopenharmony_ci		.capture = {
3618c2ecf20Sopenharmony_ci			.stream_name = "AUDMIX-Capture-1",
3628c2ecf20Sopenharmony_ci			.channels_min = 8,
3638c2ecf20Sopenharmony_ci			.channels_max = 8,
3648c2ecf20Sopenharmony_ci			.rate_min = 8000,
3658c2ecf20Sopenharmony_ci			.rate_max = 96000,
3668c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_96000,
3678c2ecf20Sopenharmony_ci			.formats = FSL_AUDMIX_FORMATS,
3688c2ecf20Sopenharmony_ci		},
3698c2ecf20Sopenharmony_ci		.ops = &fsl_audmix_dai_ops,
3708c2ecf20Sopenharmony_ci	},
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver fsl_audmix_component = {
3748c2ecf20Sopenharmony_ci	.name		  = "fsl-audmix-dai",
3758c2ecf20Sopenharmony_ci	.controls	  = fsl_audmix_snd_controls,
3768c2ecf20Sopenharmony_ci	.num_controls	  = ARRAY_SIZE(fsl_audmix_snd_controls),
3778c2ecf20Sopenharmony_ci};
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic bool fsl_audmix_readable_reg(struct device *dev, unsigned int reg)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	switch (reg) {
3828c2ecf20Sopenharmony_ci	case FSL_AUDMIX_CTR:
3838c2ecf20Sopenharmony_ci	case FSL_AUDMIX_STR:
3848c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATCR0:
3858c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATIVAL0:
3868c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPUP0:
3878c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPDN0:
3888c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPTGT0:
3898c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATTNVAL0:
3908c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTP0:
3918c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATCR1:
3928c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATIVAL1:
3938c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPUP1:
3948c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPDN1:
3958c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPTGT1:
3968c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATTNVAL1:
3978c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTP1:
3988c2ecf20Sopenharmony_ci		return true;
3998c2ecf20Sopenharmony_ci	default:
4008c2ecf20Sopenharmony_ci		return false;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic bool fsl_audmix_writeable_reg(struct device *dev, unsigned int reg)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	switch (reg) {
4078c2ecf20Sopenharmony_ci	case FSL_AUDMIX_CTR:
4088c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATCR0:
4098c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATIVAL0:
4108c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPUP0:
4118c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPDN0:
4128c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPTGT0:
4138c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATCR1:
4148c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATIVAL1:
4158c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPUP1:
4168c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPDN1:
4178c2ecf20Sopenharmony_ci	case FSL_AUDMIX_ATSTPTGT1:
4188c2ecf20Sopenharmony_ci		return true;
4198c2ecf20Sopenharmony_ci	default:
4208c2ecf20Sopenharmony_ci		return false;
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic const struct reg_default fsl_audmix_reg[] = {
4258c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_CTR,       0x00060 },
4268c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_STR,       0x00003 },
4278c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATCR0,     0x00000 },
4288c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATIVAL0,   0x3FFFF },
4298c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTPUP0,  0x2AAAA },
4308c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTPDN0,  0x30000 },
4318c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTPTGT0, 0x00010 },
4328c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATTNVAL0,  0x00000 },
4338c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTP0,    0x00000 },
4348c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATCR1,     0x00000 },
4358c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATIVAL1,   0x3FFFF },
4368c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTPUP1,  0x2AAAA },
4378c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTPDN1,  0x30000 },
4388c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTPTGT1, 0x00010 },
4398c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATTNVAL1,  0x00000 },
4408c2ecf20Sopenharmony_ci	{ FSL_AUDMIX_ATSTP1,    0x00000 },
4418c2ecf20Sopenharmony_ci};
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic const struct regmap_config fsl_audmix_regmap_config = {
4448c2ecf20Sopenharmony_ci	.reg_bits = 32,
4458c2ecf20Sopenharmony_ci	.reg_stride = 4,
4468c2ecf20Sopenharmony_ci	.val_bits = 32,
4478c2ecf20Sopenharmony_ci	.max_register = FSL_AUDMIX_ATSTP1,
4488c2ecf20Sopenharmony_ci	.reg_defaults = fsl_audmix_reg,
4498c2ecf20Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(fsl_audmix_reg),
4508c2ecf20Sopenharmony_ci	.readable_reg = fsl_audmix_readable_reg,
4518c2ecf20Sopenharmony_ci	.writeable_reg = fsl_audmix_writeable_reg,
4528c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_FLAT,
4538c2ecf20Sopenharmony_ci};
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic const struct of_device_id fsl_audmix_ids[] = {
4568c2ecf20Sopenharmony_ci	{
4578c2ecf20Sopenharmony_ci		.compatible = "fsl,imx8qm-audmix",
4588c2ecf20Sopenharmony_ci		.data = "imx-audmix",
4598c2ecf20Sopenharmony_ci	},
4608c2ecf20Sopenharmony_ci	{ /* sentinel */ }
4618c2ecf20Sopenharmony_ci};
4628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_audmix_ids);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int fsl_audmix_probe(struct platform_device *pdev)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
4678c2ecf20Sopenharmony_ci	struct fsl_audmix *priv;
4688c2ecf20Sopenharmony_ci	const char *mdrv;
4698c2ecf20Sopenharmony_ci	const struct of_device_id *of_id;
4708c2ecf20Sopenharmony_ci	void __iomem *regs;
4718c2ecf20Sopenharmony_ci	int ret;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	of_id = of_match_device(fsl_audmix_ids, dev);
4748c2ecf20Sopenharmony_ci	if (!of_id || !of_id->data)
4758c2ecf20Sopenharmony_ci		return -EINVAL;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	mdrv = of_id->data;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4808c2ecf20Sopenharmony_ci	if (!priv)
4818c2ecf20Sopenharmony_ci		return -ENOMEM;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* Get the addresses */
4848c2ecf20Sopenharmony_ci	regs = devm_platform_ioremap_resource(pdev, 0);
4858c2ecf20Sopenharmony_ci	if (IS_ERR(regs))
4868c2ecf20Sopenharmony_ci		return PTR_ERR(regs);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	priv->regmap = devm_regmap_init_mmio_clk(dev, "ipg", regs,
4898c2ecf20Sopenharmony_ci						 &fsl_audmix_regmap_config);
4908c2ecf20Sopenharmony_ci	if (IS_ERR(priv->regmap)) {
4918c2ecf20Sopenharmony_ci		dev_err(dev, "failed to init regmap\n");
4928c2ecf20Sopenharmony_ci		return PTR_ERR(priv->regmap);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	priv->ipg_clk = devm_clk_get(dev, "ipg");
4968c2ecf20Sopenharmony_ci	if (IS_ERR(priv->ipg_clk)) {
4978c2ecf20Sopenharmony_ci		dev_err(dev, "failed to get ipg clock\n");
4988c2ecf20Sopenharmony_ci		return PTR_ERR(priv->ipg_clk);
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	spin_lock_init(&priv->lock);
5028c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
5038c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(dev, &fsl_audmix_component,
5068c2ecf20Sopenharmony_ci					      fsl_audmix_dai,
5078c2ecf20Sopenharmony_ci					      ARRAY_SIZE(fsl_audmix_dai));
5088c2ecf20Sopenharmony_ci	if (ret) {
5098c2ecf20Sopenharmony_ci		dev_err(dev, "failed to register ASoC DAI\n");
5108c2ecf20Sopenharmony_ci		goto err_disable_pm;
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	priv->pdev = platform_device_register_data(dev, mdrv, 0, NULL, 0);
5148c2ecf20Sopenharmony_ci	if (IS_ERR(priv->pdev)) {
5158c2ecf20Sopenharmony_ci		ret = PTR_ERR(priv->pdev);
5168c2ecf20Sopenharmony_ci		dev_err(dev, "failed to register platform %s: %d\n", mdrv, ret);
5178c2ecf20Sopenharmony_ci		goto err_disable_pm;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return 0;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cierr_disable_pm:
5238c2ecf20Sopenharmony_ci	pm_runtime_disable(dev);
5248c2ecf20Sopenharmony_ci	return ret;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic int fsl_audmix_remove(struct platform_device *pdev)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (priv->pdev)
5348c2ecf20Sopenharmony_ci		platform_device_unregister(priv->pdev);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	return 0;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
5408c2ecf20Sopenharmony_cistatic int fsl_audmix_runtime_resume(struct device *dev)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	struct fsl_audmix *priv = dev_get_drvdata(dev);
5438c2ecf20Sopenharmony_ci	int ret;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->ipg_clk);
5468c2ecf20Sopenharmony_ci	if (ret) {
5478c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to enable IPG clock: %d\n", ret);
5488c2ecf20Sopenharmony_ci		return ret;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	regcache_cache_only(priv->regmap, false);
5528c2ecf20Sopenharmony_ci	regcache_mark_dirty(priv->regmap);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return regcache_sync(priv->regmap);
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic int fsl_audmix_runtime_suspend(struct device *dev)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	struct fsl_audmix *priv = dev_get_drvdata(dev);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	regcache_cache_only(priv->regmap, true);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->ipg_clk);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	return 0;
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic const struct dev_pm_ops fsl_audmix_pm = {
5708c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(fsl_audmix_runtime_suspend,
5718c2ecf20Sopenharmony_ci			   fsl_audmix_runtime_resume,
5728c2ecf20Sopenharmony_ci			   NULL)
5738c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
5748c2ecf20Sopenharmony_ci				pm_runtime_force_resume)
5758c2ecf20Sopenharmony_ci};
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic struct platform_driver fsl_audmix_driver = {
5788c2ecf20Sopenharmony_ci	.probe = fsl_audmix_probe,
5798c2ecf20Sopenharmony_ci	.remove = fsl_audmix_remove,
5808c2ecf20Sopenharmony_ci	.driver = {
5818c2ecf20Sopenharmony_ci		.name = "fsl-audmix",
5828c2ecf20Sopenharmony_ci		.of_match_table = fsl_audmix_ids,
5838c2ecf20Sopenharmony_ci		.pm = &fsl_audmix_pm,
5848c2ecf20Sopenharmony_ci	},
5858c2ecf20Sopenharmony_ci};
5868c2ecf20Sopenharmony_cimodule_platform_driver(fsl_audmix_driver);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NXP AUDMIX ASoC DAI driver");
5898c2ecf20Sopenharmony_ciMODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
5908c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:fsl-audmix");
5918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
592