ASoC: Intel: bxt-da7219-max98357a: support MAX98390 speaker amp
diff mbox series

Message ID 1593498722-7074-1-git-send-email-brent.lu@intel.com
State New
Headers show
Series
  • ASoC: Intel: bxt-da7219-max98357a: support MAX98390 speaker amp
Related show

Commit Message

Lu, Brent June 30, 2020, 6:32 a.m. UTC
Support MAX98390 speaker amplifier on cometlake platform. Driver now
detects amplifier type in the probe function and installs corresponding
controls and DAPM widgets/routes in the late_probe function.

Signed-off-by: Brent Lu <brent.lu@intel.com>
---
 sound/soc/intel/boards/Kconfig                    |  20 ++++
 sound/soc/intel/boards/bxt_da7219_max98357a.c     | 129 ++++++++++++++++++++--
 sound/soc/intel/common/soc-acpi-intel-cml-match.c |   4 +-
 3 files changed, 139 insertions(+), 14 deletions(-)

Comments

Lu, Brent June 30, 2020, 6:46 a.m. UTC | #1
> 
> Support MAX98390 speaker amplifier on cometlake platform. Driver now
> detects amplifier type in the probe function and installs corresponding
> controls and DAPM widgets/routes in the late_probe function.
> 
> Signed-off-by: Brent Lu <brent.lu@intel.com>

This patch is from Chrome-v4.19 branch to support the combination of DA7219
and MAX98390 on a CML Chromebook. It reuses the topology file
sof-cml-da7219-max98357a.tplg


> ---
>  sound/soc/intel/boards/Kconfig                    |  20 ++++
>  sound/soc/intel/boards/bxt_da7219_max98357a.c     | 129
> ++++++++++++++++++++--
>  sound/soc/intel/common/soc-acpi-intel-cml-match.c |   4 +-
>  3 files changed, 139 insertions(+), 14 deletions(-)
> 
> diff --git a/sound/soc/intel/boards/Kconfig
> b/sound/soc/intel/boards/Kconfig index 3d820e1..b3b863e 100644
> --- a/sound/soc/intel/boards/Kconfig
> +++ b/sound/soc/intel/boards/Kconfig
> @@ -291,9 +291,17 @@ config
> SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
>  	select SND_SOC_DMIC
>  	select SND_SOC_HDAC_HDMI
> 
> +config SND_SOC_INTEL_DA7219_MAX98390_GENERIC
> +	tristate
> +	select SND_SOC_DA7219
> +	select SND_SOC_MAX98390
> +	select SND_SOC_DMIC
> +	select SND_SOC_HDAC_HDMI
> +
>  config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
>  	tristate
>  	select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
> +	select SND_SOC_INTEL_DA7219_MAX98390_GENERIC
> 
>  if SND_SOC_INTEL_APL
> 
> @@ -309,6 +317,18 @@ config
> SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
>  	   Say Y or m if you have such a device. This is a recommended option.
>  	   If unsure select "N".
> 
> +config SND_SOC_INTEL_BXT_DA7219_MAX98390_MACH
> +	tristate "Broxton with DA7219 and MAX98390 in I2S Mode"
> +	depends on I2C && ACPI && GPIOLIB
> +	depends on MFD_INTEL_LPSS || COMPILE_TEST
> +	depends on SND_HDA_CODEC_HDMI
> +	select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
> +	help
> +	   This adds support for ASoC machine driver for Broxton-P platforms
> +	   with DA7219 + MAX98390 I2S audio codec.
> +	   Say Y or m if you have such a device. This is a recommended option.
> +	   If unsure select "N".
> +
>  config SND_SOC_INTEL_BXT_RT298_MACH
>  	tristate "Broxton with RT298 I2S mode"
>  	depends on I2C && ACPI && GPIOLIB
> diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c
> b/sound/soc/intel/boards/bxt_da7219_max98357a.c
> index 44016c1..12f07e1 100644
> --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
> +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
> @@ -25,9 +25,14 @@
> 
>  #define BXT_DIALOG_CODEC_DAI	"da7219-hifi"
>  #define BXT_MAXIM_CODEC_DAI	"HiFi"
> +#define MAX98390_DEV0_NAME	"i2c-MX98390:00"
> +#define MAX98390_DEV1_NAME	"i2c-MX98390:01"
>  #define DUAL_CHANNEL		2
>  #define QUAD_CHANNEL		4
> 
> +#define SPKAMP_MAX98357A	1
> +#define SPKAMP_MAX98390	2
> +
>  static struct snd_soc_jack broxton_headset;  static struct snd_soc_jack
> broxton_hdmi[3];
> 
> @@ -40,6 +45,7 @@ struct bxt_hdmi_pcm {
>  struct bxt_card_private {
>  	struct list_head hdmi_pcm_list;
>  	bool common_hdmi_codec_drv;
> +	int spkamp;
>  };
> 
>  enum {
> @@ -85,13 +91,20 @@ static int platform_clock_control(struct
> snd_soc_dapm_widget *w,  static const struct snd_kcontrol_new
> broxton_controls[] = {
>  	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
>  	SOC_DAPM_PIN_SWITCH("Headset Mic"),
> +};
> +
> +static const struct snd_kcontrol_new max98357a_controls[] = {
>  	SOC_DAPM_PIN_SWITCH("Spk"),
>  };
> 
> +static const struct snd_kcontrol_new max98390_controls[] = {
> +	SOC_DAPM_PIN_SWITCH("Left Spk"),
> +	SOC_DAPM_PIN_SWITCH("Right Spk"),
> +};
> +
>  static const struct snd_soc_dapm_widget broxton_widgets[] = {
>  	SND_SOC_DAPM_HP("Headphone Jack", NULL),
>  	SND_SOC_DAPM_MIC("Headset Mic", NULL),
> -	SND_SOC_DAPM_SPK("Spk", NULL),
>  	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
>  	SND_SOC_DAPM_SPK("HDMI1", NULL),
>  	SND_SOC_DAPM_SPK("HDMI2", NULL),
> @@ -100,14 +113,20 @@ static const struct snd_soc_dapm_widget
> broxton_widgets[] = {
>  			platform_clock_control,
> 	SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU),
>  };
> 
> +static const struct snd_soc_dapm_widget max98357a_widgets[] = {
> +	SND_SOC_DAPM_SPK("Spk", NULL),
> +};
> +
> +static const struct snd_soc_dapm_widget max98390_widgets[] = {
> +	SND_SOC_DAPM_SPK("Left Spk", NULL),
> +	SND_SOC_DAPM_SPK("Right Spk", NULL),
> +};
> +
>  static const struct snd_soc_dapm_route audio_map[] = {
>  	/* HP jack connectors - unknown if we have jack detection */
>  	{"Headphone Jack", NULL, "HPL"},
>  	{"Headphone Jack", NULL, "HPR"},
> 
> -	/* speaker */
> -	{"Spk", NULL, "Speaker"},
> -
>  	/* other jacks */
>  	{"MIC", NULL, "Headset Mic"},
> 
> @@ -134,6 +153,17 @@ static const struct snd_soc_dapm_route audio_map[]
> = {
>  	{ "Headset Mic", NULL, "Platform Clock" },  };
> 
> +static const struct snd_soc_dapm_route max98357a_routes[] = {
> +	/* speaker */
> +	{"Spk", NULL, "Speaker"},
> +};
> +
> +static const struct snd_soc_dapm_route max98390_routes[] = {
> +	/* Speaker */
> +	{"Left Spk", NULL, "Left BE_OUT"},
> +	{"Right Spk", NULL, "Right BE_OUT"},
> +};
> +
>  static const struct snd_soc_dapm_route broxton_map[] = {
>  	{"HiFi Playback", NULL, "ssp5 Tx"},
>  	{"ssp5 Tx", NULL, "codec0_out"},
> @@ -404,6 +434,10 @@ SND_SOC_DAILINK_DEF(ssp5_pin,
> SND_SOC_DAILINK_DEF(ssp5_codec,
>  	DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00",
>  				      BXT_MAXIM_CODEC_DAI)));
> +SND_SOC_DAILINK_DEF(max98390_codec,
> +	DAILINK_COMP_ARRAY(
> +	/* Left */	COMP_CODEC(MAX98390_DEV0_NAME, "max98390-
> aif1"),
> +	/* Right */	COMP_CODEC(MAX98390_DEV1_NAME, "max98390-
> aif1")));
> 
>  SND_SOC_DAILINK_DEF(ssp1_pin,
>  	DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); @@ -601,15
> +635,69 @@ static struct snd_soc_dai_link broxton_dais[] = {
>  	},
>  };
> 
> +static struct snd_soc_codec_conf max98390_codec_confs[] = {
> +	{
> +		.dlc = COMP_CODEC_CONF(MAX98390_DEV0_NAME),
> +		.name_prefix = "Left",
> +	},
> +	{
> +		.dlc = COMP_CODEC_CONF(MAX98390_DEV1_NAME),
> +		.name_prefix = "Right",
> +	},
> +};
> +
>  #define NAME_SIZE	32
>  static int bxt_card_late_probe(struct snd_soc_card *card)  {
>  	struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card);
>  	struct bxt_hdmi_pcm *pcm;
>  	struct snd_soc_component *component = NULL;
> -	int err, i = 0;
> +	const struct snd_kcontrol_new *controls;
> +	const struct snd_soc_dapm_widget *widgets;
> +	const struct snd_soc_dapm_route *routes;
> +	int num_controls, num_widgets, num_routes, ret, i = 0;
>  	char jack_name[NAME_SIZE];
> 
> +	switch (ctx->spkamp) {
> +	case SPKAMP_MAX98357A:
> +		controls = max98357a_controls;
> +		num_controls = ARRAY_SIZE(max98357a_controls);
> +		widgets = max98357a_widgets;
> +		num_widgets = ARRAY_SIZE(max98357a_widgets);
> +		routes = max98357a_routes;
> +		num_routes = ARRAY_SIZE(max98357a_routes);
> +		break;
> +	case SPKAMP_MAX98390:
> +		controls = max98390_controls;
> +		num_controls = ARRAY_SIZE(max98390_controls);
> +		widgets = max98390_widgets;
> +		num_widgets = ARRAY_SIZE(max98390_widgets);
> +		routes = max98390_routes;
> +		num_routes = ARRAY_SIZE(max98390_routes);
> +		break;
> +	default:
> +		dev_err(card->dev, "Invalid speaker amplifier %d\n", ctx-
> >spkamp);
> +		break;
> +	}
> +
> +	ret = snd_soc_dapm_new_controls(&card->dapm, widgets,
> num_widgets);
> +	if (ret) {
> +		dev_err(card->dev, "Fail to new widgets\n");
> +		return ret;
> +	}
> +
> +	ret = snd_soc_add_card_controls(card, controls, num_controls);
> +	if (ret) {
> +		dev_err(card->dev, "Fail to add controls\n");
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dapm_add_routes(&card->dapm, routes,
> num_routes);
> +	if (ret) {
> +		dev_err(card->dev, "Fail to add routes\n");
> +		return ret;
> +	}
> +
>  	if (soc_intel_is_glk())
>  		snd_soc_dapm_add_routes(&card->dapm, gemini_map,
>  					ARRAY_SIZE(gemini_map));
> @@ -631,17 +719,17 @@ static int bxt_card_late_probe(struct snd_soc_card
> *card)
>  		component = pcm->codec_dai->component;
>  		snprintf(jack_name, sizeof(jack_name),
>  			"HDMI/DP, pcm=%d Jack", pcm->device);
> -		err = snd_soc_card_jack_new(card, jack_name,
> +		ret = snd_soc_card_jack_new(card, jack_name,
>  					SND_JACK_AVOUT,
> &broxton_hdmi[i],
>  					NULL, 0);
> 
> -		if (err)
> -			return err;
> +		if (ret)
> +			return ret;
> 
> -		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
> +		ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
>  						&broxton_hdmi[i]);
> -		if (err < 0)
> -			return err;
> +		if (ret < 0)
> +			return ret;
> 
>  		i++;
>  	}
> @@ -678,6 +766,11 @@ static int broxton_audio_probe(struct
> platform_device *pdev)
> 
>  	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
> 
> +	if (acpi_dev_present("MX98390", NULL, -1))
> +		ctx->spkamp = SPKAMP_MAX98390;
> +	else
> +		ctx->spkamp = SPKAMP_MAX98357A;
> +
>  	broxton_audio_card.dev = &pdev->dev;
>  	snd_soc_card_set_drvdata(&broxton_audio_card, ctx);
>  	if (soc_intel_is_glk()) {
> @@ -702,7 +795,13 @@ static int broxton_audio_probe(struct
> platform_device *pdev)
>  	} else if (soc_intel_is_cml()) {
>  		unsigned int i;
> 
> -		broxton_audio_card.name = "cmlda7219max";
> +		if (ctx->spkamp == SPKAMP_MAX98390) {
> +			broxton_audio_card.name =
> "cml_max98390_da7219";
> +
> +			broxton_audio_card.codec_conf =
> max98390_codec_confs;
> +			broxton_audio_card.num_configs =
> ARRAY_SIZE(max98390_codec_confs);
> +		} else
> +			broxton_audio_card.name = "cmlda7219max";
> 
>  		for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) {
>  			/* MAXIM_CODEC is connected to SSP1. */ @@ -
> 710,6 +809,11 @@ static int broxton_audio_probe(struct platform_device
> *pdev)
>  					BXT_MAXIM_CODEC_DAI)) {
>  				broxton_dais[i].name = "SSP1-Codec";
>  				broxton_dais[i].cpus->dai_name = "SSP1 Pin";
> +
> +				if (ctx->spkamp == SPKAMP_MAX98390) {
> +					broxton_dais[i].codecs =
> max98390_codec;
> +					broxton_dais[i].num_codecs =
> ARRAY_SIZE(max98390_codec);
> +				}
>  			}
>  			/* DIALOG_CODEC is connected to SSP0 */
>  			else if (!strcmp(broxton_dais[i].codecs->dai_name,
> @@ -759,6 +863,7 @@ MODULE_AUTHOR("Harsha Priya
> <harshapriya.n@intel.com>");  MODULE_AUTHOR("Conrad Cooke
> <conrad.cooke@intel.com>");  MODULE_AUTHOR("Naveen Manohar
> <naveen.m@intel.com>");  MODULE_AUTHOR("Mac Chiang
> <mac.chiang@intel.com>");
> +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
>  MODULE_LICENSE("GPL v2");
>  MODULE_ALIAS("platform:bxt_da7219_max98357a");
>  MODULE_ALIAS("platform:glk_da7219_max98357a");
> diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
> b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
> index cdea0c0..7dc9ba9 100644
> --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
> +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
> @@ -15,8 +15,8 @@ static struct snd_soc_acpi_codecs rt1011_spk_codecs =
> {  };
> 
>  static struct snd_soc_acpi_codecs max98357a_spk_codecs = {
> -	.num_codecs = 1,
> -	.codecs = {"MX98357A"}
> +	.num_codecs = 2,
> +	.codecs = {"MX98357A", "MX98390"}
>  };
> 
>  /*
> --
> 2.7.4
Pierre-Louis Bossart June 30, 2020, 4:26 p.m. UTC | #2
>> diff --git a/sound/soc/intel/boards/Kconfig
>> b/sound/soc/intel/boards/Kconfig index 3d820e1..b3b863e 100644
>> --- a/sound/soc/intel/boards/Kconfig
>> +++ b/sound/soc/intel/boards/Kconfig
>> @@ -291,9 +291,17 @@ config
>> SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
>>   	select SND_SOC_DMIC
>>   	select SND_SOC_HDAC_HDMI
>>
>> +config SND_SOC_INTEL_DA7219_MAX98390_GENERIC
>> +	tristate
>> +	select SND_SOC_DA7219
>> +	select SND_SOC_MAX98390
>> +	select SND_SOC_DMIC
>> +	select SND_SOC_HDAC_HDMI
>> +
>>   config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
>>   	tristate
>>   	select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
>> +	select SND_SOC_INTEL_DA7219_MAX98390_GENERIC

this doesn't look too good, the only difference is the addition of 
MAX98090 which should be added in SND_SOC_INTEL_DA7219_MAX98357A_GENERIC 
above.

>>
>>   if SND_SOC_INTEL_APL
>>
>> @@ -309,6 +317,18 @@ config
>> SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
>>   	   Say Y or m if you have such a device. This is a recommended option.
>>   	   If unsure select "N".
>>
>> +config SND_SOC_INTEL_BXT_DA7219_MAX98390_MACH
>> +	tristate "Broxton with DA7219 and MAX98390 in I2S Mode"
>> +	depends on I2C && ACPI && GPIOLIB
>> +	depends on MFD_INTEL_LPSS || COMPILE_TEST
>> +	depends on SND_HDA_CODEC_HDMI
>> +	select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
>> +	help
>> +	   This adds support for ASoC machine driver for Broxton-P platforms
>> +	   with DA7219 + MAX98390 I2S audio codec.
>> +	   Say Y or m if you have such a device. This is a recommended option.
>> +	   If unsure select "N".
>> +

i don't think you need a different top-level config, just extend the 
existing one to say MAX98357A or MAX98390.

[...]

>>   	if (soc_intel_is_glk())
>>   		snd_soc_dapm_add_routes(&card->dapm, gemini_map,
>>   					ARRAY_SIZE(gemini_map));
>> @@ -631,17 +719,17 @@ static int bxt_card_late_probe(struct snd_soc_card
>> *card)
>>   		component = pcm->codec_dai->component;
>>   		snprintf(jack_name, sizeof(jack_name),
>>   			"HDMI/DP, pcm=%d Jack", pcm->device);
>> -		err = snd_soc_card_jack_new(card, jack_name,
>> +		ret = snd_soc_card_jack_new(card, jack_name,
>>   					SND_JACK_AVOUT,
>> &broxton_hdmi[i],
>>   					NULL, 0);
>>
>> -		if (err)
>> -			return err;
>> +		if (ret)
>> +			return ret;
>>
>> -		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
>> +		ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
>>   						&broxton_hdmi[i]);
>> -		if (err < 0)
>> -			return err;
>> +		if (ret < 0)
>> +			return ret;

these look like unrelated changes?


>> --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
>> +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
>> @@ -15,8 +15,8 @@ static struct snd_soc_acpi_codecs rt1011_spk_codecs =
>> {  };
>>
>>   static struct snd_soc_acpi_codecs max98357a_spk_codecs = {
>> -	.num_codecs = 1,
>> -	.codecs = {"MX98357A"}
>> +	.num_codecs = 2,
>> +	.codecs = {"MX98357A", "MX98390"}

That looks just wrong?

It would be really odd to list two devices as prerequisites for loading 
a driver, when in practice they are mutually exclusive? Something's 
broken in coreboot if both are present.

see below what we used for JSL:

see static struct snd_soc_acpi_codecs jsl_7219_98373_codecs = {
	.num_codecs = 1,
	.codecs = {"MX98373"}
};

static struct snd_soc_acpi_codecs mx98360a_spk = {
	.num_codecs = 1,
	.codecs = {"MX98360A"}
};
Lu, Brent July 1, 2020, 9:36 a.m. UTC | #3
> 
> this doesn't look too good, the only difference is the addition of
> MAX98090 which should be added in
> SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
> above.

Will do

> 
> i don't think you need a different top-level config, just extend the existing
> one to say MAX98357A or MAX98390.
> 
> [...]
> 

OK. I'll modify the description for MAX98390

> 
> these look like unrelated changes?
> 
> 

Will revert those changes.

> 
> That looks just wrong?
> 
> It would be really odd to list two devices as prerequisites for loading a driver,
> when in practice they are mutually exclusive? Something's broken in
> coreboot if both are present.
> 
> see below what we used for JSL:
> 
> see static struct snd_soc_acpi_codecs jsl_7219_98373_codecs = {
> 	.num_codecs = 1,
> 	.codecs = {"MX98373"}
> };
> 
> static struct snd_soc_acpi_codecs mx98360a_spk = {
> 	.num_codecs = 1,
> 	.codecs = {"MX98360A"}
> };

Err... I misread the snd_soc_acpi_codec_list function and made this error. Will
fix it in the V2 patch. I will also fix the Chrome v4.19 branch. Thank you for the
review.



Regards,
Brent

Patch
diff mbox series

diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 3d820e1..b3b863e 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -291,9 +291,17 @@  config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
 	select SND_SOC_DMIC
 	select SND_SOC_HDAC_HDMI
 
+config SND_SOC_INTEL_DA7219_MAX98390_GENERIC
+	tristate
+	select SND_SOC_DA7219
+	select SND_SOC_MAX98390
+	select SND_SOC_DMIC
+	select SND_SOC_HDAC_HDMI
+
 config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
 	tristate
 	select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
+	select SND_SOC_INTEL_DA7219_MAX98390_GENERIC
 
 if SND_SOC_INTEL_APL
 
@@ -309,6 +317,18 @@  config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
 	   Say Y or m if you have such a device. This is a recommended option.
 	   If unsure select "N".
 
+config SND_SOC_INTEL_BXT_DA7219_MAX98390_MACH
+	tristate "Broxton with DA7219 and MAX98390 in I2S Mode"
+	depends on I2C && ACPI && GPIOLIB
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	depends on SND_HDA_CODEC_HDMI
+	select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
+	help
+	   This adds support for ASoC machine driver for Broxton-P platforms
+	   with DA7219 + MAX98390 I2S audio codec.
+	   Say Y or m if you have such a device. This is a recommended option.
+	   If unsure select "N".
+
 config SND_SOC_INTEL_BXT_RT298_MACH
 	tristate "Broxton with RT298 I2S mode"
 	depends on I2C && ACPI && GPIOLIB
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index 44016c1..12f07e1 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -25,9 +25,14 @@ 
 
 #define BXT_DIALOG_CODEC_DAI	"da7219-hifi"
 #define BXT_MAXIM_CODEC_DAI	"HiFi"
+#define MAX98390_DEV0_NAME	"i2c-MX98390:00"
+#define MAX98390_DEV1_NAME	"i2c-MX98390:01"
 #define DUAL_CHANNEL		2
 #define QUAD_CHANNEL		4
 
+#define SPKAMP_MAX98357A	1
+#define SPKAMP_MAX98390	2
+
 static struct snd_soc_jack broxton_headset;
 static struct snd_soc_jack broxton_hdmi[3];
 
@@ -40,6 +45,7 @@  struct bxt_hdmi_pcm {
 struct bxt_card_private {
 	struct list_head hdmi_pcm_list;
 	bool common_hdmi_codec_drv;
+	int spkamp;
 };
 
 enum {
@@ -85,13 +91,20 @@  static int platform_clock_control(struct snd_soc_dapm_widget *w,
 static const struct snd_kcontrol_new broxton_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_kcontrol_new max98357a_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Spk"),
 };
 
+static const struct snd_kcontrol_new max98390_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Left Spk"),
+	SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
 static const struct snd_soc_dapm_widget broxton_widgets[] = {
 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-	SND_SOC_DAPM_SPK("Spk", NULL),
 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
 	SND_SOC_DAPM_SPK("HDMI1", NULL),
 	SND_SOC_DAPM_SPK("HDMI2", NULL),
@@ -100,14 +113,20 @@  static const struct snd_soc_dapm_widget broxton_widgets[] = {
 			platform_clock_control,	SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU),
 };
 
+static const struct snd_soc_dapm_widget max98357a_widgets[] = {
+	SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
+static const struct snd_soc_dapm_widget max98390_widgets[] = {
+	SND_SOC_DAPM_SPK("Left Spk", NULL),
+	SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
 static const struct snd_soc_dapm_route audio_map[] = {
 	/* HP jack connectors - unknown if we have jack detection */
 	{"Headphone Jack", NULL, "HPL"},
 	{"Headphone Jack", NULL, "HPR"},
 
-	/* speaker */
-	{"Spk", NULL, "Speaker"},
-
 	/* other jacks */
 	{"MIC", NULL, "Headset Mic"},
 
@@ -134,6 +153,17 @@  static const struct snd_soc_dapm_route audio_map[] = {
 	{ "Headset Mic", NULL, "Platform Clock" },
 };
 
+static const struct snd_soc_dapm_route max98357a_routes[] = {
+	/* speaker */
+	{"Spk", NULL, "Speaker"},
+};
+
+static const struct snd_soc_dapm_route max98390_routes[] = {
+	/* Speaker */
+	{"Left Spk", NULL, "Left BE_OUT"},
+	{"Right Spk", NULL, "Right BE_OUT"},
+};
+
 static const struct snd_soc_dapm_route broxton_map[] = {
 	{"HiFi Playback", NULL, "ssp5 Tx"},
 	{"ssp5 Tx", NULL, "codec0_out"},
@@ -404,6 +434,10 @@  SND_SOC_DAILINK_DEF(ssp5_pin,
 SND_SOC_DAILINK_DEF(ssp5_codec,
 	DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00",
 				      BXT_MAXIM_CODEC_DAI)));
+SND_SOC_DAILINK_DEF(max98390_codec,
+	DAILINK_COMP_ARRAY(
+	/* Left */	COMP_CODEC(MAX98390_DEV0_NAME, "max98390-aif1"),
+	/* Right */	COMP_CODEC(MAX98390_DEV1_NAME, "max98390-aif1")));
 
 SND_SOC_DAILINK_DEF(ssp1_pin,
 	DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
@@ -601,15 +635,69 @@  static struct snd_soc_dai_link broxton_dais[] = {
 	},
 };
 
+static struct snd_soc_codec_conf max98390_codec_confs[] = {
+	{
+		.dlc = COMP_CODEC_CONF(MAX98390_DEV0_NAME),
+		.name_prefix = "Left",
+	},
+	{
+		.dlc = COMP_CODEC_CONF(MAX98390_DEV1_NAME),
+		.name_prefix = "Right",
+	},
+};
+
 #define NAME_SIZE	32
 static int bxt_card_late_probe(struct snd_soc_card *card)
 {
 	struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card);
 	struct bxt_hdmi_pcm *pcm;
 	struct snd_soc_component *component = NULL;
-	int err, i = 0;
+	const struct snd_kcontrol_new *controls;
+	const struct snd_soc_dapm_widget *widgets;
+	const struct snd_soc_dapm_route *routes;
+	int num_controls, num_widgets, num_routes, ret, i = 0;
 	char jack_name[NAME_SIZE];
 
+	switch (ctx->spkamp) {
+	case SPKAMP_MAX98357A:
+		controls = max98357a_controls;
+		num_controls = ARRAY_SIZE(max98357a_controls);
+		widgets = max98357a_widgets;
+		num_widgets = ARRAY_SIZE(max98357a_widgets);
+		routes = max98357a_routes;
+		num_routes = ARRAY_SIZE(max98357a_routes);
+		break;
+	case SPKAMP_MAX98390:
+		controls = max98390_controls;
+		num_controls = ARRAY_SIZE(max98390_controls);
+		widgets = max98390_widgets;
+		num_widgets = ARRAY_SIZE(max98390_widgets);
+		routes = max98390_routes;
+		num_routes = ARRAY_SIZE(max98390_routes);
+		break;
+	default:
+		dev_err(card->dev, "Invalid speaker amplifier %d\n", ctx->spkamp);
+		break;
+	}
+
+	ret = snd_soc_dapm_new_controls(&card->dapm, widgets, num_widgets);
+	if (ret) {
+		dev_err(card->dev, "Fail to new widgets\n");
+		return ret;
+	}
+
+	ret = snd_soc_add_card_controls(card, controls, num_controls);
+	if (ret) {
+		dev_err(card->dev, "Fail to add controls\n");
+		return ret;
+	}
+
+	ret = snd_soc_dapm_add_routes(&card->dapm, routes, num_routes);
+	if (ret) {
+		dev_err(card->dev, "Fail to add routes\n");
+		return ret;
+	}
+
 	if (soc_intel_is_glk())
 		snd_soc_dapm_add_routes(&card->dapm, gemini_map,
 					ARRAY_SIZE(gemini_map));
@@ -631,17 +719,17 @@  static int bxt_card_late_probe(struct snd_soc_card *card)
 		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
-		err = snd_soc_card_jack_new(card, jack_name,
+		ret = snd_soc_card_jack_new(card, jack_name,
 					SND_JACK_AVOUT, &broxton_hdmi[i],
 					NULL, 0);
 
-		if (err)
-			return err;
+		if (ret)
+			return ret;
 
-		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+		ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
 						&broxton_hdmi[i]);
-		if (err < 0)
-			return err;
+		if (ret < 0)
+			return ret;
 
 		i++;
 	}
@@ -678,6 +766,11 @@  static int broxton_audio_probe(struct platform_device *pdev)
 
 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 
+	if (acpi_dev_present("MX98390", NULL, -1))
+		ctx->spkamp = SPKAMP_MAX98390;
+	else
+		ctx->spkamp = SPKAMP_MAX98357A;
+
 	broxton_audio_card.dev = &pdev->dev;
 	snd_soc_card_set_drvdata(&broxton_audio_card, ctx);
 	if (soc_intel_is_glk()) {
@@ -702,7 +795,13 @@  static int broxton_audio_probe(struct platform_device *pdev)
 	} else if (soc_intel_is_cml()) {
 		unsigned int i;
 
-		broxton_audio_card.name = "cmlda7219max";
+		if (ctx->spkamp == SPKAMP_MAX98390) {
+			broxton_audio_card.name = "cml_max98390_da7219";
+
+			broxton_audio_card.codec_conf = max98390_codec_confs;
+			broxton_audio_card.num_configs = ARRAY_SIZE(max98390_codec_confs);
+		} else
+			broxton_audio_card.name = "cmlda7219max";
 
 		for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) {
 			/* MAXIM_CODEC is connected to SSP1. */
@@ -710,6 +809,11 @@  static int broxton_audio_probe(struct platform_device *pdev)
 					BXT_MAXIM_CODEC_DAI)) {
 				broxton_dais[i].name = "SSP1-Codec";
 				broxton_dais[i].cpus->dai_name = "SSP1 Pin";
+
+				if (ctx->spkamp == SPKAMP_MAX98390) {
+					broxton_dais[i].codecs = max98390_codec;
+					broxton_dais[i].num_codecs = ARRAY_SIZE(max98390_codec);
+				}
 			}
 			/* DIALOG_CODEC is connected to SSP0 */
 			else if (!strcmp(broxton_dais[i].codecs->dai_name,
@@ -759,6 +863,7 @@  MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
 MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
 MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
 MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:bxt_da7219_max98357a");
 MODULE_ALIAS("platform:glk_da7219_max98357a");
diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
index cdea0c0..7dc9ba9 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
@@ -15,8 +15,8 @@  static struct snd_soc_acpi_codecs rt1011_spk_codecs = {
 };
 
 static struct snd_soc_acpi_codecs max98357a_spk_codecs = {
-	.num_codecs = 1,
-	.codecs = {"MX98357A"}
+	.num_codecs = 2,
+	.codecs = {"MX98357A", "MX98390"}
 };
 
 /*