diff options
| author | Rodrigo Vivi <[email protected]> | 2018-07-23 09:13:12 -0700 | 
|---|---|---|
| committer | Rodrigo Vivi <[email protected]> | 2018-07-23 09:13:12 -0700 | 
| commit | c74a7469f97c0f40b46e82ee979f9fb1bb6e847c (patch) | |
| tree | f2690a1a916b73ef94657fbf0e0141ae57701825 /sound/soc/intel/boards/bytcr_rt5640.c | |
| parent | 6f15a7de86c8cf2dc09fc9e6d07047efa40ef809 (diff) | |
| parent | 500775074f88d9cf5416bed2ca19592812d62c41 (diff) | |
Merge drm/drm-next into drm-intel-next-queued
We need a backmerge to get DP_DPCD_REV_14 before we push other
i915 changes to dinq that could break compilation.
Signed-off-by: Rodrigo Vivi <[email protected]>
Diffstat (limited to 'sound/soc/intel/boards/bytcr_rt5640.c')
| -rw-r--r-- | sound/soc/intel/boards/bytcr_rt5640.c | 568 | 
1 files changed, 441 insertions, 127 deletions
| diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a8d8bff788e7..33065ba294a9 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -17,6 +17,7 @@   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   */ +#include <linux/i2c.h>  #include <linux/init.h>  #include <linux/module.h>  #include <linux/moduleparam.h> @@ -25,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> @@ -33,6 +35,7 @@  #include <sound/soc.h>  #include <sound/jack.h>  #include <sound/soc-acpi.h> +#include <dt-bindings/sound/rt5640.h>  #include "../../codecs/rt5640.h"  #include "../atom/sst-atom-controls.h"  #include "../common/sst-dsp.h" @@ -44,17 +47,53 @@ enum {  	BYT_RT5640_IN3_MAP,  }; -#define BYT_RT5640_MAP(quirk)	((quirk) &  GENMASK(7, 0)) -#define BYT_RT5640_DMIC_EN	BIT(16) -#define BYT_RT5640_MONO_SPEAKER BIT(17) -#define BYT_RT5640_DIFF_MIC     BIT(18) /* defaut 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) +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) /* 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) + +#define BYTCR_INPUT_DEFAULTS				\ +	(BYT_RT5640_IN3_MAP |				\ +	 BYT_RT5640_JD_SRC_JD1_IN4P |			\ +	 BYT_RT5640_OVCD_TH_2000UA |			\ +	 BYT_RT5640_OVCD_SF_0P75 |			\ +	 BYT_RT5640_DIFF_MIC) + +/* 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; @@ -67,7 +106,6 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override");  static void log_quirks(struct device *dev)  {  	int map; -	bool has_dmic = false;  	bool has_mclk = false;  	bool has_ssp0 = false;  	bool has_ssp0_aif1 = false; @@ -78,11 +116,9 @@ static void log_quirks(struct device *dev)  	switch (map) {  	case BYT_RT5640_DMIC1_MAP:  		dev_info(dev, "quirk DMIC1_MAP enabled\n"); -		has_dmic = true;  		break;  	case BYT_RT5640_DMIC2_MAP:  		dev_info(dev, "quirk DMIC2_MAP enabled\n"); -		has_dmic = true;  		break;  	case BYT_RT5640_IN1_MAP:  		dev_info(dev, "quirk IN1_MAP enabled\n"); @@ -94,20 +130,20 @@ 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_DMIC_EN) { -		if (has_dmic) -			dev_info(dev, "quirk DMIC enabled\n"); -		else -			dev_err(dev, "quirk DMIC enabled but no DMIC input set, will be ignored\n"); +	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) { -		if (!has_dmic) -			dev_info(dev, "quirk DIFF_MIC enabled\n"); -		else -			dev_info(dev, "quirk DIFF_MIC enabled but DMIC input selected, will be ignored\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) {  		dev_info(dev, "quirk SSP0_AIF1 enabled\n");  		has_ssp0 = true; @@ -141,6 +177,52 @@ static void log_quirks(struct device *dev)  	}  } +static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, +					      int rate) +{ +	int ret; + +	/* Configure the PLL before selecting it */ +	if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { +		/* use bitclock as PLL input */ +		if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || +		    (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { +			/* 2x16 bit slots on SSP0 */ +			ret = snd_soc_dai_set_pll(codec_dai, 0, +						  RT5640_PLL1_S_BCLK1, +						  rate * 32, rate * 512); +		} else { +			/* 2x15 bit slots on SSP2 */ +			ret = snd_soc_dai_set_pll(codec_dai, 0, +						  RT5640_PLL1_S_BCLK1, +						  rate * 50, rate * 512); +		} +	} else { +		if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { +			ret = snd_soc_dai_set_pll(codec_dai, 0, +						  RT5640_PLL1_S_MCLK, +						  25000000, rate * 512); +		} else { +			ret = snd_soc_dai_set_pll(codec_dai, 0, +						  RT5640_PLL1_S_MCLK, +						  19200000, rate * 512); +		} +	} + +	if (ret < 0) { +		dev_err(codec_dai->component->dev, "can't set pll: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, +				     rate * 512, SND_SOC_CLOCK_IN); +	if (ret < 0) { +		dev_err(codec_dai->component->dev, "can't set clock %d\n", ret); +		return ret; +	} + +	return 0; +}  #define BYT_CODEC_DAI1	"rt5640-aif1"  #define BYT_CODEC_DAI2	"rt5640-aif2" @@ -173,9 +255,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,  				return ret;  			}  		} -		ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, -					     48000 * 512, -					     SND_SOC_CLOCK_IN); +		ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000);  	} else {  		/*  		 * Set codec clock source to internal clock before @@ -295,79 +375,72 @@ 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)  {  	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_dai *codec_dai = rtd->codec_dai; -	int ret; +	struct snd_soc_dai *dai = rtd->codec_dai; -	ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, -				     params_rate(params) * 512, -				     SND_SOC_CLOCK_IN); - -	if (ret < 0) { -		dev_err(rtd->dev, "can't set codec clock %d\n", ret); -		return ret; -	} - -	if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { -		/* use bitclock as PLL input */ -		if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || -			(byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { - -			/* 2x16 bit slots on SSP0 */ -			ret = snd_soc_dai_set_pll(codec_dai, 0, -						RT5640_PLL1_S_BCLK1, -						params_rate(params) * 32, -						params_rate(params) * 512); -		} else { -			/* 2x15 bit slots on SSP2 */ -			ret = snd_soc_dai_set_pll(codec_dai, 0, -						RT5640_PLL1_S_BCLK1, -						params_rate(params) * 50, -						params_rate(params) * 512); -		} -	} else { -		if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { -			ret = snd_soc_dai_set_pll(codec_dai, 0, -						RT5640_PLL1_S_MCLK, -						25000000, -						params_rate(params) * 512); -		} else { -			ret = snd_soc_dai_set_pll(codec_dai, 0, -						RT5640_PLL1_S_MCLK, -						19200000, -						params_rate(params) * 512); -		} -	} - -	if (ret < 0) { -		dev_err(rtd->dev, "can't set codec pll: %d\n", ret); -		return ret; -	} - -	return 0; -} - -static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) -{ -	byt_rt5640_quirk = (unsigned long)id->driver_data; -	return 1; +	return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params));  } +/* Please keep this list alphabetically sorted */  static const struct dmi_system_id byt_rt5640_quirk_table[] = { +	{	/* Acer Iconia Tab 8 W1-810 */ +		.matches = { +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Iconia W1-810"), +		}, +		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP | +					BYT_RT5640_JD_SRC_JD1_IN4P | +					BYT_RT5640_OVCD_TH_2000UA | +					BYT_RT5640_OVCD_SF_0P75 | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	}, +	{ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), +		}, +		.driver_data = (void *)(BYT_RT5640_IN1_MAP | +						 BYT_RT5640_MCLK_EN | +						 BYT_RT5640_SSP0_AIF1), + +	}, +	{ +		.matches = { +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 80 Cesium"), +		}, +		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS | +					BYT_RT5640_MONO_SPEAKER | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	},  	{ -		.callback = byt_rt5640_quirk_cb,  		.matches = {  			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),  			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),  	},  	{ -		.callback = byt_rt5640_quirk_cb,  		.matches = {  			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),  			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), @@ -378,18 +451,38 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {  					BYT_RT5640_SSP0_AIF2 |  					BYT_RT5640_MCLK_EN),  	}, +	{	/* Chuwi Vi8 (CWI506) */ +		.matches = { +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"), +			/* The above are too generic, also match BIOS info */ +			DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), +		}, +		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS | +					BYT_RT5640_MONO_SPEAKER | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	},  	{ -		.callback = byt_rt5640_quirk_cb,  		.matches = { -			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."), +			DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), +			DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), +		}, +		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP), +	}, +	{ +		.matches = { +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),  			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),  		}, -		.driver_data = (void *)(BYT_RT5640_DMIC2_MAP | -					BYT_RT5640_DMIC_EN | +		.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),  	},  	{ -		.callback = byt_rt5640_quirk_cb,  		.matches = {  			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),  			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), @@ -397,17 +490,112 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {  		.driver_data = (void *)(BYT_RT5640_IN1_MAP |  					BYT_RT5640_MCLK_EN),  	}, -	{ -		.callback = byt_rt5640_quirk_cb, +	{	/* HP Pavilion x2 10-n000nd */  		.matches = { -			DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), -			DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),  		},  		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP | -					BYT_RT5640_DMIC_EN), +					BYT_RT5640_JD_SRC_JD2_IN4N | +					BYT_RT5640_OVCD_TH_1500UA | +					BYT_RT5640_OVCD_SF_0P75 | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	}, +	{	/* HP Stream 7 */ +		.matches = { +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Stream 7 Tablet"), +		}, +		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS | +					BYT_RT5640_MONO_SPEAKER | +					BYT_RT5640_JD_NOT_INV | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	}, +	{	/* I.T.Works TW891 */ +		.matches = { +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891"), +			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."), +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"), +		}, +		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS | +					BYT_RT5640_MONO_SPEAKER | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	}, +	{	/* Lamina I8270 / T701BR.SE */ +		.matches = { +			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Lamina"), +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "T701BR.SE"), +		}, +		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS | +					BYT_RT5640_MONO_SPEAKER | +					BYT_RT5640_JD_NOT_INV | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	}, +	{	/* MSI S100 tablet */ +		.matches = { +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "S100"), +		}, +		.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_MONO_SPEAKER | +					BYT_RT5640_DIFF_MIC | +					BYT_RT5640_MCLK_EN), +	}, +	{	/* Pipo W4 */ +		.matches = { +			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), +			/* The above are too generic, also match BIOS info */ +			DMI_MATCH(DMI_BIOS_VERSION, "V8L_WIN32_CHIPHD"), +		}, +		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS | +					BYT_RT5640_MONO_SPEAKER | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN), +	}, +	{	/* Point of View Mobii TAB-P800W (V2.0) */ +		.matches = { +			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), +			/* The above are too generic, also match BIOS info */ +			DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1014"), +			DMI_EXACT_MATCH(DMI_BIOS_DATE, "10/24/2014"), +		}, +		.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_MONO_SPEAKER | +					BYT_RT5640_DIFF_MIC | +					BYT_RT5640_SSP0_AIF2 | +					BYT_RT5640_MCLK_EN), +	}, +	{	/* Point of View Mobii TAB-P800W (V2.1) */ +		.matches = { +			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), +			/* The above are too generic, also match BIOS info */ +			DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), +			DMI_EXACT_MATCH(DMI_BIOS_DATE, "08/22/2014"), +		}, +		.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_MONO_SPEAKER | +					BYT_RT5640_DIFF_MIC | +					BYT_RT5640_SSP0_AIF2 | +					BYT_RT5640_MCLK_EN),  	},  	{ -		.callback = byt_rt5640_quirk_cb,  		.matches = {  			DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),  			DMI_MATCH(DMI_BOARD_NAME, "tPAD"), @@ -416,23 +604,23 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {  					BYT_RT5640_MCLK_EN |  					BYT_RT5640_SSP0_AIF1),  	}, -	{ -		.callback = byt_rt5640_quirk_cb, +	{	/* Toshiba Satellite Click Mini L9W-B */  		.matches = { -			DMI_MATCH(DMI_SYS_VENDOR, "Acer"), -			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), +			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), +			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"),  		}, -		.driver_data = (void *)(BYT_RT5640_IN1_MAP | -						 BYT_RT5640_MCLK_EN | -						 BYT_RT5640_SSP0_AIF1), - +		.driver_data = (void *)(BYT_RT5640_DMIC1_MAP | +					BYT_RT5640_JD_SRC_JD2_IN4N | +					BYT_RT5640_OVCD_TH_1500UA | +					BYT_RT5640_OVCD_SF_0P75 | +					BYT_RT5640_SSP0_AIF1 | +					BYT_RT5640_MCLK_EN),  	}, -	{ -		.callback = byt_rt5640_quirk_cb, +	{	/* Catch-all for generic Insyde tablets, must be last */  		.matches = {  			DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),  		}, -		.driver_data = (void *)(BYT_RT5640_IN3_MAP | +		.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |  					BYT_RT5640_MCLK_EN |  					BYT_RT5640_SSP0_AIF1), @@ -440,6 +628,64 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {  	{}  }; +/* + * Note this MUST be called before snd_soc_register_card(), so that the props + * are in place before the codec component driver's probe function parses them. + */ +static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) +{ +	struct property_entry props[MAX_NO_PROPS] = {}; +	struct device *i2c_dev; +	int ret, cnt = 0; + +	i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name); +	if (!i2c_dev) +		return -EPROBE_DEFER; + +	switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { +	case BYT_RT5640_DMIC1_MAP: +		props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic1-data-pin", +						  RT5640_DMIC1_DATA_PIN_IN1P); +		break; +	case BYT_RT5640_DMIC2_MAP: +		props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic2-data-pin", +						  RT5640_DMIC2_DATA_PIN_IN1N); +		break; +	case BYT_RT5640_IN1_MAP: +		if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) +			props[cnt++] = +				PROPERTY_ENTRY_BOOL("realtek,in1-differential"); +		break; +	case BYT_RT5640_IN3_MAP: +		if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) +			props[cnt++] = +				PROPERTY_ENTRY_BOOL("realtek,in3-differential"); +		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); + +	return ret; +} +  static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)  {  	struct snd_soc_card *card = runtime->card; @@ -451,6 +697,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	| @@ -521,17 +772,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)  	if (ret)  		return ret; -	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) { -		snd_soc_component_update_bits(component,  RT5640_IN1_IN2, RT5640_IN_DF1, -				    RT5640_IN_DF1); -	} - -	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { -		ret = rt5640_dmic_enable(component, 0, 0); -		if (ret) -			return ret; -	} -  	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");  	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); @@ -555,11 +795,27 @@ 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; +		}  	} -	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 = { @@ -701,6 +957,48 @@ 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 char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ + +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, @@ -711,12 +1009,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[] = { @@ -736,6 +1032,8 @@ struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */  static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)  { +	const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; +	const struct dmi_system_id *dmi_id;  	struct byt_rt5640_private *priv;  	struct snd_soc_acpi_mach *mach;  	const char *i2c_name = NULL; @@ -744,7 +1042,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)  	int i;  	is_bytcr = false; -	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);  	if (!priv)  		return -ENOMEM; @@ -829,20 +1127,29 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)  		}  		/* change defaults for Baytrail-CR capture */ -		byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; -		byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; +		byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS;  	} else { -		byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP | -				BYT_RT5640_DMIC_EN); +		byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP | +				    BYT_RT5640_JD_SRC_JD2_IN4N | +				    BYT_RT5640_OVCD_TH_2000UA | +				    BYT_RT5640_OVCD_SF_0P75;  	}  	/* check quirks before creating card */ -	dmi_check_system(byt_rt5640_quirk_table); +	dmi_id = dmi_first_match(byt_rt5640_quirk_table); +	if (dmi_id) +		byt_rt5640_quirk = (unsigned long)dmi_id->driver_data;  	if (quirk_override) {  		dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n",  			 (unsigned int)byt_rt5640_quirk, quirk_override);  		byt_rt5640_quirk = quirk_override;  	} + +	/* Must be called before register_card, also see declaration comment. */ +	ret_val = byt_rt5640_add_codec_device_props(byt_rt5640_codec_name); +	if (ret_val) +		return ret_val; +  	log_quirks(&pdev->dev);  	if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) || @@ -889,6 +1196,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)  		}  	} +	snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), +		 "bytcr-rt5640-%s-spk-%s-mic", +		 (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? +			"mono" : "stereo", +		 map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); +	byt_rt5640_card.long_name = byt_rt5640_long_name; +  	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);  	if (ret_val) { |