From: Cezary Rojewski <cezary.rojewski@intel.com>
To: Christian Marangi <ansuelsmth@gmail.com>
Cc: Liam Girdwood <lgirdwood@gmail.com>,
Mark Brown <broonie@kernel.org>, "Rob Herring" <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
Matthias Brugger <matthias.bgg@gmail.com>,
"AngeloGioacchino Del Regno"
<angelogioacchino.delregno@collabora.com>,
Philipp Zabel <p.zabel@pengutronix.de>,
Cyril Chao <Cyril.Chao@mediatek.com>,
Darren Ye <darren.ye@mediatek.com>,
Daniel Golle <daniel@makrotopia.org>,
Rosen Penev <rosenp@gmail.com>,
bui duc phuc <phucduc.bui@gmail.com>,
<linux-sound@vger.kernel.org>, <devicetree@vger.kernel.org>,
<linux-kernel@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-mediatek@lists.infradead.org>
Subject: Re: [PATCH v4 4/4] ASoC: airoha: Add AFE and machine driver for Airoha AN7581
Date: Fri, 31 Jul 2026 10:39:44 +0200 [thread overview]
Message-ID: <c1ac7957-dcfc-42b6-bb24-9aa76f9c334a@intel.com> (raw)
In-Reply-To: <20260731064326.2284228-5-ansuelsmth@gmail.com>
On 7/31/2026 8:43 AM, Christian Marangi wrote:
> Add support for the Sound system present on Airoha AN7581 SoC. This is
> based on the mediatek AFE drivers.
>
> Also add the machine driver to create an actual sound card for the AFE.
...
> --- /dev/null
> +++ b/sound/soc/mediatek/an7581/an7581-afe-common.h
> @@ -0,0 +1,50 @@
> +/* 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 <linux/atomic.h>
> +#include <sound/soc.h>
> +#include <linux/list.h>
> +#include <linux/regmap.h>
Sort these, linux/ comes before sound/.
> +#include "../../mediatek/common/mtk-base-afe.h"
> +
> +enum {
> + AN7581_MEMIF_DL1,
> + AN7581_MEMIF_UL1,
> + AN7581_MEMIF_NUM,
> + AN7581_DAI_ETDM = AN7581_MEMIF_NUM,
> + AN7581_DAI_NUM,
> +};
> +
> +enum {
> + AN7581_IRQ_0,
> + AN7581_IRQ_1,
> + AN7581_IRQ_NUM,
> +};
> +
> +struct an7581_memif_irq_desc {
> + u8 irq;
> + u32 status_bit;
> + u32 clear_reg;
> +};
> +
> +struct an7581_afe_private {
> + unsigned int users;
> + /* protect concurrent ETDM user tracking */
> + struct mutex user_lock;
> +
> + /* dai */
> + void *dai_priv[AN7581_DAI_NUM];
The comment is redundant.
> +};
> +
> +unsigned int an7581_afe_rate_transform(struct device *dev,
> + unsigned int rate);
> +
> +/* dai register */
> +int an7581_dai_etdm_register(struct mtk_base_afe *afe);
Ditto.
> +
> +#endif
...
> +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);
Three '!', really? :)
> + return ARH_AFE_RATE_48K;
> + }
> +}
> +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 takes care of this unless you want to explicitly state the
fifo_size must be 0 - in such case comment is necessary, otherwise drop
the assignment.
> +};
> +
> +static int an7581_memif_fs(struct snd_pcm_substream *substream,
> + unsigned int rate)
For the entire file - char limit is 100, there is no reason not to
utilize it.
> +{
> + 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);
> +}
These two functions seem to be identical.
> +
> +static int an7581_afe_fe_startup(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_pcm_runtime *runtime = substream->runtime;
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + int ret;
> +
> + ret = mtk_afe_fe_startup(substream, dai);
> + if (ret < 0)
> + return ret;
> +
> + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> + ret = snd_pcm_hw_constraint_minmax(runtime,
> + SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
> + 0x2000, UINT_MAX);
> + if (ret < 0)
> + dev_err(afe->dev, "hw_constraint_minmax failed\n");
> + }
> +
> + return ret;
mtk_afe_fe_startup() acquires irq via mtk_dynamic_irq_acquire(). Do we
need to unwind the process if snd_pcm_hw_constraint_minmax() fails?
> +}
...
> +static int an7581_afe_pcm_dev_probe(struct platform_device *pdev)
> +{
> + struct an7581_afe_private *afe_priv;
> + struct reset_control *reset;
> + struct mtk_base_afe *afe;
> + struct device *dev;
> + int i, irq_id, ret;
> + void *base;
> +
> + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
> + if (!afe)
> + return -ENOMEM;
> + platform_set_drvdata(pdev, afe);
Typically drvdata is assigned last, one we know probe() is successful.
Is there some specific reason why you assign the pointer immediately?
> +
> + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
> + GFP_KERNEL);
> + if (!afe->platform_priv)
> + return -ENOMEM;
Especially when the memory allocation is still ongoing..
> +
> + afe_priv = afe->platform_priv;
> + mutex_init(&afe_priv->user_lock);
> + afe->dev = &pdev->dev;
> + dev = afe->dev;
> +
> + reset = devm_reset_control_get_exclusive(dev, NULL);
> + if (IS_ERR(reset))
> + return PTR_ERR(reset);
> +
> + /* Global reset I2S */
> + reset_control_assert(reset);
> + usleep_range(10, 20);
> + reset_control_deassert(reset);
> +
> + afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(afe->base_addr))
> + return PTR_ERR(afe->base_addr);
> +
> + base = devm_platform_ioremap_resource(pdev, 1);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + ret = devm_pm_runtime_enable(dev);
> + if (ret)
> + return ret;
> +
> + afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
> + &an7581_afe_regmap_config);
> + 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;
If the size is known upfront, I'd just move all the allocations to the top.
> +
> + for (i = 0; i < afe->irqs_size; i++)
> + afe->irqs[i].irq_data = &irq_data[i];
> +
> + afe->irqs[AN7581_IRQ_0].regmap = afe->regmap;
> + afe->irqs[AN7581_IRQ_1].regmap = devm_regmap_init_mmio(&pdev->dev, base,
> + &an7581_afe_irq1_regmap_config);
> + if (IS_ERR(afe->irqs[AN7581_IRQ_1].regmap))
> + return PTR_ERR(afe->irqs[AN7581_IRQ_1].regmap);
> +
> + /* request irq */
> + irq_id = platform_get_irq(pdev, 0);
> + if (irq_id < 0)
> + return irq_id;
> +
> + /* 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_irq_descs[i].irq;
> +
> + 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);
> +
> + 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");
> +
> + 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;
> +
> + /* 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;
> +}
...
> +/* dai ops */
> +static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct an7581_afe_private *afe_priv = afe->platform_priv;
> +
> + regmap_set_bits(afe->regmap, AFE_DAC_CON0,
> + BIT(AFE_AFE_ENABLE_SHIFT));
> +
> + mutex_lock(&afe_priv->user_lock);
I'd suggest to switch to guards, see cleanup.h.
> + afe_priv->users++;
> + mutex_unlock(&afe_priv->user_lock);
> +
> + return 0;
Why skip the return code of regmap_set_bits()?
> +}
> +
> +static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct an7581_afe_private *afe_priv = afe->platform_priv;
> +
> + mutex_lock(&afe_priv->user_lock);
> + afe_priv->users--;
> + if (!afe_priv->users)
> + regmap_clear_bits(afe->regmap, AFE_DAC_CON0,
> + BIT(AFE_AFE_ENABLE_SHIFT));
> + mutex_unlock(&afe_priv->user_lock);
Well, here we clear bits in locked state whereas above they're set
unlocked. Typically such inconsistency translates to an issue.
> +}
> +
> +static unsigned int get_etdm_ch_fixup(unsigned int channels)
> +{
> + if (channels > 16)
> + return 24;
> + else if (channels > 8)
> + return 16;
> + else if (channels > 4)
> + return 8;
> + else if (channels > 2)
> + return 4;
> + else
> + return 2;
Refactor, not a single 'else-if' is needed here as well as 'else'.
If a preceding if-statement ends with 'return' there is no elsing anything.
> +}
> +
> +static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
> + struct snd_pcm_hw_params *params,
> + struct snd_soc_dai *dai,
> + int stream)
> +{
> + struct an7581_afe_private *afe_priv = afe->platform_priv;
> + struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
> + unsigned int rate = params_rate(params);
> + unsigned int etdm_rate = an7581_etdm_rate_transform(afe->dev, rate);
> + unsigned int channels = params_channels(params);
> + unsigned int bit_width = params_width(params);
> + unsigned int wlen = get_etdm_wlen(bit_width);
All the format variables are used once or twice. I'd drop them. Right
now you have 11 (!) locals on the stack.
> + unsigned int val = 0, val1 = 0;
> + unsigned int mask = 0, mask1 = 0;
> +
> + dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
> + __func__, stream, rate, bit_width);
> +
> + /* CON0 */
> + mask |= ETDM_SLAVE_MODE;
> + if (etdm_data->slave_mode)
> + val |= ETDM_SLAVE_MODE;
> + mask |= ETDM_BIT_LEN;
> + val |= FIELD_PREP(ETDM_BIT_LEN, bit_width - 1);
> + mask |= ETDM_WRD_LEN;
> + val |= FIELD_PREP(ETDM_WRD_LEN, wlen - 1);
> + mask |= ETDM_FMT;
> + val |= FIELD_PREP(ETDM_FMT, etdm_data->format);
> + mask |= ETDM_CH_NUM;
> + val |= FIELD_PREP(ETDM_CH_NUM, get_etdm_ch_fixup(channels) - 1);
I'd group 'mask' and 'val' together, easier to follow. These do not seem
intertwined.
> +
> + /* CON1 */
> + mask1 |= EDTM_LRCK_AUTO_MODE;
> + val1 |= EDTM_LRCK_AUTO_MODE;
> + mask1 |= EDTM_CKEN_SEL;
> + val1 |= EDTM_CKEN_SEL;
> + mask1 |= EDTM_LRCK_AUTO_OFF;
> + val1 |= EDTM_LRCK_AUTO_OFF;
> + mask1 |= EDTM_INITIAL_POINT;
> + val1 |= FIELD_PREP(EDTM_INITIAL_POINT, 14);
> + mask1 |= EDTM_INITIAL_COUNT;
> + val1 |= FIELD_PREP(EDTM_INITIAL_COUNT, 14);
Ditto.
> +
> + switch (stream) {
> + case SNDRV_PCM_STREAM_PLAYBACK:
> + /* set ETDM_OUT1_CON0 */
> + regmap_update_bits(afe->regmap, ETDM_OUT1_CON0, mask, val);
> +
> + mask1 |= EDTM_DIRECT_INPUT_MASTER_BCK;
> + val1 |= EDTM_DIRECT_INPUT_MASTER_BCK;
> +
> + /* set ETDM_OUT1_CON1 */
> + regmap_update_bits(afe->regmap, ETDM_OUT1_CON1, mask1, val1);
> +
> + /* set ETDM_OUT1_CON4 */
> + regmap_update_bits(afe->regmap, ETDM_OUT1_CON4, OUT_SEL_FS,
> + FIELD_PREP(OUT_SEL_FS, etdm_rate));
> +
> + regmap_update_bits(afe->irqs[AN7581_IRQ_0].regmap,
> + afe->irqs[AN7581_IRQ_0].irq_data->irq_en_reg,
> + AFE_IRQ_EN_SEL, AFE_IRQ_EN_SEL_I2SOUT);
> + break;
> + case SNDRV_PCM_STREAM_CAPTURE:
> + /* set ETDM_IN1_CON0 */
> + regmap_update_bits(afe->regmap, ETDM_IN1_CON0, mask, val);
> +
> + /* set ETDM_IN1_CON1 */
> + regmap_update_bits(afe->regmap, ETDM_IN1_CON1, mask1, val1);
> +
> + /* set ETDM_IN1_CON3 */
All the comments found in this function do not explain anything. Drop them.
> + regmap_update_bits(afe->regmap, ETDM_IN1_CON3, IN_SEL_FS,
> + FIELD_PREP(IN_SEL_FS, etdm_rate));
> +
> + regmap_update_bits(afe->irqs[AN7581_IRQ_1].regmap,
> + afe->irqs[AN7581_IRQ_1].irq_data->irq_en_reg,
> + AFE_IRQ_EN_SEL, AFE_IRQ_EN_SEL_I2SIN);
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params,
> + struct snd_soc_dai *dai)
> +{
> + unsigned int rate = params_rate(params);
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> +
> + regmap_update_bits(afe->regmap, ETDM_COWORK_CON0,
> + EDTM_IN1_SLAVE_SEL,
> + EDTM_IN1_SLAVE_FROM_ETDMIN1_SLAVE);
> + regmap_update_bits(afe->regmap, ETDM_COWORK_CON0,
> + EDTM_OUT1_SLAVE_SEL,
> + EDTM_OUT1_SLAVE_FROM_ETDMOUT1_SLAVE);
> + regmap_update_bits(afe->regmap, ETDM_COWORK_CON1,
> + EDTM_IN1_SDATA0_SEL,
> + EDTM_IN1_SDATA0_FROM_PAD);
> +
> + switch (rate) {
> + case 7350:
> + case 8000:
> + case 11025:
> + case 12000:
> + case 14700:
> + case 16000:
> + case 22050:
> + case 24000:
> + case 29400:
> + case 32000:
> + case 44100:
> + case 48000:
> + case 88200:
> + case 96000:
> + case 176400:
> + case 192000:
> + case 352800:
> + case 384000:
> + mtk_dai_etdm_config(afe, params, dai, substream->stream);
> + return 0;
Again, skipping return code of the main procedure. I'd avoid blind
'return 0'.
> + default:
> + dev_err(afe->dev,
> + "Sample rate %d invalid\n",
> + rate);
> + return -EINVAL;
> + }
> +}
...
> +static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> +{
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct an7581_afe_private *afe_priv = afe->platform_priv;
> + struct mtk_dai_etdm_priv *etdm_data;
> + void *priv_data;
> +
> + switch (dai->id) {
> + case AN7581_DAI_ETDM:
> + break;
> + default:
> + dev_warn(afe->dev, "%s(), id %d not support\n",
> + __func__, dai->id);
s/support/supported/
Though this entire check looks weird. Why should set_fmt() care about
DAI's ID? Such check shall be done once, early with the rest of the
runtime doing just the important stuff.
> + return -EINVAL;
> + }
> +
> + priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
> + GFP_KERNEL);
> + if (!priv_data)
> + return -ENOMEM;
> +
> + afe_priv->dai_priv[dai->id] = priv_data;
> + etdm_data = afe_priv->dai_priv[dai->id];
> +
> + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> + case SND_SOC_DAIFMT_I2S:
> + etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
> + break;
> + case SND_SOC_DAIFMT_DSP_A:
> + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
> + break;
> + case SND_SOC_DAIFMT_DSP_B:
> + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
> + break;
> + default:
> + return -EINVAL;
> + }
Please waterfall the points to all the functions/files. I can do another
round once this batch is addressed or explained first.
Kind regards,
Czarek
prev parent reply other threads:[~2026-07-31 8:39 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 6:43 [PATCH v4 0/4] ASoC: Add support for Airoha AN7581 Christian Marangi
2026-07-31 6:43 ` [PATCH v4 1/4] ASoC: dt-bindings: Add Airoha AN7581 AFE Sound card Christian Marangi
2026-07-31 6:43 ` [PATCH v4 2/4] ASoC: dt-bindings: Add Airoha AN7581 AFE with WM8960 Codec schema Christian Marangi
2026-07-31 6:43 ` [PATCH v4 3/4] ASoC: mediatek: common: permit to provide dedicated regmap for irq Christian Marangi
2026-07-31 6:43 ` [PATCH v4 4/4] ASoC: airoha: Add AFE and machine driver for Airoha AN7581 Christian Marangi
2026-07-31 6:58 ` sashiko-bot
2026-07-31 8:39 ` Cezary Rojewski [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c1ac7957-dcfc-42b6-bb24-9aa76f9c334a@intel.com \
--to=cezary.rojewski@intel.com \
--cc=Cyril.Chao@mediatek.com \
--cc=angelogioacchino.delregno@collabora.com \
--cc=ansuelsmth@gmail.com \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=daniel@makrotopia.org \
--cc=darren.ye@mediatek.com \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-sound@vger.kernel.org \
--cc=matthias.bgg@gmail.com \
--cc=p.zabel@pengutronix.de \
--cc=perex@perex.cz \
--cc=phucduc.bui@gmail.com \
--cc=robh@kernel.org \
--cc=rosenp@gmail.com \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox