All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jiaxin Yu <jiaxin.yu@mediatek.com>
To: Mark Brown <broonie@kernel.org>
Cc: <matthias.bgg@gmail.com>, <robh+dt@kernel.org>, <tiwai@suse.com>,
	<linux-kernel@vger.kernel.org>, <alsa-devel@alsa-project.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-mediatek@lists.infradead.org>, <howie.huang@mediatek.com>,
	<tzungbi@google.com>, <eason.yen@mediatek.com>,
	<shane.chien@mediatek.com>
Subject: Re: [PATCH v2 1/2] ASoC: mediatek: mt6359: add codec driver
Date: Wed, 12 Aug 2020 15:29:13 +0800	[thread overview]
Message-ID: <1597217353.23246.45.camel@mhfsdcap03> (raw)
In-Reply-To: <20200810185933.GI6438@sirena.org.uk>

On Mon, 2020-08-10 at 19:59 +0100, Mark Brown wrote:
> On Mon, Aug 10, 2020 at 11:05:53AM +0800, Jiaxin Yu wrote:
> 
> > +void mt6359_set_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_reset_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_set_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> > +void mt6359_reset_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> What are these, should they not be managed through gpiolib and/or
> pinctrl?

These are the functions that control the mux of input or output
signal. I refer to the other codec drivers, most of them are manipulate
the regs in their codec drivers also. Maybe it's easier to control?

> > +/* use only when doing mtkaif calibraiton at the boot time */
> > +static int mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
> > +{
> > +	regmap_update_bits(priv->regmap, MT6359_DCXO_CW12,
> > +			   0x1 << RG_XO_AUDIO_EN_M_SFT,
> > +			   (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
> > +	return 0;
> 
> Either don't have a return value or use the result of
> regmap_update_bits().  There's similar issues with some other functions
> in here.
> 

Yes, I will refine them.

> > +int mt6359_mtkaif_calibration_enable(struct snd_soc_pcm_runtime *rtd)
> > +{
> 
> > +EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_enable);
> 
> Why is this exported?
> 

This function is exported to machine driver to do calibration when
registering. The interface between MT6359 and MTK SoC is a special
interface that named MTKAIF. Therefore, if MT6359 is to be used
normally, it needs to rely on the platform for calibration when
registering.

> > +static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up)
> > +{
> > +	int i = 0, stage = 0;
> > +
> > +	/* Reduce HP aux feedback loop gain step by step */
> > +	for (i = 0; i <= 0xf; i++) {
> > +		stage = up ? i : 0xf - i;
> 
> Please write normal conditional statements, it helps legibility.
> 

/* Increase/Reduce HP aux feedback loop gain step by step */
This is to prevent sudden changes in volume.

> > +static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
> > +			    struct snd_ctl_elem_value *ucontrol)
> > +{
> > +	struct snd_soc_component *component =
> > +			snd_soc_kcontrol_component(kcontrol);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
> > +	struct soc_mixer_control *mc =
> > +			(struct soc_mixer_control *)kcontrol->private_value;
> > +	unsigned int reg;
> > +	int index = ucontrol->value.integer.value[0];
> > +	int ret;
> > +
> > +	ret = snd_soc_put_volsw(kcontrol, ucontrol);
> > +	if (ret < 0)
> > +		return ret;
> 
> So we make the volume change actually take effect...
> 
> > +	switch (mc->reg) {
> > +	case MT6359_ZCD_CON2:
> > +		regmap_read(priv->regmap, MT6359_ZCD_CON2, &reg);
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] =
> > +			(reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
> > +			(reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
> > +		break;
> 
> ..then read the value that was set and store it elsewhere.  What's
> going on here?
> 

Because we can adjust the volume at two points, before and during the
playback or capture. In addition, we will do volume ramp when opening
the driver. If we set the volume before opening the driver, we need get
the value to do volume ramp during opening the driver.

> > +/*HP MUX */
> > +static const char * const hp_in_mux_map[] = {
> > +	"Open",
> > +	"LoudSPK Playback",
> > +	"Audio Playback",
> > +	"Test Mode",
> > +	"HP Impedance",
> > +	"undefined1",
> > +	"undefined2",
> > +	"undefined3",
> > +};
> 
> Why expose undefined (and presumably out of spec) values to userspace?
> 

Removed them.

> > +static int mt_clksq_event(struct snd_soc_dapm_widget *w,
> > +			  struct snd_kcontrol *kcontrol,
> > +			  int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +
> > +	dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		/* audio clk source from internal dcxo */
> > +		regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23,
> > +				   RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
> > +				   0x0);
> 
> This also appeared to be controlled in _set_clkseq() - are we sure that
> things couldn't get confused about the state?
> 

_set_clkseq() will only be run at the time of mtkaif calibraiton, and
the calibration only run once when the codec driver probe. So it won't
get confused about the state. But it really only needs to be set up once
at mt6359_codec_init_reg(). I will remove the unnecesary settings.

> > +	/* HP damp circuit enable */
> > +	/*Enable HPRN/HPLN output 4K to VCM */
> 
> Spaces around the /* */
> 

Sorry, fixed it.

> > +static int mt_hp_event(struct snd_soc_dapm_widget *w,
> > +		       struct snd_kcontrol *kcontrol,
> > +		       int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +	unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
> > +	int device = DEVICE_HP;
> > +
> > +	dev_dbg(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n",
> > +		__func__, event, priv->dev_counter[device], mux);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		priv->dev_counter[device]++;
> > +		if (priv->dev_counter[device] > 1)
> > +			break;	/* already enabled, do nothing */
> > +		else if (priv->dev_counter[device] <= 0)
> 
> Why are we doing additional refcounting on top of what DAPM is doing?
> This seems like there should be at least one widget representing the
> shared bits of the audio path.
> 

We have "HPL Mux" and "HPR Mux", there will be two paths enabled when
playback throuh HP. But actually they share the same control sequences.
So in order to prevent setting it one more time we do additional
refcouting.


> > +#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
> > +			SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\
> > +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
> > +			SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\
> > +			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
> > +			SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE)
> 
> The driver doesn't appear to configure anything except the sample rate -
> how are all these formats supported?
> 

The interface between MT6359 and MTK SoC is a special interface that
named MTKAIF. Because of its unique hardware settings, it really doesn't
to set format argument. The capability of pcm driver mainly depends on
cpu-dai driver to limit.

> > +	/* hp gain ctl default choose ZCD */
> > +	priv->hp_gain_ctl = HP_GAIN_CTL_ZCD;
> > +	hp_gain_ctl_select(priv, priv->hp_gain_ctl);
> 
> Why not use the hardware default?
> 

We have two ways to control the volume, there is to select ZCD. Because
the other one it not often used, ZCD is used by default. 

> > +	mt6359_codec_init_reg(cmpnt);
> > +
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3] = 3;
> 
> Same here.
> 

Removed them.

> > +	ret = regulator_enable(priv->avdd_reg);
> > +	if (ret) {
> > +		dev_err(priv->dev, "%s(), failed to enable regulator!\n",
> > +			__func__);
> > +		return ret;
> > +	}
> 
> Perhaps make this a DAPM widget?
> 

"vaud18" needs to be always on so we enable it when codec probe.

> > +	priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18");
> > +	if (IS_ERR(priv->avdd_reg)) {
> > +		dev_err(&pdev->dev, "%s(), have no vaud18 supply", __func__);
> > +		return PTR_ERR(priv->avdd_reg);
> > +	}
> 
> It's better to print error codes to help people debugging problems.
> 

Yes, I will print the error codes.

> > +static const struct of_device_id mt6359_of_match[] = {
> > +	{.compatible = "mediatek,mt6359-sound",},
> > +	{}
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6359_of_match);
> 
> We don't need a compatible here, we know that this device is here since
> it's part of the parent device and isn't something that might appear in
> another device.  This is reflecting the Linux driver model, not the
> hardware.

Removed them.

WARNING: multiple messages have this Message-ID (diff)
From: Jiaxin Yu <jiaxin.yu@mediatek.com>
To: Mark Brown <broonie@kernel.org>
Cc: alsa-devel@alsa-project.org, shane.chien@mediatek.com,
	howie.huang@mediatek.com, tiwai@suse.com,
	linux-kernel@vger.kernel.org, tzungbi@google.com,
	robh+dt@kernel.org, linux-mediatek@lists.infradead.org,
	eason.yen@mediatek.com, matthias.bgg@gmail.com,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v2 1/2] ASoC: mediatek: mt6359: add codec driver
Date: Wed, 12 Aug 2020 15:29:13 +0800	[thread overview]
Message-ID: <1597217353.23246.45.camel@mhfsdcap03> (raw)
In-Reply-To: <20200810185933.GI6438@sirena.org.uk>

On Mon, 2020-08-10 at 19:59 +0100, Mark Brown wrote:
> On Mon, Aug 10, 2020 at 11:05:53AM +0800, Jiaxin Yu wrote:
> 
> > +void mt6359_set_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_reset_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_set_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> > +void mt6359_reset_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> What are these, should they not be managed through gpiolib and/or
> pinctrl?

These are the functions that control the mux of input or output
signal. I refer to the other codec drivers, most of them are manipulate
the regs in their codec drivers also. Maybe it's easier to control?

> > +/* use only when doing mtkaif calibraiton at the boot time */
> > +static int mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
> > +{
> > +	regmap_update_bits(priv->regmap, MT6359_DCXO_CW12,
> > +			   0x1 << RG_XO_AUDIO_EN_M_SFT,
> > +			   (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
> > +	return 0;
> 
> Either don't have a return value or use the result of
> regmap_update_bits().  There's similar issues with some other functions
> in here.
> 

Yes, I will refine them.

> > +int mt6359_mtkaif_calibration_enable(struct snd_soc_pcm_runtime *rtd)
> > +{
> 
> > +EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_enable);
> 
> Why is this exported?
> 

This function is exported to machine driver to do calibration when
registering. The interface between MT6359 and MTK SoC is a special
interface that named MTKAIF. Therefore, if MT6359 is to be used
normally, it needs to rely on the platform for calibration when
registering.

> > +static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up)
> > +{
> > +	int i = 0, stage = 0;
> > +
> > +	/* Reduce HP aux feedback loop gain step by step */
> > +	for (i = 0; i <= 0xf; i++) {
> > +		stage = up ? i : 0xf - i;
> 
> Please write normal conditional statements, it helps legibility.
> 

/* Increase/Reduce HP aux feedback loop gain step by step */
This is to prevent sudden changes in volume.

> > +static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
> > +			    struct snd_ctl_elem_value *ucontrol)
> > +{
> > +	struct snd_soc_component *component =
> > +			snd_soc_kcontrol_component(kcontrol);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
> > +	struct soc_mixer_control *mc =
> > +			(struct soc_mixer_control *)kcontrol->private_value;
> > +	unsigned int reg;
> > +	int index = ucontrol->value.integer.value[0];
> > +	int ret;
> > +
> > +	ret = snd_soc_put_volsw(kcontrol, ucontrol);
> > +	if (ret < 0)
> > +		return ret;
> 
> So we make the volume change actually take effect...
> 
> > +	switch (mc->reg) {
> > +	case MT6359_ZCD_CON2:
> > +		regmap_read(priv->regmap, MT6359_ZCD_CON2, &reg);
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] =
> > +			(reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
> > +			(reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
> > +		break;
> 
> ..then read the value that was set and store it elsewhere.  What's
> going on here?
> 

Because we can adjust the volume at two points, before and during the
playback or capture. In addition, we will do volume ramp when opening
the driver. If we set the volume before opening the driver, we need get
the value to do volume ramp during opening the driver.

> > +/*HP MUX */
> > +static const char * const hp_in_mux_map[] = {
> > +	"Open",
> > +	"LoudSPK Playback",
> > +	"Audio Playback",
> > +	"Test Mode",
> > +	"HP Impedance",
> > +	"undefined1",
> > +	"undefined2",
> > +	"undefined3",
> > +};
> 
> Why expose undefined (and presumably out of spec) values to userspace?
> 

Removed them.

> > +static int mt_clksq_event(struct snd_soc_dapm_widget *w,
> > +			  struct snd_kcontrol *kcontrol,
> > +			  int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +
> > +	dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		/* audio clk source from internal dcxo */
> > +		regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23,
> > +				   RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
> > +				   0x0);
> 
> This also appeared to be controlled in _set_clkseq() - are we sure that
> things couldn't get confused about the state?
> 

_set_clkseq() will only be run at the time of mtkaif calibraiton, and
the calibration only run once when the codec driver probe. So it won't
get confused about the state. But it really only needs to be set up once
at mt6359_codec_init_reg(). I will remove the unnecesary settings.

> > +	/* HP damp circuit enable */
> > +	/*Enable HPRN/HPLN output 4K to VCM */
> 
> Spaces around the /* */
> 

Sorry, fixed it.

> > +static int mt_hp_event(struct snd_soc_dapm_widget *w,
> > +		       struct snd_kcontrol *kcontrol,
> > +		       int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +	unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
> > +	int device = DEVICE_HP;
> > +
> > +	dev_dbg(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n",
> > +		__func__, event, priv->dev_counter[device], mux);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		priv->dev_counter[device]++;
> > +		if (priv->dev_counter[device] > 1)
> > +			break;	/* already enabled, do nothing */
> > +		else if (priv->dev_counter[device] <= 0)
> 
> Why are we doing additional refcounting on top of what DAPM is doing?
> This seems like there should be at least one widget representing the
> shared bits of the audio path.
> 

We have "HPL Mux" and "HPR Mux", there will be two paths enabled when
playback throuh HP. But actually they share the same control sequences.
So in order to prevent setting it one more time we do additional
refcouting.


> > +#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
> > +			SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\
> > +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
> > +			SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\
> > +			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
> > +			SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE)
> 
> The driver doesn't appear to configure anything except the sample rate -
> how are all these formats supported?
> 

The interface between MT6359 and MTK SoC is a special interface that
named MTKAIF. Because of its unique hardware settings, it really doesn't
to set format argument. The capability of pcm driver mainly depends on
cpu-dai driver to limit.

> > +	/* hp gain ctl default choose ZCD */
> > +	priv->hp_gain_ctl = HP_GAIN_CTL_ZCD;
> > +	hp_gain_ctl_select(priv, priv->hp_gain_ctl);
> 
> Why not use the hardware default?
> 

We have two ways to control the volume, there is to select ZCD. Because
the other one it not often used, ZCD is used by default. 

> > +	mt6359_codec_init_reg(cmpnt);
> > +
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3] = 3;
> 
> Same here.
> 

Removed them.

> > +	ret = regulator_enable(priv->avdd_reg);
> > +	if (ret) {
> > +		dev_err(priv->dev, "%s(), failed to enable regulator!\n",
> > +			__func__);
> > +		return ret;
> > +	}
> 
> Perhaps make this a DAPM widget?
> 

"vaud18" needs to be always on so we enable it when codec probe.

> > +	priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18");
> > +	if (IS_ERR(priv->avdd_reg)) {
> > +		dev_err(&pdev->dev, "%s(), have no vaud18 supply", __func__);
> > +		return PTR_ERR(priv->avdd_reg);
> > +	}
> 
> It's better to print error codes to help people debugging problems.
> 

Yes, I will print the error codes.

> > +static const struct of_device_id mt6359_of_match[] = {
> > +	{.compatible = "mediatek,mt6359-sound",},
> > +	{}
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6359_of_match);
> 
> We don't need a compatible here, we know that this device is here since
> it's part of the parent device and isn't something that might appear in
> another device.  This is reflecting the Linux driver model, not the
> hardware.

Removed them.

WARNING: multiple messages have this Message-ID (diff)
From: Jiaxin Yu <jiaxin.yu@mediatek.com>
To: Mark Brown <broonie@kernel.org>
Cc: alsa-devel@alsa-project.org, shane.chien@mediatek.com,
	howie.huang@mediatek.com, tiwai@suse.com,
	linux-kernel@vger.kernel.org, tzungbi@google.com,
	robh+dt@kernel.org, linux-mediatek@lists.infradead.org,
	eason.yen@mediatek.com, matthias.bgg@gmail.com,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v2 1/2] ASoC: mediatek: mt6359: add codec driver
Date: Wed, 12 Aug 2020 15:29:13 +0800	[thread overview]
Message-ID: <1597217353.23246.45.camel@mhfsdcap03> (raw)
In-Reply-To: <20200810185933.GI6438@sirena.org.uk>

On Mon, 2020-08-10 at 19:59 +0100, Mark Brown wrote:
> On Mon, Aug 10, 2020 at 11:05:53AM +0800, Jiaxin Yu wrote:
> 
> > +void mt6359_set_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_reset_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_set_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> > +void mt6359_reset_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> What are these, should they not be managed through gpiolib and/or
> pinctrl?

These are the functions that control the mux of input or output
signal. I refer to the other codec drivers, most of them are manipulate
the regs in their codec drivers also. Maybe it's easier to control?

> > +/* use only when doing mtkaif calibraiton at the boot time */
> > +static int mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
> > +{
> > +	regmap_update_bits(priv->regmap, MT6359_DCXO_CW12,
> > +			   0x1 << RG_XO_AUDIO_EN_M_SFT,
> > +			   (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
> > +	return 0;
> 
> Either don't have a return value or use the result of
> regmap_update_bits().  There's similar issues with some other functions
> in here.
> 

Yes, I will refine them.

> > +int mt6359_mtkaif_calibration_enable(struct snd_soc_pcm_runtime *rtd)
> > +{
> 
> > +EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_enable);
> 
> Why is this exported?
> 

This function is exported to machine driver to do calibration when
registering. The interface between MT6359 and MTK SoC is a special
interface that named MTKAIF. Therefore, if MT6359 is to be used
normally, it needs to rely on the platform for calibration when
registering.

> > +static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up)
> > +{
> > +	int i = 0, stage = 0;
> > +
> > +	/* Reduce HP aux feedback loop gain step by step */
> > +	for (i = 0; i <= 0xf; i++) {
> > +		stage = up ? i : 0xf - i;
> 
> Please write normal conditional statements, it helps legibility.
> 

/* Increase/Reduce HP aux feedback loop gain step by step */
This is to prevent sudden changes in volume.

> > +static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
> > +			    struct snd_ctl_elem_value *ucontrol)
> > +{
> > +	struct snd_soc_component *component =
> > +			snd_soc_kcontrol_component(kcontrol);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
> > +	struct soc_mixer_control *mc =
> > +			(struct soc_mixer_control *)kcontrol->private_value;
> > +	unsigned int reg;
> > +	int index = ucontrol->value.integer.value[0];
> > +	int ret;
> > +
> > +	ret = snd_soc_put_volsw(kcontrol, ucontrol);
> > +	if (ret < 0)
> > +		return ret;
> 
> So we make the volume change actually take effect...
> 
> > +	switch (mc->reg) {
> > +	case MT6359_ZCD_CON2:
> > +		regmap_read(priv->regmap, MT6359_ZCD_CON2, &reg);
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] =
> > +			(reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
> > +			(reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
> > +		break;
> 
> ..then read the value that was set and store it elsewhere.  What's
> going on here?
> 

Because we can adjust the volume at two points, before and during the
playback or capture. In addition, we will do volume ramp when opening
the driver. If we set the volume before opening the driver, we need get
the value to do volume ramp during opening the driver.

> > +/*HP MUX */
> > +static const char * const hp_in_mux_map[] = {
> > +	"Open",
> > +	"LoudSPK Playback",
> > +	"Audio Playback",
> > +	"Test Mode",
> > +	"HP Impedance",
> > +	"undefined1",
> > +	"undefined2",
> > +	"undefined3",
> > +};
> 
> Why expose undefined (and presumably out of spec) values to userspace?
> 

Removed them.

> > +static int mt_clksq_event(struct snd_soc_dapm_widget *w,
> > +			  struct snd_kcontrol *kcontrol,
> > +			  int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +
> > +	dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		/* audio clk source from internal dcxo */
> > +		regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23,
> > +				   RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
> > +				   0x0);
> 
> This also appeared to be controlled in _set_clkseq() - are we sure that
> things couldn't get confused about the state?
> 

_set_clkseq() will only be run at the time of mtkaif calibraiton, and
the calibration only run once when the codec driver probe. So it won't
get confused about the state. But it really only needs to be set up once
at mt6359_codec_init_reg(). I will remove the unnecesary settings.

> > +	/* HP damp circuit enable */
> > +	/*Enable HPRN/HPLN output 4K to VCM */
> 
> Spaces around the /* */
> 

Sorry, fixed it.

> > +static int mt_hp_event(struct snd_soc_dapm_widget *w,
> > +		       struct snd_kcontrol *kcontrol,
> > +		       int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +	unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
> > +	int device = DEVICE_HP;
> > +
> > +	dev_dbg(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n",
> > +		__func__, event, priv->dev_counter[device], mux);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		priv->dev_counter[device]++;
> > +		if (priv->dev_counter[device] > 1)
> > +			break;	/* already enabled, do nothing */
> > +		else if (priv->dev_counter[device] <= 0)
> 
> Why are we doing additional refcounting on top of what DAPM is doing?
> This seems like there should be at least one widget representing the
> shared bits of the audio path.
> 

We have "HPL Mux" and "HPR Mux", there will be two paths enabled when
playback throuh HP. But actually they share the same control sequences.
So in order to prevent setting it one more time we do additional
refcouting.


> > +#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
> > +			SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\
> > +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
> > +			SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\
> > +			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
> > +			SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE)
> 
> The driver doesn't appear to configure anything except the sample rate -
> how are all these formats supported?
> 

The interface between MT6359 and MTK SoC is a special interface that
named MTKAIF. Because of its unique hardware settings, it really doesn't
to set format argument. The capability of pcm driver mainly depends on
cpu-dai driver to limit.

> > +	/* hp gain ctl default choose ZCD */
> > +	priv->hp_gain_ctl = HP_GAIN_CTL_ZCD;
> > +	hp_gain_ctl_select(priv, priv->hp_gain_ctl);
> 
> Why not use the hardware default?
> 

We have two ways to control the volume, there is to select ZCD. Because
the other one it not often used, ZCD is used by default. 

> > +	mt6359_codec_init_reg(cmpnt);
> > +
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3] = 3;
> 
> Same here.
> 

Removed them.

> > +	ret = regulator_enable(priv->avdd_reg);
> > +	if (ret) {
> > +		dev_err(priv->dev, "%s(), failed to enable regulator!\n",
> > +			__func__);
> > +		return ret;
> > +	}
> 
> Perhaps make this a DAPM widget?
> 

"vaud18" needs to be always on so we enable it when codec probe.

> > +	priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18");
> > +	if (IS_ERR(priv->avdd_reg)) {
> > +		dev_err(&pdev->dev, "%s(), have no vaud18 supply", __func__);
> > +		return PTR_ERR(priv->avdd_reg);
> > +	}
> 
> It's better to print error codes to help people debugging problems.
> 

Yes, I will print the error codes.

> > +static const struct of_device_id mt6359_of_match[] = {
> > +	{.compatible = "mediatek,mt6359-sound",},
> > +	{}
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6359_of_match);
> 
> We don't need a compatible here, we know that this device is here since
> it's part of the parent device and isn't something that might appear in
> another device.  This is reflecting the Linux driver model, not the
> hardware.

Removed them.
_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

WARNING: multiple messages have this Message-ID (diff)
From: Jiaxin Yu <jiaxin.yu@mediatek.com>
To: Mark Brown <broonie@kernel.org>
Cc: alsa-devel@alsa-project.org, shane.chien@mediatek.com,
	howie.huang@mediatek.com, tiwai@suse.com,
	linux-kernel@vger.kernel.org, tzungbi@google.com,
	robh+dt@kernel.org, linux-mediatek@lists.infradead.org,
	eason.yen@mediatek.com, matthias.bgg@gmail.com,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v2 1/2] ASoC: mediatek: mt6359: add codec driver
Date: Wed, 12 Aug 2020 15:29:13 +0800	[thread overview]
Message-ID: <1597217353.23246.45.camel@mhfsdcap03> (raw)
In-Reply-To: <20200810185933.GI6438@sirena.org.uk>

On Mon, 2020-08-10 at 19:59 +0100, Mark Brown wrote:
> On Mon, Aug 10, 2020 at 11:05:53AM +0800, Jiaxin Yu wrote:
> 
> > +void mt6359_set_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_reset_playback_gpio(struct snd_soc_component *cmpnt)
> > +{
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> 
> > +void mt6359_set_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> > +void mt6359_reset_capture_gpio(struct snd_soc_component *cmpnt)
> > +{
> 
> What are these, should they not be managed through gpiolib and/or
> pinctrl?

These are the functions that control the mux of input or output
signal. I refer to the other codec drivers, most of them are manipulate
the regs in their codec drivers also. Maybe it's easier to control?

> > +/* use only when doing mtkaif calibraiton at the boot time */
> > +static int mt6359_set_dcxo(struct mt6359_priv *priv, bool enable)
> > +{
> > +	regmap_update_bits(priv->regmap, MT6359_DCXO_CW12,
> > +			   0x1 << RG_XO_AUDIO_EN_M_SFT,
> > +			   (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
> > +	return 0;
> 
> Either don't have a return value or use the result of
> regmap_update_bits().  There's similar issues with some other functions
> in here.
> 

Yes, I will refine them.

> > +int mt6359_mtkaif_calibration_enable(struct snd_soc_pcm_runtime *rtd)
> > +{
> 
> > +EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_enable);
> 
> Why is this exported?
> 

This function is exported to machine driver to do calibration when
registering. The interface between MT6359 and MTK SoC is a special
interface that named MTKAIF. Therefore, if MT6359 is to be used
normally, it needs to rely on the platform for calibration when
registering.

> > +static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up)
> > +{
> > +	int i = 0, stage = 0;
> > +
> > +	/* Reduce HP aux feedback loop gain step by step */
> > +	for (i = 0; i <= 0xf; i++) {
> > +		stage = up ? i : 0xf - i;
> 
> Please write normal conditional statements, it helps legibility.
> 

/* Increase/Reduce HP aux feedback loop gain step by step */
This is to prevent sudden changes in volume.

> > +static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
> > +			    struct snd_ctl_elem_value *ucontrol)
> > +{
> > +	struct snd_soc_component *component =
> > +			snd_soc_kcontrol_component(kcontrol);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
> > +	struct soc_mixer_control *mc =
> > +			(struct soc_mixer_control *)kcontrol->private_value;
> > +	unsigned int reg;
> > +	int index = ucontrol->value.integer.value[0];
> > +	int ret;
> > +
> > +	ret = snd_soc_put_volsw(kcontrol, ucontrol);
> > +	if (ret < 0)
> > +		return ret;
> 
> So we make the volume change actually take effect...
> 
> > +	switch (mc->reg) {
> > +	case MT6359_ZCD_CON2:
> > +		regmap_read(priv->regmap, MT6359_ZCD_CON2, &reg);
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] =
> > +			(reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
> > +		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
> > +			(reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
> > +		break;
> 
> ..then read the value that was set and store it elsewhere.  What's
> going on here?
> 

Because we can adjust the volume at two points, before and during the
playback or capture. In addition, we will do volume ramp when opening
the driver. If we set the volume before opening the driver, we need get
the value to do volume ramp during opening the driver.

> > +/*HP MUX */
> > +static const char * const hp_in_mux_map[] = {
> > +	"Open",
> > +	"LoudSPK Playback",
> > +	"Audio Playback",
> > +	"Test Mode",
> > +	"HP Impedance",
> > +	"undefined1",
> > +	"undefined2",
> > +	"undefined3",
> > +};
> 
> Why expose undefined (and presumably out of spec) values to userspace?
> 

Removed them.

> > +static int mt_clksq_event(struct snd_soc_dapm_widget *w,
> > +			  struct snd_kcontrol *kcontrol,
> > +			  int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +
> > +	dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		/* audio clk source from internal dcxo */
> > +		regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23,
> > +				   RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
> > +				   0x0);
> 
> This also appeared to be controlled in _set_clkseq() - are we sure that
> things couldn't get confused about the state?
> 

_set_clkseq() will only be run at the time of mtkaif calibraiton, and
the calibration only run once when the codec driver probe. So it won't
get confused about the state. But it really only needs to be set up once
at mt6359_codec_init_reg(). I will remove the unnecesary settings.

> > +	/* HP damp circuit enable */
> > +	/*Enable HPRN/HPLN output 4K to VCM */
> 
> Spaces around the /* */
> 

Sorry, fixed it.

> > +static int mt_hp_event(struct snd_soc_dapm_widget *w,
> > +		       struct snd_kcontrol *kcontrol,
> > +		       int event)
> > +{
> > +	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
> > +	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> > +	unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
> > +	int device = DEVICE_HP;
> > +
> > +	dev_dbg(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n",
> > +		__func__, event, priv->dev_counter[device], mux);
> > +
> > +	switch (event) {
> > +	case SND_SOC_DAPM_PRE_PMU:
> > +		priv->dev_counter[device]++;
> > +		if (priv->dev_counter[device] > 1)
> > +			break;	/* already enabled, do nothing */
> > +		else if (priv->dev_counter[device] <= 0)
> 
> Why are we doing additional refcounting on top of what DAPM is doing?
> This seems like there should be at least one widget representing the
> shared bits of the audio path.
> 

We have "HPL Mux" and "HPR Mux", there will be two paths enabled when
playback throuh HP. But actually they share the same control sequences.
So in order to prevent setting it one more time we do additional
refcouting.


> > +#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
> > +			SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\
> > +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
> > +			SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\
> > +			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
> > +			SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE)
> 
> The driver doesn't appear to configure anything except the sample rate -
> how are all these formats supported?
> 

The interface between MT6359 and MTK SoC is a special interface that
named MTKAIF. Because of its unique hardware settings, it really doesn't
to set format argument. The capability of pcm driver mainly depends on
cpu-dai driver to limit.

> > +	/* hp gain ctl default choose ZCD */
> > +	priv->hp_gain_ctl = HP_GAIN_CTL_ZCD;
> > +	hp_gain_ctl_select(priv, priv->hp_gain_ctl);
> 
> Why not use the hardware default?
> 

We have two ways to control the volume, there is to select ZCD. Because
the other one it not often used, ZCD is used by default. 

> > +	mt6359_codec_init_reg(cmpnt);
> > +
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = 8;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] = 3;
> > +	priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3] = 3;
> 
> Same here.
> 

Removed them.

> > +	ret = regulator_enable(priv->avdd_reg);
> > +	if (ret) {
> > +		dev_err(priv->dev, "%s(), failed to enable regulator!\n",
> > +			__func__);
> > +		return ret;
> > +	}
> 
> Perhaps make this a DAPM widget?
> 

"vaud18" needs to be always on so we enable it when codec probe.

> > +	priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18");
> > +	if (IS_ERR(priv->avdd_reg)) {
> > +		dev_err(&pdev->dev, "%s(), have no vaud18 supply", __func__);
> > +		return PTR_ERR(priv->avdd_reg);
> > +	}
> 
> It's better to print error codes to help people debugging problems.
> 

Yes, I will print the error codes.

> > +static const struct of_device_id mt6359_of_match[] = {
> > +	{.compatible = "mediatek,mt6359-sound",},
> > +	{}
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6359_of_match);
> 
> We don't need a compatible here, we know that this device is here since
> it's part of the parent device and isn't something that might appear in
> another device.  This is reflecting the Linux driver model, not the
> hardware.

Removed them.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2020-08-12  7:30 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-10  3:05 [PATCH v2 0/2] Add mediatek codec mt6359 driver Jiaxin Yu
2020-08-10  3:05 ` Jiaxin Yu
2020-08-10  3:05 ` Jiaxin Yu
2020-08-10  3:05 ` Jiaxin Yu
2020-08-10  3:05 ` [PATCH v2 1/2] ASoC: mediatek: mt6359: add codec driver Jiaxin Yu
2020-08-10  3:05   ` Jiaxin Yu
2020-08-10  3:05   ` Jiaxin Yu
2020-08-10  8:13   ` Tzung-Bi Shih
2020-08-10  8:13     ` Tzung-Bi Shih
2020-08-10  8:13     ` Tzung-Bi Shih
2020-08-10  8:13     ` Tzung-Bi Shih
2020-08-10 18:59   ` Mark Brown
2020-08-10 18:59     ` Mark Brown
2020-08-10 18:59     ` Mark Brown
2020-08-10 18:59     ` Mark Brown
2020-08-12  7:29     ` Jiaxin Yu [this message]
2020-08-12  7:29       ` Jiaxin Yu
2020-08-12  7:29       ` Jiaxin Yu
2020-08-12  7:29       ` Jiaxin Yu
2020-08-12 12:05       ` Mark Brown
2020-08-12 12:05         ` Mark Brown
2020-08-12 12:05         ` Mark Brown
2020-08-12 12:05         ` Mark Brown
2020-08-13 15:40         ` Jiaxin Yu
2020-08-13 15:40           ` Jiaxin Yu
2020-08-13 15:40           ` Jiaxin Yu
2020-08-13 15:40           ` Jiaxin Yu
2020-08-13 15:44           ` Mark Brown
2020-08-13 15:44             ` Mark Brown
2020-08-13 15:44             ` Mark Brown
2020-08-13 15:44             ` Mark Brown
2020-08-14 10:27             ` Jiaxin Yu
2020-08-14 10:27               ` Jiaxin Yu
2020-08-14 10:27               ` Jiaxin Yu
2020-08-14 10:27               ` Jiaxin Yu
2020-08-10  3:05 ` [PATCH v2 2/2] dt-bindings: mediatek: mt6359: add codec document Jiaxin Yu
2020-08-10  3:05   ` Jiaxin Yu
2020-08-10  3:05   ` Jiaxin Yu
2020-08-10  3:05   ` Jiaxin Yu

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=1597217353.23246.45.camel@mhfsdcap03 \
    --to=jiaxin.yu@mediatek.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    --cc=eason.yen@mediatek.com \
    --cc=howie.huang@mediatek.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=robh+dt@kernel.org \
    --cc=shane.chien@mediatek.com \
    --cc=tiwai@suse.com \
    --cc=tzungbi@google.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.