Commit c25695ae authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Mark Brown

ASoC: Intel: cht_bsw_rt5672: 19.2MHz clock for Baytrail platforms

Lenovo platforms use RT5670 with Baytrail, add the required
MCLK control and configuration to 19.2MHz

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96691Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 98faf436
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h>
#include <asm/cpu_device_id.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
...@@ -31,8 +33,11 @@ ...@@ -31,8 +33,11 @@
#define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_PLAT_CLK_3_HZ 19200000
#define CHT_CODEC_DAI "rt5670-aif1" #define CHT_CODEC_DAI "rt5670-aif1"
static struct snd_soc_jack cht_bsw_headset; struct cht_mc_private {
static char cht_bsw_codec_name[16]; struct snd_soc_jack headset;
char codec_name[16];
struct clk *mclk;
};
/* Headset jack detection DAPM pins */ /* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
...@@ -64,6 +69,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, ...@@ -64,6 +69,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card; struct snd_soc_card *card = dapm->card;
struct snd_soc_dai *codec_dai; struct snd_soc_dai *codec_dai;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret; int ret;
codec_dai = cht_get_codec_dai(card); codec_dai = cht_get_codec_dai(card);
...@@ -73,6 +79,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, ...@@ -73,6 +79,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
} }
if (SND_SOC_DAPM_EVENT_ON(event)) { if (SND_SOC_DAPM_EVENT_ON(event)) {
if (ctx->mclk) {
ret = clk_prepare_enable(ctx->mclk);
if (ret < 0) {
dev_err(card->dev,
"could not configure MCLK state");
return ret;
}
}
/* set codec PLL source to the 19.2MHz platform clock (MCLK) */ /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
CHT_PLAT_CLK_3_HZ, 48000 * 512); CHT_PLAT_CLK_3_HZ, 48000 * 512);
...@@ -96,6 +111,9 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, ...@@ -96,6 +111,9 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
*/ */
snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
48000 * 512, SND_SOC_CLOCK_IN); 48000 * 512, SND_SOC_CLOCK_IN);
if (ctx->mclk)
clk_disable_unprepare(ctx->mclk);
} }
return 0; return 0;
} }
...@@ -171,6 +189,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) ...@@ -171,6 +189,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
int ret; int ret;
struct snd_soc_dai *codec_dai = runtime->codec_dai; struct snd_soc_dai *codec_dai = runtime->codec_dai;
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ /* 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); ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
...@@ -195,12 +214,36 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) ...@@ -195,12 +214,36 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
ret = snd_soc_card_jack_new(runtime->card, "Headset", ret = snd_soc_card_jack_new(runtime->card, "Headset",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset, SND_JACK_BTN_1 | SND_JACK_BTN_2,
cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins)); &ctx->headset,
cht_bsw_headset_pins,
ARRAY_SIZE(cht_bsw_headset_pins));
if (ret) if (ret)
return ret; return ret;
rt5670_set_jack_detect(codec, &cht_bsw_headset); rt5670_set_jack_detect(codec, &ctx->headset);
if (ctx->mclk) {
/*
* The firmware might enable the clock at
* boot (this information may or may not
* be reflected in the enable clock register).
* To change the rate we must disable the clock
* first to cover these cases. Due to common
* clock framework restrictions that do not allow
* to disable a clock that has not been enabled,
* we need to enable the clock first.
*/
ret = clk_prepare_enable(ctx->mclk);
if (!ret)
clk_disable_unprepare(ctx->mclk);
ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
if (ret) {
dev_err(runtime->dev, "unable to set MCLK rate\n");
return ret;
}
}
return 0; return 0;
} }
...@@ -341,34 +384,62 @@ static struct snd_soc_card snd_soc_card_cht = { ...@@ -341,34 +384,62 @@ static struct snd_soc_card snd_soc_card_cht = {
.resume_post = cht_resume_post, .resume_post = cht_resume_post,
}; };
static bool is_valleyview(void)
{
static const struct x86_cpu_id cpu_ids[] = {
{ X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
{}
};
if (!x86_match_cpu(cpu_ids))
return false;
return true;
}
#define RT5672_I2C_DEFAULT "i2c-10EC5670:00" #define RT5672_I2C_DEFAULT "i2c-10EC5670:00"
static int snd_cht_mc_probe(struct platform_device *pdev) static int snd_cht_mc_probe(struct platform_device *pdev)
{ {
int ret_val = 0; int ret_val = 0;
struct cht_mc_private *drv;
struct sst_acpi_mach *mach = pdev->dev.platform_data; struct sst_acpi_mach *mach = pdev->dev.platform_data;
const char *i2c_name; const char *i2c_name;
int i; int i;
strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv)
return -ENOMEM;
strcpy(drv->codec_name, RT5672_I2C_DEFAULT);
/* fixup codec name based on HID */ /* fixup codec name based on HID */
if (mach) { if (mach) {
i2c_name = sst_acpi_find_name_from_hid(mach->id); i2c_name = sst_acpi_find_name_from_hid(mach->id);
if (i2c_name) { if (i2c_name) {
snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), snprintf(drv->codec_name, sizeof(drv->codec_name),
"i2c-%s", i2c_name); "i2c-%s", i2c_name);
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
if (!strcmp(cht_dailink[i].codec_name, if (!strcmp(cht_dailink[i].codec_name,
RT5672_I2C_DEFAULT)) { RT5672_I2C_DEFAULT)) {
cht_dailink[i].codec_name = cht_dailink[i].codec_name =
cht_bsw_codec_name; drv->codec_name;
break; break;
} }
} }
} }
} }
if (is_valleyview()) {
drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
if (IS_ERR(drv->mclk)) {
dev_err(&pdev->dev,
"Failed to get MCLK from pmc_plt_clk_3: %ld\n",
PTR_ERR(drv->mclk));
return PTR_ERR(drv->mclk);
}
}
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
/* register the soc card */ /* register the soc card */
snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_cht.dev = &pdev->dev;
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment