ASoC: Intel: bytcr_rt5651: Add support for Bay Trail CR / SSP0 using boards

Despite its name being prefixed with bytcr, before this commit the
bytcr_rt5651 machine driver could not work with Bay Trail CR boards,
as those only have SSP0 and it only supported SSP0-AIF1 setups.

This commit adds support for this, autodetecting AIF1 vs AIF2 based on
BIOS tables.

While at it also add support for SSP2-AIF2 setups, as that requires only
minimal extra code on top of the code adding SSP0-AIF1 / SSP0-AIF2 support.

Note this code is all copy-pasted from bytcr_rt5640.c. I've looked into
merging the 2 machine drivers into 1 to avoid copy-pasting, but there are
enough subtile differences to make this hard *and* with all the quirks the
machine driver already is full with if (variant-foo) then ... else ...
constructs adding more of these is going to make the code unreadable.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Hans de Goede 2018-03-04 15:36:07 +01:00 committed by Mark Brown
parent f026e06317
commit 8a880a2014
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
1 changed files with 201 additions and 16 deletions

View File

@ -27,6 +27,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h> #include <asm/platform_sst_audio.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
@ -72,6 +73,9 @@ enum {
#define BYT_RT5651_DMIC_EN BIT(16) #define BYT_RT5651_DMIC_EN BIT(16)
#define BYT_RT5651_MCLK_EN BIT(17) #define BYT_RT5651_MCLK_EN BIT(17)
#define BYT_RT5651_MCLK_25MHZ BIT(18) #define BYT_RT5651_MCLK_25MHZ BIT(18)
#define BYT_RT5651_SSP2_AIF2 BIT(19) /* default is using AIF1 */
#define BYT_RT5651_SSP0_AIF1 BIT(20)
#define BYT_RT5651_SSP0_AIF2 BIT(21)
/* jack-detect-source + dmic-en + ovcd-th + -sf + terminating empty entry */ /* jack-detect-source + dmic-en + ovcd-th + -sf + terminating empty entry */
#define MAX_NO_PROPS 5 #define MAX_NO_PROPS 5
@ -81,8 +85,7 @@ struct byt_rt5651_private {
struct snd_soc_jack jack; struct snd_soc_jack jack;
}; };
static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC_MAP | static unsigned long byt_rt5651_quirk = BYT_RT5651_MCLK_EN;
BYT_RT5651_MCLK_EN;
static void log_quirks(struct device *dev) static void log_quirks(struct device *dev)
{ {
@ -110,9 +113,16 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk MCLK_EN enabled"); dev_info(dev, "quirk MCLK_EN enabled");
if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ) if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ)
dev_info(dev, "quirk MCLK_25MHZ enabled"); dev_info(dev, "quirk MCLK_25MHZ enabled");
if (byt_rt5651_quirk & BYT_RT5651_SSP2_AIF2)
dev_info(dev, "quirk SSP2_AIF2 enabled\n");
if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF1)
dev_info(dev, "quirk SSP0_AIF1 enabled\n");
if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2)
dev_info(dev, "quirk SSP0_AIF2 enabled\n");
} }
#define BYT_CODEC_DAI1 "rt5651-aif1" #define BYT_CODEC_DAI1 "rt5651-aif1"
#define BYT_CODEC_DAI2 "rt5651-aif2"
static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
int rate, int bclk_ratio) int rate, int bclk_ratio)
@ -156,6 +166,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
int ret; int ret;
codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1); codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1);
if (!codec_dai)
codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI2);
if (!codec_dai) { if (!codec_dai) {
dev_err(card->dev, dev_err(card->dev,
"Codec dai not found; Unable to set platform clock\n"); "Codec dai not found; Unable to set platform clock\n");
@ -213,13 +225,6 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
{"Speaker", NULL, "Platform Clock"}, {"Speaker", NULL, "Platform Clock"},
{"Line In", NULL, "Platform Clock"}, {"Line In", NULL, "Platform Clock"},
{"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"},
{"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */ {"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */
{"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"}, {"Headphone", NULL, "HPOR"},
@ -267,6 +272,42 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_hs_in3_map[] = {
{"IN3P", NULL, "Headset Mic"}, {"IN3P", NULL, "Headset Mic"},
}; };
static const struct snd_soc_dapm_route byt_rt5651_ssp0_aif1_map[] = {
{"ssp0 Tx", NULL, "modem_out"},
{"modem_in", NULL, "ssp0 Rx"},
{"AIF1 Playback", NULL, "ssp0 Tx"},
{"ssp0 Rx", NULL, "AIF1 Capture"},
};
static const struct snd_soc_dapm_route byt_rt5651_ssp0_aif2_map[] = {
{"ssp0 Tx", NULL, "modem_out"},
{"modem_in", NULL, "ssp0 Rx"},
{"AIF2 Playback", NULL, "ssp0 Tx"},
{"ssp0 Rx", NULL, "AIF2 Capture"},
};
static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif1_map[] = {
{"ssp2 Tx", NULL, "codec_out0"},
{"ssp2 Tx", NULL, "codec_out1"},
{"codec_in0", NULL, "ssp2 Rx"},
{"codec_in1", NULL, "ssp2 Rx"},
{"AIF1 Playback", NULL, "ssp2 Tx"},
{"ssp2 Rx", NULL, "AIF1 Capture"},
};
static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif2_map[] = {
{"ssp2 Tx", NULL, "codec_out0"},
{"ssp2 Tx", NULL, "codec_out1"},
{"codec_in0", NULL, "ssp2 Rx"},
{"codec_in1", NULL, "ssp2 Rx"},
{"AIF2 Playback", NULL, "ssp2 Tx"},
{"ssp2 Rx", NULL, "AIF2 Capture"},
};
static const struct snd_kcontrol_new byt_rt5651_controls[] = { static const struct snd_kcontrol_new byt_rt5651_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"),
@ -291,9 +332,16 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream,
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai;
snd_pcm_format_t format = params_format(params);
int rate = params_rate(params); int rate = params_rate(params);
int bclk_ratio;
return byt_rt5651_prepare_and_enable_pll1(codec_dai, rate, 50); if (format == SNDRV_PCM_FORMAT_S16_LE)
bclk_ratio = 32;
else
bclk_ratio = 50;
return byt_rt5651_prepare_and_enable_pll1(codec_dai, rate, bclk_ratio);
} }
static int byt_rt5651_quirk_cb(const struct dmi_system_id *id) static int byt_rt5651_quirk_cb(const struct dmi_system_id *id)
@ -420,6 +468,26 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
if (ret) if (ret)
return ret; return ret;
if (byt_rt5651_quirk & BYT_RT5651_SSP2_AIF2) {
ret = snd_soc_dapm_add_routes(&card->dapm,
byt_rt5651_ssp2_aif2_map,
ARRAY_SIZE(byt_rt5651_ssp2_aif2_map));
} else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF1) {
ret = snd_soc_dapm_add_routes(&card->dapm,
byt_rt5651_ssp0_aif1_map,
ARRAY_SIZE(byt_rt5651_ssp0_aif1_map));
} else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2) {
ret = snd_soc_dapm_add_routes(&card->dapm,
byt_rt5651_ssp0_aif2_map,
ARRAY_SIZE(byt_rt5651_ssp0_aif2_map));
} else {
ret = snd_soc_dapm_add_routes(&card->dapm,
byt_rt5651_ssp2_aif1_map,
ARRAY_SIZE(byt_rt5651_ssp2_aif1_map));
}
if (ret)
return ret;
ret = snd_soc_add_card_controls(card, byt_rt5651_controls, ret = snd_soc_add_card_controls(card, byt_rt5651_controls,
ARRAY_SIZE(byt_rt5651_controls)); ARRAY_SIZE(byt_rt5651_controls));
if (ret) { if (ret) {
@ -485,18 +553,26 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_RATE); SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params, struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS); SNDRV_PCM_HW_PARAM_CHANNELS);
int ret; int ret, bits;
/* The DSP will covert the FE rate to 48k, stereo, 24bits */ /* The DSP will covert the FE rate to 48k, stereo */
rate->min = rate->max = 48000; rate->min = rate->max = 48000;
channels->min = channels->max = 2; channels->min = channels->max = 2;
/* set SSP2 to 24-bit */ if ((byt_rt5651_quirk & BYT_RT5651_SSP0_AIF1) ||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2)) {
/* set SSP0 to 16-bit */
params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
bits = 16;
} else {
/* set SSP2 to 24-bit */
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
bits = 24;
}
/* /*
* Default mode for SSP configuration is TDM 4 slot, override config * Default mode for SSP configuration is TDM 4 slot, override config
* with explicit setting to I2S 2ch 24-bit. The word length is set with * with explicit setting to I2S 2ch. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed * dai_set_tdm_slot() since there is no other API exposed
*/ */
ret = snd_soc_dai_set_fmt(rtd->cpu_dai, ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
@ -510,7 +586,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret; return ret;
} }
ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, bits);
if (ret < 0) { if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret; return ret;
@ -605,12 +681,32 @@ static struct snd_soc_card byt_rt5651_card = {
}; };
static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5651_codec_aif_name[12]; /* = "rt5651-aif[1|2]" */
static char byt_rt5651_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
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;
}
struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
u64 aif_value; /* 1: AIF1, 2: AIF2 */
u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */
};
static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
{ {
struct byt_rt5651_private *priv; struct byt_rt5651_private *priv;
struct snd_soc_acpi_mach *mach; struct snd_soc_acpi_mach *mach;
const char *i2c_name = NULL; const char *i2c_name = NULL;
bool is_bytcr = false;
int ret_val = 0; int ret_val = 0;
int dai_index = 0; int dai_index = 0;
int i; int i;
@ -643,6 +739,73 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
"%s%s", "i2c-", i2c_name); "%s%s", "i2c-", i2c_name);
byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name; byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name;
/*
* swap SSP0 if bytcr is detected
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
struct sst_platform_info *p_info = mach->pdata;
const struct sst_res_info *res_info = p_info->res_info;
if (res_info->acpi_ipc_irq_index == 0)
is_bytcr = true;
}
if (is_bytcr) {
/*
* Baytrail CR platforms may have CHAN package in BIOS, try
* to find relevant routing quirk based as done on Windows
* platforms. We have to read the information directly from the
* BIOS, at this stage the card is not created and the links
* with the codec driver/pdata are non-existent
*/
struct acpi_chan_package chan_package;
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
struct acpi_buffer state = {0, NULL};
struct snd_soc_acpi_package_context pkg_ctx;
bool pkg_found = false;
state.length = sizeof(chan_package);
state.pointer = &chan_package;
pkg_ctx.name = "CHAN";
pkg_ctx.length = 2;
pkg_ctx.format = &format;
pkg_ctx.state = &state;
pkg_ctx.data_valid = false;
pkg_found = snd_soc_acpi_find_package_from_hid(mach->id,
&pkg_ctx);
if (pkg_found) {
if (chan_package.aif_value == 1) {
dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n");
byt_rt5651_quirk |= BYT_RT5651_SSP0_AIF1;
} else if (chan_package.aif_value == 2) {
dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n");
byt_rt5651_quirk |= BYT_RT5651_SSP0_AIF2;
} else {
dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n");
pkg_found = false;
}
}
if (!pkg_found) {
/* no BIOS indications, assume SSP0-AIF2 connection */
byt_rt5651_quirk |= BYT_RT5651_SSP0_AIF2;
}
/* change defaults for Baytrail-CR capture */
byt_rt5651_quirk |= BYT_RT5651_JD1_1 |
BYT_RT5651_OVCD_TH_2000UA |
BYT_RT5651_OVCD_SF_0P75 |
BYT_RT5651_IN2_HS_IN3_MAP;
} else {
byt_rt5651_quirk |= BYT_RT5651_DMIC_MAP;
}
/* check quirks before creating card */ /* check quirks before creating card */
dmi_check_system(byt_rt5651_quirk_table); dmi_check_system(byt_rt5651_quirk_table);
@ -653,6 +816,28 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
log_quirks(&pdev->dev); log_quirks(&pdev->dev);
if ((byt_rt5651_quirk & BYT_RT5651_SSP2_AIF2) ||
(byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2)) {
/* fixup codec aif name */
snprintf(byt_rt5651_codec_aif_name,
sizeof(byt_rt5651_codec_aif_name),
"%s", "rt5651-aif2");
byt_rt5651_dais[dai_index].codec_dai_name =
byt_rt5651_codec_aif_name;
}
if ((byt_rt5651_quirk & BYT_RT5651_SSP0_AIF1) ||
(byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2)) {
/* fixup cpu dai name name */
snprintf(byt_rt5651_cpu_dai_name,
sizeof(byt_rt5651_cpu_dai_name),
"%s", "ssp0-port");
byt_rt5651_dais[dai_index].cpu_dai_name =
byt_rt5651_cpu_dai_name;
}
if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) { if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) {
priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
if (IS_ERR(priv->mclk)) { if (IS_ERR(priv->mclk)) {