Merge series "ASoC: Intel: bytcr_rt5640: Fix HP ElitePad 1000 G2 audio routing" from Hans de Goede <hdegoede@redhat.com>:
Changes in v2: - Only set lineout_string if BYT_RT5640_LINEOUT is set, since BYT_RT5640_LINEOUT_AS_HP2 only works if the lineout is enabled in the first place Original cover-letter: The HP Elitepad 1000 G2 has 2 headset jacks: 1. on the dock which uses the output of the codecs built-in HP-amp + the standard IN2 input which is always used with the headset-jack. 2. on the tablet itself, this uses the line-out of the codec, combined with an external HP-amp + IN1 for the headset-mic. This series adds support for this, resolving: https://bugzilla.kernel.org/show_bug.cgi?id=213415 Note this series does not add jack-detect support. I plan to add that with a follow-up series when I can make some time to implement that. Regards, Hans Hans de Goede (6): ASoC: Intel: bytcr_rt5640: Move "Platform Clock" routes to the maps for the matching in-/output ASoC: Intel: bytcr_rt5640: Add line-out support ASoC: Intel: bytcr_rt5640: Add a byt_rt5640_get_codec_dai() helper ASoC: Intel: bytcr_rt5640: Add support for a second headphones output ASoC: Intel: bytcr_rt5640: Add support for a second headset mic input ASoC: Intel: bytcr_rt5640: Fix HP ElitePad 1000 G2 quirk sound/soc/intel/boards/bytcr_rt5640.c | 118 ++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 16 deletions(-) -- 2.31.1
This commit is contained in:
commit
2f535e2cd5
|
@ -73,6 +73,9 @@ enum {
|
|||
#define BYT_RT5640_MCLK_EN BIT(22)
|
||||
#define BYT_RT5640_MCLK_25MHZ BIT(23)
|
||||
#define BYT_RT5640_NO_SPEAKERS BIT(24)
|
||||
#define BYT_RT5640_LINEOUT BIT(25)
|
||||
#define BYT_RT5640_LINEOUT_AS_HP2 BIT(26)
|
||||
#define BYT_RT5640_HSMIC2_ON_IN1 BIT(27)
|
||||
|
||||
#define BYTCR_INPUT_DEFAULTS \
|
||||
(BYT_RT5640_IN3_MAP | \
|
||||
|
@ -125,6 +128,8 @@ static void log_quirks(struct device *dev)
|
|||
dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map);
|
||||
break;
|
||||
}
|
||||
if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1)
|
||||
dev_info(dev, "quirk HSMIC2_ON_IN1 enabled\n");
|
||||
if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
|
||||
dev_info(dev, "quirk realtek,jack-detect-source %ld\n",
|
||||
BYT_RT5640_JDSRC(byt_rt5640_quirk));
|
||||
|
@ -139,6 +144,10 @@ static void log_quirks(struct device *dev)
|
|||
dev_info(dev, "quirk MONO_SPEAKER enabled\n");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)
|
||||
dev_info(dev, "quirk NO_SPEAKERS enabled\n");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT)
|
||||
dev_info(dev, "quirk LINEOUT enabled\n");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2)
|
||||
dev_info(dev, "quirk LINEOUT_AS_HP2 enabled\n");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
|
||||
dev_info(dev, "quirk DIFF_MIC enabled\n");
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
|
||||
|
@ -224,6 +233,20 @@ static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
|
|||
#define BYT_CODEC_DAI1 "rt5640-aif1"
|
||||
#define BYT_CODEC_DAI2 "rt5640-aif2"
|
||||
|
||||
static struct snd_soc_dai *byt_rt5640_get_codec_dai(struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
|
||||
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)
|
||||
dev_err(card->dev, "Error codec dai not found\n");
|
||||
|
||||
return codec_dai;
|
||||
}
|
||||
|
||||
static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
|
@ -233,15 +256,9 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
|||
struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
|
||||
int ret;
|
||||
|
||||
codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1);
|
||||
codec_dai = byt_rt5640_get_codec_dai(dapm);
|
||||
if (!codec_dai)
|
||||
codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI2);
|
||||
|
||||
if (!codec_dai) {
|
||||
dev_err(card->dev,
|
||||
"Codec dai not found; Unable to set platform clock\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) {
|
||||
|
@ -276,23 +293,47 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int byt_rt5640_event_lineout(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
unsigned int gpio_ctrl3_val = RT5640_GP1_PF_OUT;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
|
||||
if (!(byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* On devices which use line-out as a second headphones output,
|
||||
* the codec's GPIO1 pin is used to enable an external HP-amp.
|
||||
*/
|
||||
|
||||
codec_dai = byt_rt5640_get_codec_dai(w->dapm);
|
||||
if (!codec_dai)
|
||||
return -EIO;
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
||||
gpio_ctrl3_val |= RT5640_GP1_OUT_HI;
|
||||
|
||||
snd_soc_component_update_bits(codec_dai->component, RT5640_GPIO_CTRL3,
|
||||
RT5640_GP1_PF_MASK | RT5640_GP1_OUT_MASK, gpio_ctrl3_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_MIC("Internal Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_LINE("Line Out", byt_rt5640_event_lineout),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Internal Mic", NULL, "Platform Clock"},
|
||||
{"Speaker", NULL, "Platform Clock"},
|
||||
|
||||
{"Headset Mic", NULL, "MICBIAS1"},
|
||||
{"IN2P", NULL, "Headset Mic"},
|
||||
{"Headphone", NULL, "HPOL"},
|
||||
|
@ -300,19 +341,23 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
|
||||
{"Internal Mic", NULL, "Platform Clock"},
|
||||
{"DMIC1", NULL, "Internal Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
|
||||
{"Internal Mic", NULL, "Platform Clock"},
|
||||
{"DMIC2", NULL, "Internal Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
|
||||
{"Internal Mic", NULL, "Platform Clock"},
|
||||
{"Internal Mic", NULL, "MICBIAS1"},
|
||||
{"IN1P", NULL, "Internal Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_intmic_in3_map[] = {
|
||||
{"Internal Mic", NULL, "Platform Clock"},
|
||||
{"Internal Mic", NULL, "MICBIAS1"},
|
||||
{"IN3P", NULL, "Internal Mic"},
|
||||
};
|
||||
|
@ -354,6 +399,7 @@ static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif2_map[] = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = {
|
||||
{"Speaker", NULL, "Platform Clock"},
|
||||
{"Speaker", NULL, "SPOLP"},
|
||||
{"Speaker", NULL, "SPOLN"},
|
||||
{"Speaker", NULL, "SPORP"},
|
||||
|
@ -361,15 +407,23 @@ static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_mono_spk_map[] = {
|
||||
{"Speaker", NULL, "Platform Clock"},
|
||||
{"Speaker", NULL, "SPOLP"},
|
||||
{"Speaker", NULL, "SPOLN"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_lineout_map[] = {
|
||||
{"Line Out", NULL, "Platform Clock"},
|
||||
{"Line Out", NULL, "LOUTR"},
|
||||
{"Line Out", NULL, "LOUTL"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new byt_rt5640_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Internal Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
SOC_DAPM_PIN_SWITCH("Line Out"),
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin rt5640_pins[] = {
|
||||
|
@ -590,8 +644,11 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
|||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
|
||||
},
|
||||
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
|
||||
BYT_RT5640_MCLK_EN),
|
||||
.driver_data = (void *)(BYT_RT5640_DMIC2_MAP |
|
||||
BYT_RT5640_MCLK_EN |
|
||||
BYT_RT5640_LINEOUT |
|
||||
BYT_RT5640_LINEOUT_AS_HP2 |
|
||||
BYT_RT5640_HSMIC2_ON_IN1),
|
||||
},
|
||||
{ /* HP Pavilion x2 10-k0XX, 10-n0XX */
|
||||
.matches = {
|
||||
|
@ -1021,6 +1078,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
byt_rt5640_intmic_in1_map,
|
||||
ARRAY_SIZE(byt_rt5640_intmic_in1_map));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
byt_rt5640_ssp2_aif2_map,
|
||||
|
@ -1053,6 +1118,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
byt_rt5640_lineout_map,
|
||||
ARRAY_SIZE(byt_rt5640_lineout_map));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) {
|
||||
/*
|
||||
* The firmware might enable the clock at
|
||||
|
@ -1218,7 +1291,7 @@ static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
|
|||
#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
|
||||
static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */
|
||||
#endif
|
||||
static char byt_rt5640_components[32]; /* = "cfg-spk:* cfg-mic:*" */
|
||||
static char byt_rt5640_components[64]; /* = "cfg-spk:* cfg-mic:* ..." */
|
||||
|
||||
static int byt_rt5640_suspend(struct snd_soc_card *card)
|
||||
{
|
||||
|
@ -1288,6 +1361,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
|
|||
static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3", "none" };
|
||||
__maybe_unused const char *spk_type;
|
||||
const struct dmi_system_id *dmi_id;
|
||||
const char *headset2_string = "";
|
||||
const char *lineout_string = "";
|
||||
struct byt_rt5640_private *priv;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
const char *platform_name;
|
||||
|
@ -1450,9 +1525,20 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
|
|||
spk_type = "stereo";
|
||||
}
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) {
|
||||
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2)
|
||||
lineout_string = " cfg-hp2:lineout";
|
||||
else
|
||||
lineout_string = " cfg-lineout:1";
|
||||
}
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1)
|
||||
headset2_string = " cfg-hs2:in1";
|
||||
|
||||
snprintf(byt_rt5640_components, sizeof(byt_rt5640_components),
|
||||
"cfg-spk:%d cfg-mic:%s aif:%d", cfg_spk,
|
||||
map_name[BYT_RT5640_MAP(byt_rt5640_quirk)], aif);
|
||||
"cfg-spk:%d cfg-mic:%s aif:%d%s%s", cfg_spk,
|
||||
map_name[BYT_RT5640_MAP(byt_rt5640_quirk)], aif,
|
||||
lineout_string, headset2_string);
|
||||
byt_rt5640_card.components = byt_rt5640_components;
|
||||
#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
|
||||
snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name),
|
||||
|
|
Loading…
Reference in New Issue