diff mbox

[v2] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_rt5672

Message ID c716a6624d4227908ee879cbbc9de6d9bca1a0c0.1414495605.git.mengdong.lin@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lin, Mengdong Oct. 28, 2014, 11:30 a.m. UTC
From: Mengdong Lin <mengdong.lin@intel.com>

Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and
Braswell, with RT5672 codec.

Signed-off-by: Mengdong Lin <mengdong.lin@intel.com>

Comments

Mark Brown Oct. 28, 2014, 4:48 p.m. UTC | #1
On Tue, Oct 28, 2014 at 07:30:32PM +0800, mengdong.lin@intel.com wrote:

> +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
> +        tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
> +        depends on X86_INTEL_LPSS
> +        select SND_SOC_RT5670
> +        select SND_SST_MFLD_PLATFORM
> +        select SND_SOC_INTEL_SST
> +        select SND_SST_IPC
> +        select SND_SST_MACHINE
> +        default n

n is the default anyway.

> +obj-$(CONFIG_SND_SST_MACHINE) += board/

It's a bit weird to have the Kconfig in the root Intel directory if the
boards are getting moved into a subdirectory - why not just source a
Kconfig in the board directory?

> +static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
> +					struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> +	int ret;
> +
> +	if (strncmp(codec_dai->name, "rt5670-aif1", 11))
> +		return 0;

11 is a magic number!  Why not use strlen() here (and why do we do
nothing in the AIF1 hw_params() if we're working with AIF1)?

> +	ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
> +				  CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
> +	if (ret < 0) {
> +		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
> +				     params_rate(params) * 512,
> +				     SND_SOC_CLOCK_IN);
> +	if (ret < 0) {
> +		dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
> +		return ret;
> +	}

Nothing ever stops the PLL - a set_bias_level() callback with a handler
for _OFF.  Otherwise we're wasting power.

> +	snd_soc_card_cht.dev = &pdev->dev;
> +	ret_val = snd_soc_register_card(&snd_soc_card_cht);
> +	if (ret_val) {

devm_snd_soc_register_card() and the removal function can go entirely.
Lin, Mengdong Oct. 29, 2014, 6:45 a.m. UTC | #2
> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Wednesday, October 29, 2014 12:48 AM

> > +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
> > +        tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with
> RT5672 codec"
> > +        depends on X86_INTEL_LPSS
> > +        select SND_SOC_RT5670
> > +        select SND_SST_MFLD_PLATFORM
> > +        select SND_SOC_INTEL_SST
> > +        select SND_SST_IPC
> > +        select SND_SST_MACHINE
> > +        default n
> 
> n is the default anyway.

Will remove " default n"

> > +obj-$(CONFIG_SND_SST_MACHINE) += board/
> 
> It's a bit weird to have the Kconfig in the root Intel directory if the boards are
> getting moved into a subdirectory - why not just source a Kconfig in the board
> directory?

Will source a Kconfig in the board directory.

> > +static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
> > +					struct snd_pcm_hw_params *params) {
> > +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> > +	int ret;
> > +
> > +	if (strncmp(codec_dai->name, "rt5670-aif1", 11))
> > +		return 0;
> 
> 11 is a magic number!  Why not use strlen() here (and why do we do nothing
> in the AIF1 hw_params() if we're working with AIF1)?

It not necessary. Will remove.
> 
> > +	ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
> > +				  CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
> > +	if (ret < 0) {
> > +		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
> > +				     params_rate(params) * 512,
> > +				     SND_SOC_CLOCK_IN);
> > +	if (ret < 0) {
> > +		dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
> > +		return ret;
> > +	}
> 
> Nothing ever stops the PLL - a set_bias_level() callback with a handler for _OFF.
> Otherwise we're wasting power.

Can we introduce a power supply widget for the platform clock used as MCLK?
That widget can be added into the playback and capture path. 
So when idle, the platform clock can be turn off and let the codec PLL selects
its internal low frequency clock only for jack detection. It's verified internally.

The platform clock driver is not upstream yet, so in the widget control we can't
really turn off the MCLK output to codec, but at least we can let the codec PLL
no longer locked to the high frequency MCLK. 

Or we don't change the code at moment, until we upstream the platform clock
driver at first?

Which way is better?

> 
> > +	snd_soc_card_cht.dev = &pdev->dev;
> > +	ret_val = snd_soc_register_card(&snd_soc_card_cht);
> > +	if (ret_val) {
> 
> devm_snd_soc_register_card() and the removal function can go entirely.

Okay.

Thanks
Mengdong
Mark Brown Oct. 29, 2014, 10:30 a.m. UTC | #3
On Wed, Oct 29, 2014 at 06:45:05AM +0000, Lin, Mengdong wrote:

> > Nothing ever stops the PLL - a set_bias_level() callback with a handler for _OFF.
> > Otherwise we're wasting power.

> Can we introduce a power supply widget for the platform clock used as MCLK?
> That widget can be added into the playback and capture path. 
> So when idle, the platform clock can be turn off and let the codec PLL selects
> its internal low frequency clock only for jack detection. It's verified internally.

That should be fine also, it's just usually a bit more work to add all
the routes for DAPM.

> Or we don't change the code at moment, until we upstream the platform clock
> driver at first?

> Which way is better?

Well, currently the code to load the driver is also not upstream so may
as well have the driver be what's wanted!  But it's not a massive deal,
main thing would be to get everything done as part of initial
upstreaming instead of having to come back and work on it again later.
Lin, Mengdong Oct. 31, 2014, 12:48 p.m. UTC | #4
+ Liam.

> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Wednesday, October 29, 2014 6:31 PM

> > > Nothing ever stops the PLL - a set_bias_level() callback with a handler for
> _OFF.
> > > Otherwise we're wasting power.
> 
> > Can we introduce a power supply widget for the platform clock used as
> MCLK?
> > That widget can be added into the playback and capture path.
> > So when idle, the platform clock can be turn off and let the codec PLL
> > selects its internal low frequency clock only for jack detection. It's verified
> internally.
> 
> That should be fine also, it's just usually a bit more work to add all the routes
> for DAPM.
> 
> > Or we don't change the code at moment, until we upstream the platform
> > clock driver at first?
> 
> > Which way is better?
> 
> Well, currently the code to load the driver is also not upstream so may as well
> have the driver be what's wanted!  But it's not a massive deal, main thing
> would be to get everything done as part of initial upstreaming instead of
> having to come back and work on it again later.

Now we're working with Realtek to enable runtime PM on RT5672 codec driver.
With help of ACPI, 
- the codec will be in suspended to D3 when idle , switch to its internal clock, 
 and BIOS will turn off the platform clock output (MCLK) to save power.
- And when the codec resumes to D0, BIOS will turn on the clock at first. And 
 hw_params will make the codec use PLL and lock to MCLK again.

Thus the machine driver does not need to explicitly turn on/off the platform 
codec by itself.

Thanks
Mengdong
Mark Brown Oct. 31, 2014, 12:54 p.m. UTC | #5
On Fri, Oct 31, 2014 at 12:48:26PM +0000, Lin, Mengdong wrote:

> Now we're working with Realtek to enable runtime PM on RT5672 codec driver.
> With help of ACPI, 
> - the codec will be in suspended to D3 when idle , switch to its internal clock, 
>  and BIOS will turn off the platform clock output (MCLK) to save power.
> - And when the codec resumes to D0, BIOS will turn on the clock at first. And 
>  hw_params will make the codec use PLL and lock to MCLK again.

> Thus the machine driver does not need to explicitly turn on/off the platform 
> codec by itself.

If the machine driver has asked for the PLL to be on I'd expect the
CODEC driver to be respecting that...
Lin, Mengdong Nov. 3, 2014, 12:11 p.m. UTC | #6
> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Friday, October 31, 2014 8:54 PM
 
> On Fri, Oct 31, 2014 at 12:48:26PM +0000, Lin, Mengdong wrote:
> 
> > Now we're working with Realtek to enable runtime PM on RT5672 codec
> driver.
> > With help of ACPI,
> > - the codec will be in suspended to D3 when idle , switch to its
> > internal clock,  and BIOS will turn off the platform clock output (MCLK) to
> save power.
> > - And when the codec resumes to D0, BIOS will turn on the clock at
> > first. And  hw_params will make the codec use PLL and lock to MCLK again.
> 
> > Thus the machine driver does not need to explicitly turn on/off the
> > platform codec by itself.
> 
> If the machine driver has asked for the PLL to be on I'd expect the CODEC
> driver to be respecting that...

The codec driver rt5670 defines a supply widget to control the power of PLL.
So the PLL will be power on when there is active audio streaming and power
off when Idle. 
The machine driver need not explicitly turn on/off the PLL, but only need to 
select PLL source to MCLK in hw_params and configure the in/out frequency.

And we've verified to enable runtime PM on the codec driver and trigger ACPI
method to dynamically control the MCLK output from SOC to the codec:
- When codec is active (D0), BIOS will turn on MCLK at first
- When codec is suspended on idle (D3), codec will switch to its internal clock,
 and BIOS will turn off MCLK

I'll post V3 machine driver based on your comments on v2.
After an internal sync, this machine driver will be moved to sound/soc/intel
directory, with other existing Intel machines.

Thanks
Mengdong
Lin, Mengdong Nov. 4, 2014, 9:45 a.m. UTC | #7
Hi Mark,

I've posted the v3 patch. Would you please have a review?

There are other Intel machine drivers submitted at the same time, hope they
can be integrated smoothly to avoid conflict on Kconfig and Makefile.

Thanks
Mengdong

> -----Original Message-----
> From: alsa-devel-bounces@alsa-project.org
> [mailto:alsa-devel-bounces@alsa-project.org] On Behalf Of Lin, Mengdong
> Sent: Monday, November 03, 2014 8:11 PM
> To: Mark Brown
> Cc: Koul, Vinod; alsa-devel@alsa-project.org; Prusty, Subhransu S; Girdwood,
> Liam R
> Subject: Re: [alsa-devel] [PATCH v2] ASoC: Intel: Add Cherrytrail & Braswell
> machine driver cht_bsw_rt5672
> 
> > -----Original Message-----
> > From: Mark Brown [mailto:broonie@kernel.org]
> > Sent: Friday, October 31, 2014 8:54 PM
> 
> > On Fri, Oct 31, 2014 at 12:48:26PM +0000, Lin, Mengdong wrote:
> >
> > > Now we're working with Realtek to enable runtime PM on RT5672 codec
> > driver.
> > > With help of ACPI,
> > > - the codec will be in suspended to D3 when idle , switch to its
> > > internal clock,  and BIOS will turn off the platform clock output
> > > (MCLK) to
> > save power.
> > > - And when the codec resumes to D0, BIOS will turn on the clock at
> > > first. And  hw_params will make the codec use PLL and lock to MCLK again.
> >
> > > Thus the machine driver does not need to explicitly turn on/off the
> > > platform codec by itself.
> >
> > If the machine driver has asked for the PLL to be on I'd expect the
> > CODEC driver to be respecting that...
> 
> The codec driver rt5670 defines a supply widget to control the power of PLL.
> So the PLL will be power on when there is active audio streaming and power off
> when Idle.
> The machine driver need not explicitly turn on/off the PLL, but only need to
> select PLL source to MCLK in hw_params and configure the in/out frequency.
> 
> And we've verified to enable runtime PM on the codec driver and trigger ACPI
> method to dynamically control the MCLK output from SOC to the codec:
> - When codec is active (D0), BIOS will turn on MCLK at first
> - When codec is suspended on idle (D3), codec will switch to its internal clock,
> and BIOS will turn off MCLK
> 
> I'll post V3 machine driver based on your comments on v2.
> After an internal sync, this machine driver will be moved to sound/soc/intel
> directory, with other existing Intel machines.
> 
> Thanks
> Mengdong
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Vinod Koul Nov. 4, 2014, 10:23 a.m. UTC | #8
On Tue, Nov 04, 2014 at 03:15:15PM +0530, Lin, Mengdong wrote:
> Hi Mark,
> 
> I've posted the v3 patch. Would you please have a review?
> 
> There are other Intel machine drivers submitted at the same time, hope they
> can be integrated smoothly to avoid conflict on Kconfig and Makefile.

Mengdong, I am about to send v3 series of my driver changes. Should I add
this driver in my series to avoid merge conflict in Kconfig?
Mark Brown Nov. 4, 2014, 11:47 a.m. UTC | #9
On Tue, Nov 04, 2014 at 09:45:15AM +0000, Lin, Mengdong wrote:
> Hi Mark,
> 
> I've posted the v3 patch. Would you please have a review?

You only posted it yesterday.  Please allow reasonable time for review, 
demanding a review within a day is not reasonable and will only annoy
maintainers.
Lin, Mengdong Nov. 5, 2014, 1:37 a.m. UTC | #10
> -----Original Message-----
> From: Koul, Vinod
> Sent: Tuesday, November 04, 2014 6:23 PM
> To: Lin, Mengdong
> Cc: Mark Brown; alsa-devel@alsa-project.org; Prusty, Subhransu S; Girdwood,
> Liam R
> Subject: Re: [PATCH v2] ASoC: Intel: Add Cherrytrail & Braswell machine driver
> cht_bsw_rt5672
> 
> On Tue, Nov 04, 2014 at 03:15:15PM +0530, Lin, Mengdong wrote:
> > Hi Mark,
> >
> > I've posted the v3 patch. Would you please have a review?
> >
> > There are other Intel machine drivers submitted at the same time, hope
> > they can be integrated smoothly to avoid conflict on Kconfig and Makefile.
> 
> Mengdong, I am about to send v3 series of my driver changes. Should I add
> this driver in my series to avoid merge conflict in Kconfig?

Okay, please. It will help to avoid merge conflict.

Thanks
Mengdong
Lin, Mengdong Nov. 5, 2014, 1:44 a.m. UTC | #11
> -----Original Message-----
> From: alsa-devel-bounces@alsa-project.org
> [mailto:alsa-devel-bounces@alsa-project.org] On Behalf Of Mark Brown
> Sent: Tuesday, November 04, 2014 7:47 PM
> To: Lin, Mengdong
> Cc: Koul, Vinod; alsa-devel@alsa-project.org; Prusty, Subhransu S; Girdwood,
> Liam R
> Subject: Re: [alsa-devel] [PATCH v2] ASoC: Intel: Add Cherrytrail & Braswell
> machine driver cht_bsw_rt5672
> 
> On Tue, Nov 04, 2014 at 09:45:15AM +0000, Lin, Mengdong wrote:
> > Hi Mark,
> >
> > I've posted the v3 patch. Would you please have a review?
> 
> You only posted it yesterday.  Please allow reasonable time for review,
> demanding a review within a day is not reasonable and will only annoy
> maintainers.

I'm sorry for this. 
Vinod is posting other Intel machine drivers at the same time now. 
He will add this machine driver in his v3 patch series to avoid conflict in 
Kconfig and Makefile.

Thanks
Mengdong
diff mbox

Patch

diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 2a3af88..7479ce0 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -16,6 +16,9 @@  config SND_SST_MFLD_PLATFORM
 config SND_SST_IPC
 	tristate
 
+config SND_SST_MACHINE
+        tristate
+
 config SND_SOC_INTEL_SST
 	tristate "ASoC support for Intel(R) Smart Sound Technology"
 	select SND_SOC_INTEL_SST_ACPI if ACPI
@@ -76,3 +79,20 @@  config SND_SOC_INTEL_BROADWELL_MACH
 	  Ultrabook platforms.
 	  Say Y if you have such a device
 	  If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
+        tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
+        depends on X86_INTEL_LPSS
+        select SND_SOC_RT5670
+        select SND_SST_MFLD_PLATFORM
+        select SND_SOC_INTEL_SST
+        select SND_SST_IPC
+        select SND_SST_MACHINE
+        default n
+
+        help
+          This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+          platforms with RT5672 audio codec.
+          Say Y if you have such a device
+          If unsure select "N".
+
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 9ab43be..4069d3f 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -31,6 +31,7 @@  obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
+obj-$(CONFIG_SND_SST_MACHINE) += board/
 
 # DSP driver
 obj-$(CONFIG_SND_SST_IPC) += sst/
diff --git a/sound/soc/intel/board/Makefile b/sound/soc/intel/board/Makefile
new file mode 100644
index 0000000..9ecc227
--- /dev/null
+++ b/sound/soc/intel/board/Makefile
@@ -0,0 +1,2 @@ 
+snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
+obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
diff --git a/sound/soc/intel/board/cht_bsw_rt5672.c b/sound/soc/intel/board/cht_bsw_rt5672.c
new file mode 100644
index 0000000..789d1a0
--- /dev/null
+++ b/sound/soc/intel/board/cht_bsw_rt5672.c
@@ -0,0 +1,246 @@ 
+/*
+ *  cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms
+ *                     Cherrytrail and Braswell, with RT5672 codec.
+ *
+ *  Copyright (C) 2014 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *          Mengdong Lin <mengdong.lin@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/rt5670.h"
+#include "../sst-atom-controls.h"
+
+#define CHT_PLAT_CLK_3_HZ	19200000
+
+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route cht_audio_map[] = {
+	{"IN1P", NULL, "Headset Mic"},
+	{"IN1N", NULL, "Headset Mic"},
+	{"DMIC L1", NULL, "Int Mic"},
+	{"DMIC R1", NULL, "Int Mic"},
+	{"Headphone", NULL, "HPOL"},
+	{"Headphone", NULL, "HPOR"},
+	{"Ext Spk", NULL, "SPOLP"},
+	{"Ext Spk", NULL, "SPOLN"},
+	{"Ext Spk", NULL, "SPORP"},
+	{"Ext Spk", NULL, "SPORN"},
+	{"AIF1 Playback", NULL, "ssp2 Tx"},
+	{"ssp2 Tx", NULL, "codec_out0"},
+	{"ssp2 Tx", NULL, "codec_out1"},
+	{"codec_in0", NULL, "ssp2 Rx"},
+	{"codec_in1", NULL, "ssp2 Rx"},
+	{"ssp2 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_kcontrol_new cht_mc_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Mic"),
+	SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	if (strncmp(codec_dai->name, "rt5670-aif1", 11))
+		return 0;
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
+				  CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
+				     params_rate(params) * 512,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	int ret;
+	struct snd_soc_dai *codec_dai = runtime->codec_dai;
+
+	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+	if (ret < 0) {
+		dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+			    struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/* The DSP will covert the FE rate to 48k, stereo, 24bits */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP2 to 24-bit */
+	snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+				    SNDRV_PCM_HW_PARAM_FIRST_MASK],
+				    SNDRV_PCM_FORMAT_S24_LE);
+	return 0;
+}
+
+static unsigned int rates_48000[] = {
+	48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+	.count = ARRAY_SIZE(rates_48000),
+	.list  = rates_48000,
+};
+
+static int cht_aif1_startup(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE,
+			&constraints_48000);
+}
+
+static struct snd_soc_ops cht_aif1_ops = {
+	.startup = cht_aif1_startup,
+};
+
+static struct snd_soc_ops cht_be_ssp2_ops = {
+	.hw_params = cht_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link cht_dailink[] = {
+	/* Front End DAI links */
+	[MERR_DPCM_AUDIO] = {
+		.name = "Audio Port",
+		.stream_name = "Audio",
+		.cpu_dai_name = "media-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.ignore_suspend = 1,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ops = &cht_aif1_ops,
+	},
+	[MERR_DPCM_COMPR] = {
+		.name = "Compressed Port",
+		.stream_name = "Compress",
+		.cpu_dai_name = "compress-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+	},
+
+	/* Back End DAI links */
+	{
+		/* SSP2 - Codec */
+		.name = "SSP2-Codec",
+		.be_id = 1,
+		.cpu_dai_name = "ssp2-port",
+		.platform_name = "sst-mfld-platform",
+		.no_pcm = 1,
+		.codec_dai_name = "rt5670-aif1",
+		.codec_name = "i2c-10EC5670:00",
+		.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
+					| SND_SOC_DAIFMT_CBS_CFS,
+		.init = cht_codec_init,
+		.be_hw_params_fixup = cht_codec_fixup,
+		.ignore_suspend = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ops = &cht_be_ssp2_ops,
+	},
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_cht = {
+	.name = "cherrytrailcraudio",
+	.dai_link = cht_dailink,
+	.num_links = ARRAY_SIZE(cht_dailink),
+	.dapm_widgets = cht_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+	.dapm_routes = cht_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+	.controls = cht_mc_controls,
+	.num_controls = ARRAY_SIZE(cht_mc_controls),
+};
+
+static int snd_cht_mc_probe(struct platform_device *pdev)
+{
+	int ret_val = 0;
+
+	/* register the soc card */
+	snd_soc_card_cht.dev = &pdev->dev;
+	ret_val = snd_soc_register_card(&snd_soc_card_cht);
+	if (ret_val) {
+		dev_err(&pdev->dev,
+			"snd_soc_register_card failed %d\n", ret_val);
+		return ret_val;
+	}
+	platform_set_drvdata(pdev, &snd_soc_card_cht);
+	return ret_val;
+}
+
+static int snd_cht_mc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *soc_card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(soc_card);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver snd_cht_mc_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "cht-bsw-rt5672",
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = snd_cht_mc_probe,
+	.remove = snd_cht_mc_remove,
+};
+
+module_platform_driver(snd_cht_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
+MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-rt5672");