Unverified Commit 77323108 authored by Hans de Goede's avatar Hans de Goede Committed by Mark Brown
Browse files

ASoC: Intel: bytcr_rt5640: Enable jack detection



Add code to support setting jack-detect parameters through quirks and
extend the existing DMI quirk table entries for the Asus T100TA and the
Dell Venue 8 Pro 5830 to enable jack detection.

Tested-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Acked-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 6748fb7e
Loading
Loading
Loading
Loading
+148 −16
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
@@ -46,19 +47,46 @@ enum {
	BYT_RT5640_IN3_MAP,
};

#define BYT_RT5640_MAP(quirk)	((quirk) &  GENMASK(7, 0))
enum {
	BYT_RT5640_JD_SRC_GPIO1		= (RT5640_JD_SRC_GPIO1 << 4),
	BYT_RT5640_JD_SRC_JD1_IN4P	= (RT5640_JD_SRC_JD1_IN4P << 4),
	BYT_RT5640_JD_SRC_JD2_IN4N	= (RT5640_JD_SRC_JD2_IN4N << 4),
	BYT_RT5640_JD_SRC_GPIO2		= (RT5640_JD_SRC_GPIO2 << 4),
	BYT_RT5640_JD_SRC_GPIO3		= (RT5640_JD_SRC_GPIO3 << 4),
	BYT_RT5640_JD_SRC_GPIO4		= (RT5640_JD_SRC_GPIO4 << 4),
};

enum {
	BYT_RT5640_OVCD_TH_600UA	= (6 << 8),
	BYT_RT5640_OVCD_TH_1500UA	= (15 << 8),
	BYT_RT5640_OVCD_TH_2000UA	= (20 << 8),
};

enum {
	BYT_RT5640_OVCD_SF_0P5		= (RT5640_OVCD_SF_0P5 << 13),
	BYT_RT5640_OVCD_SF_0P75		= (RT5640_OVCD_SF_0P75 << 13),
	BYT_RT5640_OVCD_SF_1P0		= (RT5640_OVCD_SF_1P0 << 13),
	BYT_RT5640_OVCD_SF_1P5		= (RT5640_OVCD_SF_1P5 << 13),
};

#define BYT_RT5640_MAP(quirk)		((quirk) &  GENMASK(3, 0))
#define BYT_RT5640_JDSRC(quirk)		(((quirk) & GENMASK(7, 4)) >> 4)
#define BYT_RT5640_OVCD_TH(quirk)	(((quirk) & GENMASK(12, 8)) >> 8)
#define BYT_RT5640_OVCD_SF(quirk)	(((quirk) & GENMASK(14, 13)) >> 13)
#define BYT_RT5640_JD_NOT_INV		BIT(16)
#define BYT_RT5640_MONO_SPEAKER		BIT(17)
#define BYT_RT5640_DIFF_MIC     BIT(18) /* defaut is single-ended */
#define BYT_RT5640_DIFF_MIC		BIT(18) /* default is single-ended */
#define BYT_RT5640_SSP2_AIF2		BIT(19) /* default is using AIF1  */
#define BYT_RT5640_SSP0_AIF1		BIT(20)
#define BYT_RT5640_SSP0_AIF2		BIT(21)
#define BYT_RT5640_MCLK_EN		BIT(22)
#define BYT_RT5640_MCLK_25MHZ		BIT(23)

/* in-diff or dmic-pin + terminating empty entry */
#define MAX_NO_PROPS 2
/* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */
#define MAX_NO_PROPS 6

struct byt_rt5640_private {
	struct snd_soc_jack jack;
	struct clk *mclk;
};
static bool is_bytcr;
@@ -95,6 +123,16 @@ 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_JDSRC(byt_rt5640_quirk)) {
		dev_info(dev, "quirk realtek,jack-detect-source %ld\n",
			 BYT_RT5640_JDSRC(byt_rt5640_quirk));
		dev_info(dev, "quirk realtek,over-current-threshold-microamp %ld\n",
			 BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100);
		dev_info(dev, "quirk realtek,over-current-scale-factor %ld\n",
			 BYT_RT5640_OVCD_SF(byt_rt5640_quirk));
	}
	if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV)
		dev_info(dev, "quirk JD_NOT_INV enabled\n");
	if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
		dev_info(dev, "quirk MONO_SPEAKER enabled\n");
	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
@@ -330,6 +368,17 @@ static const struct snd_kcontrol_new byt_rt5640_controls[] = {
	SOC_DAPM_PIN_SWITCH("Speaker"),
};

static struct snd_soc_jack_pin rt5640_pins[] = {
	{
		.pin	= "Headphone",
		.mask	= SND_JACK_HEADPHONE,
	},
	{
		.pin	= "Headset Mic",
		.mask	= SND_JACK_MICROPHONE,
	},
};

static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
					struct snd_pcm_hw_params *params)
{
@@ -353,6 +402,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
		},
		.driver_data = (void *)(BYT_RT5640_IN1_MAP |
					BYT_RT5640_JD_SRC_JD2_IN4N |
					BYT_RT5640_OVCD_TH_2000UA |
					BYT_RT5640_OVCD_SF_0P75 |
					BYT_RT5640_MCLK_EN),
	},
	{
@@ -374,6 +426,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
		},
		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
					BYT_RT5640_JD_SRC_JD2_IN4N |
					BYT_RT5640_OVCD_TH_2000UA |
					BYT_RT5640_OVCD_SF_0P75 |
					BYT_RT5640_MONO_SPEAKER |
					BYT_RT5640_MCLK_EN),
	},
@@ -463,6 +518,23 @@ static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name)
		break;
	}

	if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
		props[cnt++] = PROPERTY_ENTRY_U32(
				    "realtek,jack-detect-source",
				    BYT_RT5640_JDSRC(byt_rt5640_quirk));

		props[cnt++] = PROPERTY_ENTRY_U32(
				    "realtek,over-current-threshold-microamp",
				    BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100);

		props[cnt++] = PROPERTY_ENTRY_U32(
				    "realtek,over-current-scale-factor",
				    BYT_RT5640_OVCD_SF(byt_rt5640_quirk));
	}

	if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV)
		props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted");

	ret = device_add_properties(i2c_dev, props);
	put_device(i2c_dev);

@@ -480,6 +552,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)

	card->dapm.idle_bias_off = true;

	/* Start with RC clk for jack-detect (we disable MCLK below) */
	if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN)
		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
			RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_RCCLK);

	rt5640_sel_asrc_clk_src(component,
				RT5640_DA_STEREO_FILTER |
				RT5640_DA_MONO_L_FILTER	|
@@ -573,12 +650,28 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
		else
			ret = clk_set_rate(priv->mclk, 19200000);

		if (ret)
		if (ret) {
			dev_err(card->dev, "unable to set MCLK rate\n");
			return ret;
		}
	}

	if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
		ret = snd_soc_card_jack_new(card, "Headset",
					    SND_JACK_HEADSET | SND_JACK_BTN_0,
					    &priv->jack, rt5640_pins,
					    ARRAY_SIZE(rt5640_pins));
		if (ret) {
			dev_err(card->dev, "Jack creation failed %d\n", ret);
			return ret;
		}
		snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0,
				 KEY_PLAYPAUSE);
		snd_soc_component_set_jack(component, &priv->jack, NULL);
	}

	return 0;
}

static const struct snd_soc_pcm_stream byt_rt5640_dai_params = {
	.formats = SNDRV_PCM_FMTBIT_S24_LE,
@@ -719,6 +812,47 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
};

/* SoC card */
static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5640_codec_aif_name[12]; /*  = "rt5640-aif[1|2]" */
static char byt_rt5640_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */

static int byt_rt5640_suspend(struct snd_soc_card *card)
{
	struct snd_soc_component *component;

	if (!BYT_RT5640_JDSRC(byt_rt5640_quirk))
		return 0;

	list_for_each_entry(component, &card->component_dev_list, card_list) {
		if (!strcmp(component->name, byt_rt5640_codec_name)) {
			dev_dbg(component->dev, "disabling jack detect before suspend\n");
			snd_soc_component_set_jack(component, NULL, NULL);
			break;
		}
	}

	return 0;
}

static int byt_rt5640_resume(struct snd_soc_card *card)
{
	struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
	struct snd_soc_component *component;

	if (!BYT_RT5640_JDSRC(byt_rt5640_quirk))
		return 0;

	list_for_each_entry(component, &card->component_dev_list, card_list) {
		if (!strcmp(component->name, byt_rt5640_codec_name)) {
			dev_dbg(component->dev, "re-enabling jack detect after resume\n");
			snd_soc_component_set_jack(component, &priv->jack, NULL);
			break;
		}
	}

	return 0;
}

static struct snd_soc_card byt_rt5640_card = {
	.name = "bytcr-rt5640",
	.owner = THIS_MODULE,
@@ -729,12 +863,10 @@ static struct snd_soc_card byt_rt5640_card = {
	.dapm_routes = byt_rt5640_audio_map,
	.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
	.fully_routed = true,
	.suspend_pre = byt_rt5640_suspend,
	.resume_post = byt_rt5640_resume,
};

static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5640_codec_aif_name[12]; /*  = "rt5640-aif[1|2]" */
static char byt_rt5640_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */

static bool is_valleyview(void)
{
	static const struct x86_cpu_id cpu_ids[] = {